@tanstack/ai-devtools-core 0.2.1 → 0.2.3
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 +1 -0
- package/dist/esm/components/ConversationDetails.js +74 -1
- package/dist/esm/components/ConversationDetails.js.map +1 -1
- package/dist/esm/components/conversation/ActivityEventsTab.d.ts +8 -0
- package/dist/esm/components/conversation/ActivityEventsTab.js +72 -0
- package/dist/esm/components/conversation/ActivityEventsTab.js.map +1 -0
- package/dist/esm/components/conversation/ConversationHeader.js +109 -66
- package/dist/esm/components/conversation/ConversationHeader.js.map +1 -1
- package/dist/esm/components/conversation/ConversationTabs.d.ts +1 -1
- package/dist/esm/components/conversation/ConversationTabs.js +107 -3
- package/dist/esm/components/conversation/ConversationTabs.js.map +1 -1
- package/dist/esm/components/conversation/MessageCard.js +83 -28
- package/dist/esm/components/conversation/MessageCard.js.map +1 -1
- package/dist/esm/components/conversation/index.d.ts +1 -0
- package/dist/esm/store/ai-context.d.ts +19 -2
- package/dist/esm/store/ai-context.js +528 -262
- package/dist/esm/store/ai-context.js.map +1 -1
- package/dist/esm/styles/use-styles.d.ts +7 -0
- package/dist/esm/styles/use-styles.js +65 -1
- package/dist/esm/styles/use-styles.js.map +1 -1
- package/package.json +2 -2
- package/src/components/ConversationDetails.tsx +70 -1
- package/src/components/conversation/ActivityEventsTab.tsx +57 -0
- package/src/components/conversation/ConversationHeader.tsx +52 -36
- package/src/components/conversation/ConversationTabs.tsx +121 -2
- package/src/components/conversation/MessageCard.tsx +45 -10
- package/src/components/conversation/index.ts +1 -0
- package/src/store/ai-context.tsx +783 -418
- package/src/styles/use-styles.ts +65 -1
|
@@ -1,27 +1,79 @@
|
|
|
1
1
|
import { template, insert, createComponent, effect, className, memo, delegateEvents } from "solid-js/web";
|
|
2
|
-
import { Show } from "solid-js";
|
|
2
|
+
import { createSignal, createEffect, Show } from "solid-js";
|
|
3
3
|
import { useStyles } from "../../styles/use-styles.js";
|
|
4
|
-
var _tmpl$ = /* @__PURE__ */ template(`<button>💬 Messages (<!>)`), _tmpl$2 = /* @__PURE__ */ template(`<button>📦 Chunks (<!>)`), _tmpl$3 = /* @__PURE__ */ template(`<button>📝 Summaries (<!>)`), _tmpl$4 = /* @__PURE__ */ template(`<div>`);
|
|
4
|
+
var _tmpl$ = /* @__PURE__ */ template(`<button>💬 Messages (<!>)`), _tmpl$2 = /* @__PURE__ */ template(`<button>📦 Chunks (<!>)`), _tmpl$3 = /* @__PURE__ */ template(`<button>📝 Summaries (<!>)`), _tmpl$4 = /* @__PURE__ */ template(`<button>🖼️ Image (<!>)`), _tmpl$5 = /* @__PURE__ */ template(`<button>🔊 Speech (<!>)`), _tmpl$6 = /* @__PURE__ */ template(`<button>📝 Transcription (<!>)`), _tmpl$7 = /* @__PURE__ */ template(`<button>🎬 Video (<!>)`), _tmpl$8 = /* @__PURE__ */ template(`<div>`);
|
|
5
5
|
const ConversationTabs = (props) => {
|
|
6
6
|
const styles = useStyles();
|
|
7
7
|
const conv = () => props.conversation;
|
|
8
8
|
const totalRawChunks = () => conv().chunks.reduce((sum, c) => sum + (c.chunkCount || 1), 0);
|
|
9
9
|
const summariesCount = () => conv().summaries?.length ?? 0;
|
|
10
|
+
const imageCount = () => conv().imageEvents?.length ?? 0;
|
|
11
|
+
const speechCount = () => conv().speechEvents?.length ?? 0;
|
|
12
|
+
const transcriptionCount = () => conv().transcriptionEvents?.length ?? 0;
|
|
13
|
+
const videoCount = () => conv().videoEvents?.length ?? 0;
|
|
14
|
+
const [imagePulse, setImagePulse] = createSignal(false);
|
|
15
|
+
const [speechPulse, setSpeechPulse] = createSignal(false);
|
|
16
|
+
const [transcriptionPulse, setTranscriptionPulse] = createSignal(false);
|
|
17
|
+
const [videoPulse, setVideoPulse] = createSignal(false);
|
|
18
|
+
const triggerPulse = (setter) => {
|
|
19
|
+
setter(true);
|
|
20
|
+
setTimeout(() => setter(false), 2e3);
|
|
21
|
+
};
|
|
22
|
+
let previousImageCount = 0;
|
|
23
|
+
let previousSpeechCount = 0;
|
|
24
|
+
let previousTranscriptionCount = 0;
|
|
25
|
+
let previousVideoCount = 0;
|
|
26
|
+
createEffect(() => {
|
|
27
|
+
const count = imageCount();
|
|
28
|
+
if (count > 0 && previousImageCount === 0) {
|
|
29
|
+
triggerPulse(setImagePulse);
|
|
30
|
+
}
|
|
31
|
+
previousImageCount = count;
|
|
32
|
+
});
|
|
33
|
+
createEffect(() => {
|
|
34
|
+
const count = speechCount();
|
|
35
|
+
if (count > 0 && previousSpeechCount === 0) {
|
|
36
|
+
triggerPulse(setSpeechPulse);
|
|
37
|
+
}
|
|
38
|
+
previousSpeechCount = count;
|
|
39
|
+
});
|
|
40
|
+
createEffect(() => {
|
|
41
|
+
const count = transcriptionCount();
|
|
42
|
+
if (count > 0 && previousTranscriptionCount === 0) {
|
|
43
|
+
triggerPulse(setTranscriptionPulse);
|
|
44
|
+
}
|
|
45
|
+
previousTranscriptionCount = count;
|
|
46
|
+
});
|
|
47
|
+
createEffect(() => {
|
|
48
|
+
const count = videoCount();
|
|
49
|
+
if (count > 0 && previousVideoCount === 0) {
|
|
50
|
+
triggerPulse(setVideoPulse);
|
|
51
|
+
}
|
|
52
|
+
previousVideoCount = count;
|
|
53
|
+
});
|
|
10
54
|
const hasMessages = () => conv().type === "client" && conv().messages.length > 0;
|
|
11
55
|
const hasChunks = () => conv().chunks.length > 0 || conv().type === "server";
|
|
12
56
|
const hasSummaries = () => conv().hasSummarize || summariesCount() > 0;
|
|
57
|
+
const hasImage = () => conv().hasImage || imageCount() > 0;
|
|
58
|
+
const hasSpeech = () => conv().hasSpeech || speechCount() > 0;
|
|
59
|
+
const hasTranscription = () => conv().hasTranscription || transcriptionCount() > 0;
|
|
60
|
+
const hasVideo = () => conv().hasVideo || videoCount() > 0;
|
|
13
61
|
const visibleTabCount = () => {
|
|
14
62
|
let count = 0;
|
|
15
63
|
if (hasMessages()) count++;
|
|
16
64
|
if (hasChunks() && conv().type === "server") count++;
|
|
17
65
|
if (hasSummaries()) count++;
|
|
66
|
+
if (hasImage()) count++;
|
|
67
|
+
if (hasSpeech()) count++;
|
|
68
|
+
if (hasTranscription()) count++;
|
|
69
|
+
if (hasVideo()) count++;
|
|
18
70
|
return count;
|
|
19
71
|
};
|
|
20
72
|
if (visibleTabCount() <= 1) {
|
|
21
73
|
return null;
|
|
22
74
|
}
|
|
23
75
|
return (() => {
|
|
24
|
-
var _el$ = _tmpl$
|
|
76
|
+
var _el$ = _tmpl$8();
|
|
25
77
|
insert(_el$, createComponent(Show, {
|
|
26
78
|
get when() {
|
|
27
79
|
return hasMessages();
|
|
@@ -61,6 +113,58 @@ const ConversationTabs = (props) => {
|
|
|
61
113
|
return _el$0;
|
|
62
114
|
}
|
|
63
115
|
}), null);
|
|
116
|
+
insert(_el$, createComponent(Show, {
|
|
117
|
+
get when() {
|
|
118
|
+
return hasImage();
|
|
119
|
+
},
|
|
120
|
+
get children() {
|
|
121
|
+
var _el$12 = _tmpl$4(), _el$13 = _el$12.firstChild, _el$15 = _el$13.nextSibling;
|
|
122
|
+
_el$15.nextSibling;
|
|
123
|
+
_el$12.$$click = () => props.onTabChange("image");
|
|
124
|
+
insert(_el$12, imageCount, _el$15);
|
|
125
|
+
effect(() => className(_el$12, `${styles().actionButton} ${props.activeTab === "image" ? styles().conversationDetails.tabButtonActive : ""} ${imagePulse() ? styles().conversationDetails.tabButtonPulse : ""}`));
|
|
126
|
+
return _el$12;
|
|
127
|
+
}
|
|
128
|
+
}), null);
|
|
129
|
+
insert(_el$, createComponent(Show, {
|
|
130
|
+
get when() {
|
|
131
|
+
return hasSpeech();
|
|
132
|
+
},
|
|
133
|
+
get children() {
|
|
134
|
+
var _el$16 = _tmpl$5(), _el$17 = _el$16.firstChild, _el$19 = _el$17.nextSibling;
|
|
135
|
+
_el$19.nextSibling;
|
|
136
|
+
_el$16.$$click = () => props.onTabChange("speech");
|
|
137
|
+
insert(_el$16, speechCount, _el$19);
|
|
138
|
+
effect(() => className(_el$16, `${styles().actionButton} ${props.activeTab === "speech" ? styles().conversationDetails.tabButtonActive : ""} ${speechPulse() ? styles().conversationDetails.tabButtonPulse : ""}`));
|
|
139
|
+
return _el$16;
|
|
140
|
+
}
|
|
141
|
+
}), null);
|
|
142
|
+
insert(_el$, createComponent(Show, {
|
|
143
|
+
get when() {
|
|
144
|
+
return hasTranscription();
|
|
145
|
+
},
|
|
146
|
+
get children() {
|
|
147
|
+
var _el$20 = _tmpl$6(), _el$21 = _el$20.firstChild, _el$23 = _el$21.nextSibling;
|
|
148
|
+
_el$23.nextSibling;
|
|
149
|
+
_el$20.$$click = () => props.onTabChange("transcription");
|
|
150
|
+
insert(_el$20, transcriptionCount, _el$23);
|
|
151
|
+
effect(() => className(_el$20, `${styles().actionButton} ${props.activeTab === "transcription" ? styles().conversationDetails.tabButtonActive : ""} ${transcriptionPulse() ? styles().conversationDetails.tabButtonPulse : ""}`));
|
|
152
|
+
return _el$20;
|
|
153
|
+
}
|
|
154
|
+
}), null);
|
|
155
|
+
insert(_el$, createComponent(Show, {
|
|
156
|
+
get when() {
|
|
157
|
+
return hasVideo();
|
|
158
|
+
},
|
|
159
|
+
get children() {
|
|
160
|
+
var _el$24 = _tmpl$7(), _el$25 = _el$24.firstChild, _el$27 = _el$25.nextSibling;
|
|
161
|
+
_el$27.nextSibling;
|
|
162
|
+
_el$24.$$click = () => props.onTabChange("video");
|
|
163
|
+
insert(_el$24, videoCount, _el$27);
|
|
164
|
+
effect(() => className(_el$24, `${styles().actionButton} ${props.activeTab === "video" ? styles().conversationDetails.tabButtonActive : ""} ${videoPulse() ? styles().conversationDetails.tabButtonPulse : ""}`));
|
|
165
|
+
return _el$24;
|
|
166
|
+
}
|
|
167
|
+
}), null);
|
|
64
168
|
effect(() => className(_el$, styles().conversationDetails.tabsContainer));
|
|
65
169
|
return _el$;
|
|
66
170
|
})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConversationTabs.js","sources":["../../../../src/components/conversation/ConversationTabs.tsx"],"sourcesContent":["import { Show } from 'solid-js'\nimport { useStyles } from '../../styles/use-styles'\nimport type { Component } from 'solid-js'\nimport type { Conversation } from '../../store/ai-context'\n\nexport type TabType = 'messages' | 'chunks' | 'summaries'\n\ninterface ConversationTabsProps {\n conversation: Conversation\n activeTab: TabType\n onTabChange: (tab: TabType) => void\n}\n\nexport const ConversationTabs: Component<ConversationTabsProps> = (props) => {\n const styles = useStyles()\n const conv = () => props.conversation\n\n // Total raw chunks = sum of all chunkCounts\n const totalRawChunks = () =>\n conv().chunks.reduce((sum, c) => sum + (c.chunkCount || 1), 0)\n\n const summariesCount = () => conv().summaries?.length ?? 0\n\n // Determine if we should show any chat-related tabs\n // For server conversations, don't show messages tab - only chunks\n const hasMessages = () =>\n conv().type === 'client' && conv().messages.length > 0\n const hasChunks = () => conv().chunks.length > 0 || conv().type === 'server'\n const hasSummaries = () => conv().hasSummarize || summariesCount() > 0\n\n // Count how many tabs would be visible\n const visibleTabCount = () => {\n let count = 0\n if (hasMessages()) count++\n if (hasChunks() && conv().type === 'server') count++\n if (hasSummaries()) count++\n return count\n }\n\n // Don't render tabs if only one tab would be visible\n if (visibleTabCount() <= 1) {\n return null\n }\n\n return (\n <div class={styles().conversationDetails.tabsContainer}>\n {/* Show messages tab for client conversations or when there are messages */}\n <Show when={hasMessages()}>\n <button\n class={`${styles().actionButton} ${\n props.activeTab === 'messages'\n ? styles().conversationDetails.tabButtonActive\n : ''\n }`}\n onClick={() => props.onTabChange('messages')}\n >\n 💬 Messages ({conv().messages.length})\n </button>\n </Show>\n {/* Show chunks tab for server conversations or when there are chunks */}\n <Show when={hasChunks() && conv().type === 'server'}>\n <button\n class={`${styles().actionButton} ${\n props.activeTab === 'chunks'\n ? styles().conversationDetails.tabButtonActive\n : ''\n }`}\n onClick={() => props.onTabChange('chunks')}\n >\n 📦 Chunks ({totalRawChunks()})\n </button>\n </Show>\n {/* Show summaries tab if there are summarize operations */}\n <Show when={hasSummaries()}>\n <button\n class={`${styles().actionButton} ${\n props.activeTab === 'summaries'\n ? styles().conversationDetails.tabButtonActive\n : ''\n }`}\n onClick={() => props.onTabChange('summaries')}\n >\n 📝 Summaries ({summariesCount()})\n </button>\n </Show>\n </div>\n )\n}\n"],"names":["ConversationTabs","props","styles","useStyles","conv","conversation","totalRawChunks","chunks","reduce","sum","c","chunkCount","summariesCount","summaries","length","hasMessages","type","messages","hasChunks","hasSummaries","hasSummarize","visibleTabCount","count","_el$","_tmpl$4","_$insert","_$createComponent","Show","when","children","_el$2","_tmpl$","_el$3","firstChild","_el$5","nextSibling","$$click","onTabChange","_$effect","_$className","actionButton","activeTab","conversationDetails","tabButtonActive","_$memo","_el$6","_tmpl$2","_el$7","_el$9","_el$0","_tmpl$3","_el$1","_el$11","tabsContainer","_$delegateEvents"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ConversationTabs.js","sources":["../../../../src/components/conversation/ConversationTabs.tsx"],"sourcesContent":["import { Show, createEffect, createSignal } from 'solid-js'\nimport { useStyles } from '../../styles/use-styles'\nimport type { Component } from 'solid-js'\nimport type { Conversation } from '../../store/ai-context'\n\nexport type TabType =\n | 'messages'\n | 'chunks'\n | 'summaries'\n | 'image'\n | 'speech'\n | 'transcription'\n | 'video'\n\ninterface ConversationTabsProps {\n conversation: Conversation\n activeTab: TabType\n onTabChange: (tab: TabType) => void\n}\n\nexport const ConversationTabs: Component<ConversationTabsProps> = (props) => {\n const styles = useStyles()\n const conv = () => props.conversation\n\n // Total raw chunks = sum of all chunkCounts\n const totalRawChunks = () =>\n conv().chunks.reduce((sum, c) => sum + (c.chunkCount || 1), 0)\n\n const summariesCount = () => conv().summaries?.length ?? 0\n const imageCount = () => conv().imageEvents?.length ?? 0\n const speechCount = () => conv().speechEvents?.length ?? 0\n const transcriptionCount = () => conv().transcriptionEvents?.length ?? 0\n const videoCount = () => conv().videoEvents?.length ?? 0\n\n const [imagePulse, setImagePulse] = createSignal(false)\n const [speechPulse, setSpeechPulse] = createSignal(false)\n const [transcriptionPulse, setTranscriptionPulse] = createSignal(false)\n const [videoPulse, setVideoPulse] = createSignal(false)\n\n const triggerPulse = (setter: (value: boolean) => void) => {\n setter(true)\n setTimeout(() => setter(false), 2000)\n }\n\n let previousImageCount = 0\n let previousSpeechCount = 0\n let previousTranscriptionCount = 0\n let previousVideoCount = 0\n\n createEffect(() => {\n const count = imageCount()\n if (count > 0 && previousImageCount === 0) {\n triggerPulse(setImagePulse)\n }\n previousImageCount = count\n })\n\n createEffect(() => {\n const count = speechCount()\n if (count > 0 && previousSpeechCount === 0) {\n triggerPulse(setSpeechPulse)\n }\n previousSpeechCount = count\n })\n\n createEffect(() => {\n const count = transcriptionCount()\n if (count > 0 && previousTranscriptionCount === 0) {\n triggerPulse(setTranscriptionPulse)\n }\n previousTranscriptionCount = count\n })\n\n createEffect(() => {\n const count = videoCount()\n if (count > 0 && previousVideoCount === 0) {\n triggerPulse(setVideoPulse)\n }\n previousVideoCount = count\n })\n\n // Determine if we should show any chat-related tabs\n // For server conversations, don't show messages tab - only chunks\n const hasMessages = () =>\n conv().type === 'client' && conv().messages.length > 0\n const hasChunks = () => conv().chunks.length > 0 || conv().type === 'server'\n const hasSummaries = () => conv().hasSummarize || summariesCount() > 0\n const hasImage = () => conv().hasImage || imageCount() > 0\n const hasSpeech = () => conv().hasSpeech || speechCount() > 0\n const hasTranscription = () =>\n conv().hasTranscription || transcriptionCount() > 0\n const hasVideo = () => conv().hasVideo || videoCount() > 0\n\n // Count how many tabs would be visible\n const visibleTabCount = () => {\n let count = 0\n if (hasMessages()) count++\n if (hasChunks() && conv().type === 'server') count++\n if (hasSummaries()) count++\n if (hasImage()) count++\n if (hasSpeech()) count++\n if (hasTranscription()) count++\n if (hasVideo()) count++\n return count\n }\n\n // Don't render tabs if only one tab would be visible\n if (visibleTabCount() <= 1) {\n return null\n }\n\n return (\n <div class={styles().conversationDetails.tabsContainer}>\n {/* Show messages tab for client conversations or when there are messages */}\n <Show when={hasMessages()}>\n <button\n class={`${styles().actionButton} ${\n props.activeTab === 'messages'\n ? styles().conversationDetails.tabButtonActive\n : ''\n }`}\n onClick={() => props.onTabChange('messages')}\n >\n 💬 Messages ({conv().messages.length})\n </button>\n </Show>\n {/* Show chunks tab for server conversations or when there are chunks */}\n <Show when={hasChunks() && conv().type === 'server'}>\n <button\n class={`${styles().actionButton} ${\n props.activeTab === 'chunks'\n ? styles().conversationDetails.tabButtonActive\n : ''\n }`}\n onClick={() => props.onTabChange('chunks')}\n >\n 📦 Chunks ({totalRawChunks()})\n </button>\n </Show>\n {/* Show summaries tab if there are summarize operations */}\n <Show when={hasSummaries()}>\n <button\n class={`${styles().actionButton} ${\n props.activeTab === 'summaries'\n ? styles().conversationDetails.tabButtonActive\n : ''\n }`}\n onClick={() => props.onTabChange('summaries')}\n >\n 📝 Summaries ({summariesCount()})\n </button>\n </Show>\n <Show when={hasImage()}>\n <button\n class={`${styles().actionButton} ${\n props.activeTab === 'image'\n ? styles().conversationDetails.tabButtonActive\n : ''\n } ${imagePulse() ? styles().conversationDetails.tabButtonPulse : ''}`}\n onClick={() => props.onTabChange('image')}\n >\n 🖼️ Image ({imageCount()})\n </button>\n </Show>\n <Show when={hasSpeech()}>\n <button\n class={`${styles().actionButton} ${\n props.activeTab === 'speech'\n ? styles().conversationDetails.tabButtonActive\n : ''\n } ${speechPulse() ? styles().conversationDetails.tabButtonPulse : ''}`}\n onClick={() => props.onTabChange('speech')}\n >\n 🔊 Speech ({speechCount()})\n </button>\n </Show>\n <Show when={hasTranscription()}>\n <button\n class={`${styles().actionButton} ${\n props.activeTab === 'transcription'\n ? styles().conversationDetails.tabButtonActive\n : ''\n } ${\n transcriptionPulse()\n ? styles().conversationDetails.tabButtonPulse\n : ''\n }`}\n onClick={() => props.onTabChange('transcription')}\n >\n 📝 Transcription ({transcriptionCount()})\n </button>\n </Show>\n <Show when={hasVideo()}>\n <button\n class={`${styles().actionButton} ${\n props.activeTab === 'video'\n ? styles().conversationDetails.tabButtonActive\n : ''\n } ${videoPulse() ? styles().conversationDetails.tabButtonPulse : ''}`}\n onClick={() => props.onTabChange('video')}\n >\n 🎬 Video ({videoCount()})\n </button>\n </Show>\n </div>\n )\n}\n"],"names":["ConversationTabs","props","styles","useStyles","conv","conversation","totalRawChunks","chunks","reduce","sum","c","chunkCount","summariesCount","summaries","length","imageCount","imageEvents","speechCount","speechEvents","transcriptionCount","transcriptionEvents","videoCount","videoEvents","imagePulse","setImagePulse","createSignal","speechPulse","setSpeechPulse","transcriptionPulse","setTranscriptionPulse","videoPulse","setVideoPulse","triggerPulse","setter","setTimeout","previousImageCount","previousSpeechCount","previousTranscriptionCount","previousVideoCount","createEffect","count","hasMessages","type","messages","hasChunks","hasSummaries","hasSummarize","hasImage","hasSpeech","hasTranscription","hasVideo","visibleTabCount","_el$","_tmpl$8","_$insert","_$createComponent","Show","when","children","_el$2","_tmpl$","_el$3","firstChild","_el$5","nextSibling","$$click","onTabChange","_$effect","_$className","actionButton","activeTab","conversationDetails","tabButtonActive","_$memo","_el$6","_tmpl$2","_el$7","_el$9","_el$0","_tmpl$3","_el$1","_el$11","_el$12","_tmpl$4","_el$13","_el$15","tabButtonPulse","_el$16","_tmpl$5","_el$17","_el$19","_el$20","_tmpl$6","_el$21","_el$23","_el$24","_tmpl$7","_el$25","_el$27","tabsContainer","_$delegateEvents"],"mappings":"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"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { template, insert, createComponent, effect, className, memo } from "solid-js/web";
|
|
2
2
|
import { Show, For } from "solid-js";
|
|
3
|
+
import { JsonTree } from "@tanstack/devtools-ui";
|
|
3
4
|
import { useStyles } from "../../styles/use-styles.js";
|
|
4
|
-
import { formatTimestamp } from "../utils/format.js";
|
|
5
|
+
import { formatTimestamp, formatDuration } from "../utils/format.js";
|
|
5
6
|
import { ToolCallDisplay } from "./ToolCallDisplay.js";
|
|
6
7
|
import { ChunksCollapsible } from "./ChunksCollapsible.js";
|
|
7
|
-
var _tmpl$ = /* @__PURE__ */ template(`<div><span></span><span>`), _tmpl$2 = /* @__PURE__ */ template(`<div><span>🎯</span><span> in</span><span>•</span><span> out`), _tmpl$3 = /* @__PURE__ */ template(`<details><summary>💭 Thinking...</summary><div>`), _tmpl$
|
|
8
|
+
var _tmpl$ = /* @__PURE__ */ template(`<div><span></span><span>`), _tmpl$2 = /* @__PURE__ */ template(`<div><span>🎯</span><span> in</span><span>•</span><span> out`), _tmpl$3 = /* @__PURE__ */ template(`<div><span>⏱️</span><span>`), _tmpl$4 = /* @__PURE__ */ template(`<details><summary>💭 Thinking...</summary><div>`), _tmpl$5 = /* @__PURE__ */ template(`<div>`), _tmpl$6 = /* @__PURE__ */ template(`<div><div><div><div></div><div><div></div></div><div>`);
|
|
8
9
|
const MessageCard = (props) => {
|
|
9
10
|
const styles = useStyles();
|
|
10
11
|
const msg = () => props.message;
|
|
@@ -19,12 +20,27 @@ const MessageCard = (props) => {
|
|
|
19
20
|
}
|
|
20
21
|
return `${base} ${styles().conversationDetails.messageCardServer}`;
|
|
21
22
|
};
|
|
22
|
-
const
|
|
23
|
+
const parseJsonContent = () => {
|
|
24
|
+
const content = msg().content;
|
|
25
|
+
if (typeof content !== "string") return null;
|
|
26
|
+
const trimmed = content.trim();
|
|
27
|
+
if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return null;
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(trimmed);
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const toolDuration = () => {
|
|
35
|
+
const durations = msg().toolCalls?.map((tool) => tool.duration || 0).filter((duration) => duration > 0);
|
|
36
|
+
if (!durations || durations.length === 0) return 0;
|
|
37
|
+
return durations.reduce((total, duration) => total + duration, 0);
|
|
38
|
+
};
|
|
23
39
|
return (() => {
|
|
24
|
-
var _el$ = _tmpl$
|
|
40
|
+
var _el$ = _tmpl$6(), _el$5 = _el$.firstChild, _el$6 = _el$5.firstChild, _el$7 = _el$6.firstChild, _el$8 = _el$7.nextSibling, _el$9 = _el$8.firstChild, _el$0 = _el$8.nextSibling;
|
|
25
41
|
insert(_el$, createComponent(Show, {
|
|
26
42
|
get when() {
|
|
27
|
-
return
|
|
43
|
+
return msg().role === "assistant";
|
|
28
44
|
},
|
|
29
45
|
get children() {
|
|
30
46
|
var _el$2 = _tmpl$(), _el$3 = _el$2.firstChild, _el$4 = _el$3.nextSibling;
|
|
@@ -70,35 +86,76 @@ const MessageCard = (props) => {
|
|
|
70
86
|
return _el$1;
|
|
71
87
|
}
|
|
72
88
|
}), null);
|
|
73
|
-
insert(_el$
|
|
89
|
+
insert(_el$6, createComponent(Show, {
|
|
74
90
|
get when() {
|
|
75
|
-
return
|
|
91
|
+
return toolDuration() > 0;
|
|
76
92
|
},
|
|
77
93
|
get children() {
|
|
78
94
|
var _el$16 = _tmpl$3(), _el$17 = _el$16.firstChild, _el$18 = _el$17.nextSibling;
|
|
79
|
-
insert(_el$18, () =>
|
|
95
|
+
insert(_el$18, () => formatDuration(toolDuration()));
|
|
80
96
|
effect((_p$) => {
|
|
81
|
-
var _v$6 = styles().conversationDetails.
|
|
97
|
+
var _v$6 = styles().conversationDetails.messageUsage, _v$7 = styles().conversationDetails.messageUsageIcon;
|
|
82
98
|
_v$6 !== _p$.e && className(_el$16, _p$.e = _v$6);
|
|
83
99
|
_v$7 !== _p$.t && className(_el$17, _p$.t = _v$7);
|
|
84
|
-
|
|
100
|
+
return _p$;
|
|
101
|
+
}, {
|
|
102
|
+
e: void 0,
|
|
103
|
+
t: void 0
|
|
104
|
+
});
|
|
105
|
+
return _el$16;
|
|
106
|
+
}
|
|
107
|
+
}), null);
|
|
108
|
+
insert(_el$5, createComponent(Show, {
|
|
109
|
+
get when() {
|
|
110
|
+
return msg().thinkingContent;
|
|
111
|
+
},
|
|
112
|
+
get children() {
|
|
113
|
+
var _el$19 = _tmpl$4(), _el$20 = _el$19.firstChild, _el$21 = _el$20.nextSibling;
|
|
114
|
+
insert(_el$21, () => msg().thinkingContent);
|
|
115
|
+
effect((_p$) => {
|
|
116
|
+
var _v$8 = styles().conversationDetails.thinkingDetails, _v$9 = styles().conversationDetails.thinkingSummary, _v$0 = styles().conversationDetails.thinkingContent;
|
|
117
|
+
_v$8 !== _p$.e && className(_el$19, _p$.e = _v$8);
|
|
118
|
+
_v$9 !== _p$.t && className(_el$20, _p$.t = _v$9);
|
|
119
|
+
_v$0 !== _p$.a && className(_el$21, _p$.a = _v$0);
|
|
85
120
|
return _p$;
|
|
86
121
|
}, {
|
|
87
122
|
e: void 0,
|
|
88
123
|
t: void 0,
|
|
89
124
|
a: void 0
|
|
90
125
|
});
|
|
91
|
-
return _el$
|
|
126
|
+
return _el$19;
|
|
92
127
|
}
|
|
93
|
-
}),
|
|
94
|
-
insert(_el$
|
|
128
|
+
}), null);
|
|
129
|
+
insert(_el$5, createComponent(Show, {
|
|
130
|
+
get when() {
|
|
131
|
+
return memo(() => msg().role === "tool")() && parseJsonContent() !== null;
|
|
132
|
+
},
|
|
133
|
+
get fallback() {
|
|
134
|
+
return (() => {
|
|
135
|
+
var _el$24 = _tmpl$5();
|
|
136
|
+
insert(_el$24, () => msg().content);
|
|
137
|
+
effect(() => className(_el$24, styles().conversationDetails.messageContent));
|
|
138
|
+
return _el$24;
|
|
139
|
+
})();
|
|
140
|
+
},
|
|
141
|
+
get children() {
|
|
142
|
+
var _el$22 = _tmpl$5();
|
|
143
|
+
insert(_el$22, createComponent(JsonTree, {
|
|
144
|
+
get value() {
|
|
145
|
+
return parseJsonContent();
|
|
146
|
+
}
|
|
147
|
+
}));
|
|
148
|
+
effect(() => className(_el$22, styles().conversationDetails.toolJsonContainer));
|
|
149
|
+
return _el$22;
|
|
150
|
+
}
|
|
151
|
+
}), null);
|
|
95
152
|
insert(_el$5, createComponent(Show, {
|
|
96
153
|
get when() {
|
|
97
154
|
return memo(() => !!msg().toolCalls)() && msg().toolCalls.length > 0;
|
|
98
155
|
},
|
|
99
156
|
get children() {
|
|
100
|
-
var _el$
|
|
101
|
-
insert(_el$
|
|
157
|
+
var _el$23 = _tmpl$5();
|
|
158
|
+
insert(_el$23, createComponent(For, {
|
|
102
159
|
get each() {
|
|
103
160
|
return msg().toolCalls;
|
|
104
161
|
},
|
|
@@ -106,8 +163,8 @@ const MessageCard = (props) => {
|
|
|
106
163
|
tool
|
|
107
164
|
})
|
|
108
165
|
}));
|
|
109
|
-
effect(() => className(_el$
|
|
110
|
-
return _el$
|
|
166
|
+
effect(() => className(_el$23, styles().conversationDetails.toolCallsContainer));
|
|
167
|
+
return _el$23;
|
|
111
168
|
}
|
|
112
169
|
}), null);
|
|
113
170
|
insert(_el$5, createComponent(Show, {
|
|
@@ -123,15 +180,14 @@ const MessageCard = (props) => {
|
|
|
123
180
|
}
|
|
124
181
|
}), null);
|
|
125
182
|
effect((_p$) => {
|
|
126
|
-
var _v$
|
|
127
|
-
_v$
|
|
128
|
-
_v$
|
|
129
|
-
_v$
|
|
130
|
-
_v$
|
|
131
|
-
_v$
|
|
132
|
-
_v$
|
|
133
|
-
_v$
|
|
134
|
-
_v$14 !== _p$.h && className(_el$19, _p$.h = _v$14);
|
|
183
|
+
var _v$1 = getCardClass(), _v$10 = msg().role === "user" ? "" : styles().conversationDetails.messageCardContent, _v$11 = styles().conversationDetails.messageHeader, _v$12 = msg().role === "user" ? styles().conversationDetails.avatarUser : isClientMessage() ? styles().conversationDetails.avatarClient : styles().conversationDetails.avatarServer, _v$13 = styles().conversationDetails.roleLabel, _v$14 = msg().role === "user" ? styles().conversationDetails.roleLabelUser : isClientMessage() ? styles().conversationDetails.roleLabelClient : styles().conversationDetails.roleLabelServer, _v$15 = styles().conversationDetails.timestamp;
|
|
184
|
+
_v$1 !== _p$.e && className(_el$, _p$.e = _v$1);
|
|
185
|
+
_v$10 !== _p$.t && className(_el$5, _p$.t = _v$10);
|
|
186
|
+
_v$11 !== _p$.a && className(_el$6, _p$.a = _v$11);
|
|
187
|
+
_v$12 !== _p$.o && className(_el$7, _p$.o = _v$12);
|
|
188
|
+
_v$13 !== _p$.i && className(_el$8, _p$.i = _v$13);
|
|
189
|
+
_v$14 !== _p$.n && className(_el$9, _p$.n = _v$14);
|
|
190
|
+
_v$15 !== _p$.s && className(_el$0, _p$.s = _v$15);
|
|
135
191
|
return _p$;
|
|
136
192
|
}, {
|
|
137
193
|
e: void 0,
|
|
@@ -140,8 +196,7 @@ const MessageCard = (props) => {
|
|
|
140
196
|
o: void 0,
|
|
141
197
|
i: void 0,
|
|
142
198
|
n: void 0,
|
|
143
|
-
s: void 0
|
|
144
|
-
h: void 0
|
|
199
|
+
s: void 0
|
|
145
200
|
});
|
|
146
201
|
return _el$;
|
|
147
202
|
})();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageCard.js","sources":["../../../../src/components/conversation/MessageCard.tsx"],"sourcesContent":["import { For, Show } from 'solid-js'\nimport { useStyles } from '../../styles/use-styles'\nimport { formatTimestamp } from '../utils'\nimport { ToolCallDisplay } from './ToolCallDisplay'\nimport { ChunksCollapsible } from './ChunksCollapsible'\nimport type { Message } from '../../store/ai-store'\nimport type { Component } from 'solid-js'\n\ninterface MessageCardProps {\n message: Message\n}\n\nexport const MessageCard: Component<MessageCardProps> = (props) => {\n const styles = useStyles()\n // Access message through props directly for proper SolidJS reactivity\n const msg = () => props.message\n\n // Check if message is from client (explicitly marked) or server (default)\n const isClientMessage = () => msg().source === 'client'\n\n // Determine card class based on role and source\n const getCardClass = () => {\n const base = styles().conversationDetails.messageCard\n if (msg().role === 'user') {\n return `${base} ${styles().conversationDetails.messageCardUser}`\n }\n // For assistant messages: client if explicitly marked, otherwise server\n if (isClientMessage()) {\n return `${base} ${styles().conversationDetails.messageCardClient}`\n }\n return `${base} ${styles().conversationDetails.messageCardServer}`\n }\n\n // Check if this is a non-user message (needs source banner and content wrapper)\n const isSourcedMessage = () => msg().role !== 'user'\n\n return (\n <div class={getCardClass()}>\n {/* Source indicator banner at top of card */}\n <Show when={isSourcedMessage()}>\n <div\n class={`${styles().conversationDetails.sourceBanner} ${\n isClientMessage()\n ? styles().conversationDetails.sourceBannerClient\n : styles().conversationDetails.sourceBannerServer\n }`}\n >\n <span class={styles().conversationDetails.sourceBannerIcon}>\n {isClientMessage() ? '📱' : '☁️'}\n </span>\n <span class={styles().conversationDetails.sourceBannerText}>\n {isClientMessage() ? 'Client Message' : 'Server Message'}\n </span>\n </div>\n </Show>\n {/* Content wrapper with padding */}\n <div\n class={\n isSourcedMessage()\n ? styles().conversationDetails.messageCardContent\n : ''\n }\n >\n <div class={styles().conversationDetails.messageHeader}>\n <div\n class={\n msg().role === 'user'\n ? styles().conversationDetails.avatarUser\n : isClientMessage()\n ? styles().conversationDetails.avatarClient\n : styles().conversationDetails.avatarServer\n }\n >\n {msg().role === 'user' ? 'U' : msg().role === 'tool' ? '🔧' : '🤖'}\n </div>\n <div class={styles().conversationDetails.roleLabel}>\n <div\n class={\n msg().role === 'user'\n ? styles().conversationDetails.roleLabelUser\n : isClientMessage()\n ? styles().conversationDetails.roleLabelClient\n : styles().conversationDetails.roleLabelServer\n }\n >\n {msg().role}\n </div>\n </div>\n <div class={styles().conversationDetails.timestamp}>\n {formatTimestamp(msg().timestamp)}\n </div>\n {/* Per-message token usage */}\n <Show when={msg().usage}>\n <div class={styles().conversationDetails.messageUsage}>\n <span class={styles().conversationDetails.messageUsageIcon}>\n 🎯\n </span>\n <span>{msg().usage?.promptTokens.toLocaleString()} in</span>\n <span>•</span>\n <span>{msg().usage?.completionTokens.toLocaleString()} out</span>\n </div>\n </Show>\n </div>\n\n {/* Thinking content (for extended thinking models) */}\n <Show when={msg().thinkingContent}>\n <details class={styles().conversationDetails.thinkingDetails}>\n <summary class={styles().conversationDetails.thinkingSummary}>\n 💭 Thinking...\n </summary>\n <div class={styles().conversationDetails.thinkingContent}>\n {msg().thinkingContent}\n </div>\n </details>\n </Show>\n\n <div class={styles().conversationDetails.messageContent}>\n {msg().content}\n </div>\n\n {/* Tool Calls Display */}\n <Show when={msg().toolCalls && msg().toolCalls!.length > 0}>\n <div class={styles().conversationDetails.toolCallsContainer}>\n <For each={msg().toolCalls}>\n {(tool) => <ToolCallDisplay tool={tool} />}\n </For>\n </div>\n </Show>\n\n {/* Chunks Display (for client conversations with server chunks) */}\n <Show when={msg().chunks && msg().chunks!.length > 0}>\n <ChunksCollapsible chunks={msg().chunks!} />\n </Show>\n </div>\n </div>\n )\n}\n"],"names":["MessageCard","props","styles","useStyles","msg","message","isClientMessage","source","getCardClass","base","conversationDetails","messageCard","role","messageCardUser","messageCardClient","messageCardServer","isSourcedMessage","_el$","_tmpl$5","_el$5","firstChild","_el$6","_el$7","_el$8","nextSibling","_el$9","_el$0","_el$19","_$insert","_$createComponent","Show","when","children","_el$2","_tmpl$","_el$3","_el$4","_$effect","_p$","_v$","sourceBanner","sourceBannerClient","sourceBannerServer","_v$2","sourceBannerIcon","_v$3","sourceBannerText","e","_$className","t","a","undefined","_c$","_$memo","formatTimestamp","timestamp","usage","_el$1","_tmpl$2","_el$10","_el$11","_el$12","_el$13","_el$14","_el$15","promptTokens","toLocaleString","completionTokens","_v$4","messageUsage","_v$5","messageUsageIcon","thinkingContent","_el$16","_tmpl$3","_el$17","_el$18","_v$6","thinkingDetails","_v$7","thinkingSummary","_v$8","content","toolCalls","length","_el$20","_tmpl$4","For","each","tool","ToolCallDisplay","toolCallsContainer","chunks","ChunksCollapsible","_v$9","_v$0","messageCardContent","_v$1","messageHeader","_v$10","avatarUser","avatarClient","avatarServer","_v$11","roleLabel","_v$12","roleLabelUser","roleLabelClient","roleLabelServer","_v$13","_v$14","messageContent","o","i","n","s","h"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"MessageCard.js","sources":["../../../../src/components/conversation/MessageCard.tsx"],"sourcesContent":["import { For, Show } from 'solid-js'\nimport { JsonTree } from '@tanstack/devtools-ui'\nimport { useStyles } from '../../styles/use-styles'\nimport { formatDuration, formatTimestamp } from '../utils'\nimport { ToolCallDisplay } from './ToolCallDisplay'\nimport { ChunksCollapsible } from './ChunksCollapsible'\nimport type { Message } from '../../store/ai-store'\nimport type { Component } from 'solid-js'\n\ninterface MessageCardProps {\n message: Message\n}\n\nexport const MessageCard: Component<MessageCardProps> = (props) => {\n const styles = useStyles()\n // Access message through props directly for proper SolidJS reactivity\n const msg = () => props.message\n\n // Check if message is from client (explicitly marked) or server (default)\n const isClientMessage = () => msg().source === 'client'\n\n // Determine card class based on role and source\n const getCardClass = () => {\n const base = styles().conversationDetails.messageCard\n if (msg().role === 'user') {\n return `${base} ${styles().conversationDetails.messageCardUser}`\n }\n // For assistant messages: client if explicitly marked, otherwise server\n if (isClientMessage()) {\n return `${base} ${styles().conversationDetails.messageCardClient}`\n }\n return `${base} ${styles().conversationDetails.messageCardServer}`\n }\n\n const parseJsonContent = () => {\n const content = msg().content\n if (typeof content !== 'string') return null\n const trimmed = content.trim()\n if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) return null\n try {\n return JSON.parse(trimmed) as Record<string, unknown> | Array<unknown>\n } catch {\n return null\n }\n }\n\n const toolDuration = () => {\n const durations = msg()\n .toolCalls?.map((tool) => tool.duration || 0)\n .filter((duration) => duration > 0)\n if (!durations || durations.length === 0) return 0\n return durations.reduce((total, duration) => total + duration, 0)\n }\n\n return (\n <div class={getCardClass()}>\n {/* Source indicator banner at top of card */}\n <Show when={msg().role === 'assistant'}>\n <div\n class={`${styles().conversationDetails.sourceBanner} ${\n isClientMessage()\n ? styles().conversationDetails.sourceBannerClient\n : styles().conversationDetails.sourceBannerServer\n }`}\n >\n <span class={styles().conversationDetails.sourceBannerIcon}>\n {isClientMessage() ? '📱' : '☁️'}\n </span>\n <span class={styles().conversationDetails.sourceBannerText}>\n {isClientMessage() ? 'Client Message' : 'Server Message'}\n </span>\n </div>\n </Show>\n {/* Content wrapper with padding */}\n <div\n class={\n msg().role === 'user'\n ? ''\n : styles().conversationDetails.messageCardContent\n }\n >\n <div class={styles().conversationDetails.messageHeader}>\n <div\n class={\n msg().role === 'user'\n ? styles().conversationDetails.avatarUser\n : isClientMessage()\n ? styles().conversationDetails.avatarClient\n : styles().conversationDetails.avatarServer\n }\n >\n {msg().role === 'user' ? 'U' : msg().role === 'tool' ? '🔧' : '🤖'}\n </div>\n <div class={styles().conversationDetails.roleLabel}>\n <div\n class={\n msg().role === 'user'\n ? styles().conversationDetails.roleLabelUser\n : isClientMessage()\n ? styles().conversationDetails.roleLabelClient\n : styles().conversationDetails.roleLabelServer\n }\n >\n {msg().role}\n </div>\n </div>\n <div class={styles().conversationDetails.timestamp}>\n {formatTimestamp(msg().timestamp)}\n </div>\n {/* Per-message token usage */}\n <Show when={msg().usage}>\n <div class={styles().conversationDetails.messageUsage}>\n <span class={styles().conversationDetails.messageUsageIcon}>\n 🎯\n </span>\n <span>{msg().usage?.promptTokens.toLocaleString()} in</span>\n <span>•</span>\n <span>{msg().usage?.completionTokens.toLocaleString()} out</span>\n </div>\n </Show>\n <Show when={toolDuration() > 0}>\n <div class={styles().conversationDetails.messageUsage}>\n <span class={styles().conversationDetails.messageUsageIcon}>\n ⏱️\n </span>\n <span>{formatDuration(toolDuration())}</span>\n </div>\n </Show>\n </div>\n\n {/* Thinking content (for extended thinking models) */}\n <Show when={msg().thinkingContent}>\n <details class={styles().conversationDetails.thinkingDetails}>\n <summary class={styles().conversationDetails.thinkingSummary}>\n 💭 Thinking...\n </summary>\n <div class={styles().conversationDetails.thinkingContent}>\n {msg().thinkingContent}\n </div>\n </details>\n </Show>\n\n <Show\n when={msg().role === 'tool' && parseJsonContent() !== null}\n fallback={\n <div class={styles().conversationDetails.messageContent}>\n {msg().content}\n </div>\n }\n >\n <div class={styles().conversationDetails.toolJsonContainer}>\n <JsonTree value={parseJsonContent()!} />\n </div>\n </Show>\n\n {/* Tool Calls Display */}\n <Show when={msg().toolCalls && msg().toolCalls!.length > 0}>\n <div class={styles().conversationDetails.toolCallsContainer}>\n <For each={msg().toolCalls}>\n {(tool) => <ToolCallDisplay tool={tool} />}\n </For>\n </div>\n </Show>\n\n {/* Chunks Display (for client conversations with server chunks) */}\n <Show when={msg().chunks && msg().chunks!.length > 0}>\n <ChunksCollapsible chunks={msg().chunks!} />\n </Show>\n </div>\n </div>\n )\n}\n"],"names":["MessageCard","props","styles","useStyles","msg","message","isClientMessage","source","getCardClass","base","conversationDetails","messageCard","role","messageCardUser","messageCardClient","messageCardServer","parseJsonContent","content","trimmed","trim","startsWith","JSON","parse","toolDuration","durations","toolCalls","map","tool","duration","filter","length","reduce","total","_el$","_tmpl$6","_el$5","firstChild","_el$6","_el$7","_el$8","nextSibling","_el$9","_el$0","_$insert","_$createComponent","Show","when","children","_el$2","_tmpl$","_el$3","_el$4","_$effect","_p$","_v$","sourceBanner","sourceBannerClient","sourceBannerServer","_v$2","sourceBannerIcon","_v$3","sourceBannerText","e","_$className","t","a","undefined","_c$","_$memo","formatTimestamp","timestamp","usage","_el$1","_tmpl$2","_el$10","_el$11","_el$12","_el$13","_el$14","_el$15","promptTokens","toLocaleString","completionTokens","_v$4","messageUsage","_v$5","messageUsageIcon","_el$16","_tmpl$3","_el$17","_el$18","formatDuration","_v$6","_v$7","thinkingContent","_el$19","_tmpl$4","_el$20","_el$21","_v$8","thinkingDetails","_v$9","thinkingSummary","_v$0","fallback","_el$24","_tmpl$5","messageContent","_el$22","JsonTree","value","toolJsonContainer","_el$23","For","each","ToolCallDisplay","toolCallsContainer","chunks","ChunksCollapsible","_v$1","_v$10","messageCardContent","_v$11","messageHeader","_v$12","avatarUser","avatarClient","avatarServer","_v$13","roleLabel","_v$14","roleLabelUser","roleLabelClient","roleLabelServer","_v$15","o","i","n","s"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ParentComponent } from 'solid-js';
|
|
2
2
|
interface MessagePart {
|
|
3
|
-
type: 'text' | 'tool-call' | 'tool-result';
|
|
3
|
+
type: 'text' | 'tool-call' | 'tool-result' | 'thinking';
|
|
4
4
|
content?: string;
|
|
5
5
|
toolCallId?: string;
|
|
6
6
|
toolName?: string;
|
|
@@ -69,6 +69,8 @@ export interface Chunk {
|
|
|
69
69
|
duration?: number;
|
|
70
70
|
/** Number of raw chunks that were merged into this consolidated chunk */
|
|
71
71
|
chunkCount: number;
|
|
72
|
+
/** Whether this is a client-side tool execution */
|
|
73
|
+
isClientTool?: boolean;
|
|
72
74
|
}
|
|
73
75
|
export interface SummarizeOperation {
|
|
74
76
|
id: string;
|
|
@@ -79,6 +81,12 @@ export interface SummarizeOperation {
|
|
|
79
81
|
timestamp: number;
|
|
80
82
|
status: 'started' | 'completed';
|
|
81
83
|
}
|
|
84
|
+
export interface ActivityEvent {
|
|
85
|
+
id: string;
|
|
86
|
+
name: string;
|
|
87
|
+
timestamp: number;
|
|
88
|
+
payload: unknown;
|
|
89
|
+
}
|
|
82
90
|
export interface Conversation {
|
|
83
91
|
id: string;
|
|
84
92
|
type: 'client' | 'server';
|
|
@@ -94,12 +102,21 @@ export interface Conversation {
|
|
|
94
102
|
iterationCount?: number;
|
|
95
103
|
toolNames?: Array<string>;
|
|
96
104
|
options?: Record<string, unknown>;
|
|
97
|
-
|
|
105
|
+
modelOptions?: Record<string, unknown>;
|
|
106
|
+
systemPrompts?: Array<string>;
|
|
98
107
|
/** Flags for which operation types this conversation has */
|
|
99
108
|
hasChat?: boolean;
|
|
100
109
|
hasSummarize?: boolean;
|
|
110
|
+
hasImage?: boolean;
|
|
111
|
+
hasSpeech?: boolean;
|
|
112
|
+
hasTranscription?: boolean;
|
|
113
|
+
hasVideo?: boolean;
|
|
101
114
|
/** Summarize operations in this conversation */
|
|
102
115
|
summaries?: Array<SummarizeOperation>;
|
|
116
|
+
imageEvents?: Array<ActivityEvent>;
|
|
117
|
+
speechEvents?: Array<ActivityEvent>;
|
|
118
|
+
transcriptionEvents?: Array<ActivityEvent>;
|
|
119
|
+
videoEvents?: Array<ActivityEvent>;
|
|
103
120
|
}
|
|
104
121
|
interface AIStoreState {
|
|
105
122
|
conversations: Record<string, Conversation>;
|