@mongoosejs/studio 0.3.11 → 0.4.0
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/backend/actions/ChatThread/createChatMessage.js +15 -3
- package/backend/actions/ChatThread/createChatThread.js +8 -1
- package/backend/actions/ChatThread/index.js +1 -0
- package/backend/actions/ChatThread/streamChatMessage.js +49 -14
- package/backend/actions/ChatThread/toggleAgentMode.js +37 -0
- package/backend/actions/Model/streamChatMessage.js +15 -4
- package/backend/authorize.js +1 -0
- package/backend/chatAgent/agentSystemPrompt.js +45 -0
- package/backend/chatAgent/agentToolMetadata.js +20 -0
- package/backend/chatAgent/getAgentTools.js +140 -0
- package/backend/db/chatMessageSchema.js +5 -0
- package/backend/db/chatThreadSchema.js +4 -0
- package/backend/integrations/callLLM.js +4 -2
- package/backend/integrations/streamLLM.js +12 -4
- package/eslint.config.js +2 -1
- package/frontend/public/app.js +171 -23
- package/frontend/public/tw.css +34 -8
- package/frontend/src/api.js +6 -0
- package/frontend/src/chat/chat-message/chat-message.html +12 -1
- package/frontend/src/chat/chat-message/chat-message.js +8 -0
- package/frontend/src/chat/chat-message-script/chat-message-script.html +1 -1
- package/frontend/src/chat/chat.html +91 -44
- package/frontend/src/chat/chat.js +119 -19
- package/frontend/src/create-document/create-document.js +3 -0
- package/package.json +3 -2
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
v-if="activeTab === 'code' && !isEditing"
|
|
36
36
|
class="px-2 py-1 mr-1 text-xs bg-gray-700 text-white border-none rounded cursor-pointer hover:bg-gray-600 transition-colors flex items-center"
|
|
37
37
|
@click.stop="startEditing">
|
|
38
|
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-
|
|
38
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-4" viewBox="0 0 20 20" fill="currentColor">
|
|
39
39
|
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM4 13.5V16h2.5l7.086-7.086-2.828-2.828L4 13.5z" />
|
|
40
40
|
</svg>
|
|
41
41
|
</button>
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
class="rounded p-1.5 text-gray-400 hover:text-gray-600 hover:bg-muted"
|
|
70
70
|
title="Hide sidebar"
|
|
71
71
|
>
|
|
72
|
-
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-
|
|
72
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-5 h-5">
|
|
73
73
|
<path stroke-linecap="round" stroke-linejoin="round" d="m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5" />
|
|
74
74
|
</svg>
|
|
75
75
|
</button>
|
|
@@ -82,57 +82,104 @@
|
|
|
82
82
|
aria-label="Share thread with workspace"
|
|
83
83
|
:title="'Share thread with workspace' + (!hasWorkspace ? ' (requires a pro workspace)' : !chatThreadId ? ': Open a thread first!' : '')"
|
|
84
84
|
>
|
|
85
|
-
<svg v-if="hasWorkspace" xmlns="http://www.w3.org/2000/svg" class="w-
|
|
86
|
-
<svg v-else xmlns="http://www.w3.org/2000/svg" class="w-
|
|
85
|
+
<svg v-if="hasWorkspace" xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7a2.48 2.48 0 0 0 0-1.39l7.02-4.11a2.5 2.5 0 1 0-.87-1.37L8.04 9.94a2.5 2.5 0 1 0 0 4.12l7.12 4.16a2.5 2.5 0 1 0 .84-1.34l-7.05-4.12c-.04-.02-.08-.05-.11-.07a2.48 2.48 0 0 0 0-1.39c.03-.02.07-.04.11-.07l7.11-4.16c.52.47 1.2.76 1.94.76a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0-1.94.94L7.97 8.43a2.5 2.5 0 1 0 0 7.14l9.09 5.3c.52-.47 1.2-.76 1.94-.76a2.5 2.5 0 1 0 0-5z"/></svg>
|
|
86
|
+
<svg v-else xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"><path d="M12 1a5 5 0 00-5 5v3H6a2 2 0 00-2 2v9a2 2 0 002 2h12a2 2 0 002-2v-9a2 2 0 00-2-2h-1V6a5 5 0 00-5-5zm-3 8V6a3 3 0 016 0v3H9zm9 2v9H6v-9h12z"/></svg>
|
|
87
|
+
</button>
|
|
88
|
+
<button
|
|
89
|
+
type="button"
|
|
90
|
+
@click="toggleAgentMode"
|
|
91
|
+
class="rounded p-1.5 transition-colors"
|
|
92
|
+
:class="isAgentModeEnabled ? 'text-primary bg-primary/10' : 'text-gray-400 hover:text-gray-600 hover:bg-muted'"
|
|
93
|
+
:aria-label="isAgentModeEnabled ? 'Turn agent mode off' : 'Turn agent mode on'"
|
|
94
|
+
:aria-pressed="isAgentModeEnabled"
|
|
95
|
+
:title="isAgentModeEnabled ? 'Agent mode on' : 'Agent mode off'"
|
|
96
|
+
>
|
|
97
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="currentColor" viewBox="0 0 200 200"><path d="m187 170.9-38.72-13.73-0.55-0.25-11.24-12.18v-9.98c6.3-6.82 6.43-11.03 8.3-23.22 7.34-1.41 10.2-7.7 12.28-18.9 0.97-5.02 2.72-9.88 0.14-13.92-1.38-2.35-3.49-3.08-5.62-3.38 1.65-11.57 5.47-27.07-2.68-42.38-5.47-9.94-14-14.18-21.8-14.92-3.5-9.15-12.32-13.06-27.11-13.06h-1.06c-27.2 0-48.53 17.96-52.18 39.74-2.05 11.38-0.41 20.41 0.74 30.03-2.23 0.19-4.38 1.02-5.84 3.42-2.21 3.83-1.27 8.84 0.06 14.19 2 8.28 2.26 16.18 12.9 18.96 1.47 6.52 0.58 14.07 8.3 22.84v10.77l-12.54 12.83-38.38 12.85v24.18h57.31c-3.11-14.37-6.53-23.75-5.45-42.72l0.44-0.34c5.71 9.04 16.02 15.97 29.22 25.91l-12.68 17.15h38.07l-13.16-17.2c11.44-9.29 22.31-16.55 29.2-25.38 4.68 9.53-1.48 26.7-4.72 42.58h56.77v-23.89zm-49.56-49.09c-1.43 5.43-2.53 6.16-9.69 14.68l-11.68 13.11c-3.48 3.27-4.8 3.27-11.11 3.27h-10.39c-6.25 0-7.45-0.78-11.01-4.46-6.78-7.7-11.76-13.37-15.09-17.32-5.39-6.33-5.85-7.2-7.16-18.89-0.73-4.86-3.02-14.25-2.94-14.91 3.94 3.43 13.59 3.35 16.89 3.35 12.76 0 15.79-2.74 19.92-17.12 0.68-2.98 1.71-3.53 4-3.53 2.04 0 3.04 0.98 3.86 3.71 3.9 13.69 5.2 16.52 16.15 16.76h2.99c8.1 0 15.01-1.52 18.58-2.93-0.5 5.06-2.28 16.7-3.32 24.28zm4.72-39.02c-1.97 10.98-2.94 12.3-17.69 12.91-9.05 0.38-11.35-0.71-14.17-8.69-3.69-11.25-2.17-13 5.55-13.83 6.36-0.83 11.74-0.79 15.92-0.79 10.01 0 12.11 0.27 10.39 10.4zm-84.38-32c0-11.99 9.26-21.63 15.54-23.52 4.46-1.14 7.99 3.61 15.25 5.74 5.06 1.54 10.71 1.32 11.84 1.32 11.49 0 16.71-2.62 21.55-6.91 1.66-1.28 3.22-1.57 4.86-0.67 10.89 6.36 15.34 16.28 14.74 26.07-0.36 5.5-2.18 9.03-1.38 12.23l1.14 3.62c-3.83-0.82-6.2-0.92-10.69-0.92-9.44 0-17.61 1.24-22.14 2.5-3.66 1.24-5.2 1.44-8.35 1.44-2.98 0-4.92-0.2-7.56-1.44-4.97-1.54-14.49-2.5-21.47-2.5-3.69 0-7 0.01-10.9 0.62l-1.84 0.3 0.42-3.07c0.82-3.01-1.01-7.56-1.01-14.81z"/><path d="m116.6 125.4-12.18-2.58c-2.29-0.68-3.7 0.76-5.4 0.76-1.66 0-2.79-1.35-5.4-0.66l-10.88 2.36c-1.35 0.12-1.55 1.44-0.79 3.32 0.38 1.02 1.26 0.7 3.07 0.36 3.25-0.46 4.65-0.84 8.11-1.04 1.85-0.17 2.59 0.41 5.06 0.41h1.14c1.72 0 2.62-0.55 4.15-0.31 3.81 0.31 5.64 0.72 11.64 1.22 2.08 0.38 2.4-1.15 2.21-2.52-0.07-0.65-0.24-1.1-0.73-1.32z"/><path d="m94.08 133.5c-1.96 0-2.49 1.23-2.4 2.39 0.06 1.38 0.93 2.27 2.57 2.27h10.06c2.13 0 2.7-1.25 2.7-2.56 0-1.13-0.65-2.1-2.53-2.1h-10.4z"/><path d="m91.31 106.6c-2.13 0-2.51 3.32-1.24 4.55 1.11 1.08 7.39 3.76 9.34 3.76s8.38-3.24 9.4-3.87c1.9-1.2 0.85-4.82-1.7-4.44-1.84 0.3-6.01 3.39-7.96 3.01-1.53-0.32-6.08-3.01-7.84-3.01z"/><path d="m85.62 73.71c-5.3-1.1-10.53-1.15-14.51-1.15-10.96 0-14.08-0.44-14.33 5.26-0.47 11.15 1.82 15.96 6.69 17.19 4.7 1.26 6.84 1.08 11.71 1.08 8.88 0 10.9-1.18 14.23-10.67 2.38-6.81 1.87-10.59-3.79-11.71z"/><path d="m114.5 73.51c-7.72 0.83-7.35 2.71-6.39 9.73 1.78 7.47 3.64 11.94 10.97 12.49 3.07 0.14 4.97-0.05 8-0.32 10.72-0.96 12.6-2.48 14.45-12.22 1.88-10.29-0.54-10.77-9.79-10.77-4.18 0-10.45 0.26-17.24 1.09z"/></svg>
|
|
87
98
|
</button>
|
|
88
99
|
</div>
|
|
89
100
|
</aside>
|
|
90
101
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<
|
|
94
|
-
<div
|
|
95
|
-
<div
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
<div class="flex-1 min-w-0 flex">
|
|
103
|
+
<!-- Main Chat Area -->
|
|
104
|
+
<main class="flex-1 min-w-0 flex flex-col bg-slate-50">
|
|
105
|
+
<div class="flex-1 overflow-y-auto p-6 space-y-4" ref="messagesContainer">
|
|
106
|
+
<div v-if="chatMessages?.length === 0">
|
|
107
|
+
<div class="flex items-center w-full h-full justify-center py-3 mb-4">
|
|
108
|
+
<p class="mx-4 font-bold text-content">
|
|
109
|
+
Ask Mongoose Studio to analyze your data or generate a script
|
|
110
|
+
</p>
|
|
111
|
+
</div>
|
|
99
112
|
</div>
|
|
113
|
+
<ul role="list" class="space-y-4" v-else>
|
|
114
|
+
<li v-for="message in chatMessages" :key="message._id">
|
|
115
|
+
<chat-message :message="message" :target-dashboard-id="currentThread?.dashboardId"></chat-message>
|
|
116
|
+
</li>
|
|
117
|
+
</ul>
|
|
100
118
|
</div>
|
|
101
|
-
<ul role="list" class="space-y-4" v-else>
|
|
102
|
-
<li v-for="message in chatMessages" :key="message._id">
|
|
103
|
-
<chat-message :message="message" :target-dashboard-id="currentThread?.dashboardId"></chat-message>
|
|
104
|
-
</li>
|
|
105
|
-
</ul>
|
|
106
|
-
</div>
|
|
107
119
|
|
|
108
120
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
121
|
+
<!-- Input Area -->
|
|
122
|
+
<div class="border-t p-4">
|
|
123
|
+
<form @submit.prevent="sendMessage" :disabled="sendingMessage" class="flex gap-2 items-end justify-end">
|
|
124
|
+
<textarea
|
|
125
|
+
v-model="newMessage"
|
|
126
|
+
:placeholder="sendingMessage ? 'Sending...' : 'Ask about your data, generate a query, or build a chart…'"
|
|
127
|
+
class="flex-1 border rounded px-4 py-2 resize-none overflow-y-auto shadow-sm"
|
|
128
|
+
:disabled="sendingMessage"
|
|
129
|
+
rows="2"
|
|
130
|
+
ref="messageInput"
|
|
131
|
+
@input="adjustTextareaHeight"
|
|
132
|
+
@keydown.enter.exact.prevent="handleEnter"
|
|
133
|
+
></textarea>
|
|
134
|
+
<button class="bg-primary hover:bg-primary-hover text-white px-4 h-[42px] rounded disabled:bg-gray-600" :disabled="sendingMessage">
|
|
135
|
+
<svg v-if="sendingMessage" style="height: 1em" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
136
|
+
<g>
|
|
137
|
+
<circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2" opacity="0.3" />
|
|
138
|
+
<path d="M12 2a10 10 0 0 1 10 10" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
|
|
139
|
+
<animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite" />
|
|
140
|
+
</path>
|
|
141
|
+
</g>
|
|
142
|
+
</svg>
|
|
143
|
+
<span v-else>Send</span>
|
|
144
|
+
</button>
|
|
145
|
+
</form>
|
|
146
|
+
</div>
|
|
147
|
+
</main>
|
|
148
|
+
|
|
149
|
+
<aside
|
|
150
|
+
v-if="isAgentModeEnabled"
|
|
151
|
+
class="hidden lg:flex shrink-0 border-l border-edge bg-page transition-all duration-300 ease-in-out overflow-hidden"
|
|
152
|
+
:class="showAgentSidebar ? 'w-80' : 'w-0 border-l-0'"
|
|
153
|
+
>
|
|
154
|
+
<div v-if="showAgentSidebar" class="flex h-full w-80 flex-col">
|
|
155
|
+
<div class="flex items-center justify-between border-b border-edge px-4 py-3">
|
|
156
|
+
<div>
|
|
157
|
+
<h2 class="text-sm font-semibold text-content">Agent Mode</h2>
|
|
158
|
+
<p class="mt-1 text-xs text-content-tertiary">Agent mode lets Mongoose Studio inspect your data and validate scripts before it responds.</p>
|
|
159
|
+
</div>
|
|
160
|
+
<button
|
|
161
|
+
type="button"
|
|
162
|
+
@click="closeAgentSidebar"
|
|
163
|
+
class="rounded p-1.5 text-gray-400 hover:bg-muted hover:text-gray-600"
|
|
164
|
+
title="Hide agent sidebar"
|
|
165
|
+
>
|
|
166
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
|
167
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12" />
|
|
168
|
+
</svg>
|
|
169
|
+
</button>
|
|
170
|
+
</div>
|
|
171
|
+
<div class="flex-1 overflow-y-auto px-4 py-4">
|
|
172
|
+
<div class="mb-3 text-xs font-semibold uppercase tracking-wider text-gray-400">Available Tools</div>
|
|
173
|
+
<ul role="list" class="space-y-3">
|
|
174
|
+
<li v-for="tool in agentTools" :key="tool.name" class="rounded-md border border-edge bg-surface px-3 py-3">
|
|
175
|
+
<div class="text-sm font-medium text-content">{{ tool.name }}</div>
|
|
176
|
+
<div class="mt-1 text-sm text-content-secondary">{{ tool.description }}</div>
|
|
177
|
+
</li>
|
|
178
|
+
</ul>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</aside>
|
|
182
|
+
</div>
|
|
136
183
|
|
|
137
184
|
<pro-upgrade-modal
|
|
138
185
|
:show="showProUpgradeModal"
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const api = require('../api');
|
|
4
|
+
const agentToolMetadata = require('../../../backend/chatAgent/agentToolMetadata');
|
|
4
5
|
const getCurrentDateTimeContext = require('../getCurrentDateTimeContext');
|
|
5
6
|
const template = require('./chat.html');
|
|
6
7
|
|
|
8
|
+
const AGENT_MODE_STORAGE_KEY = '_mongooseStudioAgentMode';
|
|
9
|
+
|
|
7
10
|
module.exports = {
|
|
8
11
|
template: template,
|
|
9
12
|
props: ['threadId'],
|
|
@@ -12,12 +15,15 @@ module.exports = {
|
|
|
12
15
|
sendingMessage: false,
|
|
13
16
|
newMessage: '',
|
|
14
17
|
chatThreadId: null,
|
|
18
|
+
draftAgentMode: false,
|
|
15
19
|
chatThreads: [],
|
|
16
20
|
chatMessages: [],
|
|
17
21
|
hideSidebar: null,
|
|
22
|
+
showAgentSidebar: false,
|
|
18
23
|
sharingThread: false,
|
|
19
24
|
threadSearch: '',
|
|
20
|
-
showProUpgradeModal: false
|
|
25
|
+
showProUpgradeModal: false,
|
|
26
|
+
agentTools: agentToolMetadata
|
|
21
27
|
}),
|
|
22
28
|
methods: {
|
|
23
29
|
async sendMessage() {
|
|
@@ -26,7 +32,9 @@ module.exports = {
|
|
|
26
32
|
const content = this.newMessage;
|
|
27
33
|
this.newMessage = '';
|
|
28
34
|
if (!this.chatThreadId) {
|
|
29
|
-
const { chatThread } = await api.ChatThread.createChatThread(
|
|
35
|
+
const { chatThread } = await api.ChatThread.createChatThread({
|
|
36
|
+
agentMode: this.draftAgentMode
|
|
37
|
+
});
|
|
30
38
|
this.chatThreads.unshift(chatThread);
|
|
31
39
|
this.chatThreadId = chatThread._id;
|
|
32
40
|
this.chatMessages = [];
|
|
@@ -40,11 +48,7 @@ module.exports = {
|
|
|
40
48
|
role: 'user'
|
|
41
49
|
});
|
|
42
50
|
|
|
43
|
-
this
|
|
44
|
-
if (this.$refs.messagesContainer) {
|
|
45
|
-
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
|
|
46
|
-
}
|
|
47
|
-
});
|
|
51
|
+
this.scrollToBottom();
|
|
48
52
|
|
|
49
53
|
const params = {
|
|
50
54
|
chatThreadId: this.chatThreadId,
|
|
@@ -53,6 +57,7 @@ module.exports = {
|
|
|
53
57
|
};
|
|
54
58
|
let userChatMessage = null;
|
|
55
59
|
let assistantChatMessage = null;
|
|
60
|
+
const toolCalls = [];
|
|
56
61
|
for await (const event of api.ChatThread.streamChatMessage(params)) {
|
|
57
62
|
if (event.chatMessage) {
|
|
58
63
|
if (!userChatMessage) {
|
|
@@ -61,6 +66,7 @@ module.exports = {
|
|
|
61
66
|
} else {
|
|
62
67
|
const assistantChatMessageIndex = this.chatMessages.indexOf(assistantChatMessage);
|
|
63
68
|
assistantChatMessage = event.chatMessage;
|
|
69
|
+
assistantChatMessage.toolCalls = toolCalls;
|
|
64
70
|
if (assistantChatMessageIndex !== -1) {
|
|
65
71
|
this.chatMessages.splice(assistantChatMessageIndex, 1, assistantChatMessage);
|
|
66
72
|
} else {
|
|
@@ -73,27 +79,44 @@ module.exports = {
|
|
|
73
79
|
thread.title = event.chatThread.title;
|
|
74
80
|
}
|
|
75
81
|
}
|
|
82
|
+
} else if (event.toolCall) {
|
|
83
|
+
toolCalls.push({ toolName: event.toolCall.toolName, input: event.toolCall.input, status: 'running' });
|
|
84
|
+
if (!assistantChatMessage) {
|
|
85
|
+
assistantChatMessage = {
|
|
86
|
+
_id: Math.random().toString(36).substr(2, 9),
|
|
87
|
+
content: '',
|
|
88
|
+
role: 'assistant',
|
|
89
|
+
toolCalls: [...toolCalls]
|
|
90
|
+
};
|
|
91
|
+
this.chatMessages.push(assistantChatMessage);
|
|
92
|
+
assistantChatMessage = this.chatMessages[this.chatMessages.length - 1];
|
|
93
|
+
} else {
|
|
94
|
+
assistantChatMessage.toolCalls = [...toolCalls];
|
|
95
|
+
}
|
|
96
|
+
this.scrollToBottom();
|
|
97
|
+
} else if (event.toolResult) {
|
|
98
|
+
const tc = toolCalls.find(t => t.toolName === event.toolResult.toolName && t.status === 'running');
|
|
99
|
+
if (tc) {
|
|
100
|
+
tc.status = 'done';
|
|
101
|
+
}
|
|
102
|
+
if (assistantChatMessage) {
|
|
103
|
+
assistantChatMessage.toolCalls = [...toolCalls];
|
|
104
|
+
}
|
|
105
|
+
this.scrollToBottom();
|
|
76
106
|
} else if (event.textPart) {
|
|
77
107
|
if (!assistantChatMessage) {
|
|
78
108
|
assistantChatMessage = {
|
|
79
109
|
_id: Math.random().toString(36).substr(2, 9),
|
|
80
110
|
content: event.textPart,
|
|
81
|
-
role: 'assistant'
|
|
111
|
+
role: 'assistant',
|
|
112
|
+
toolCalls: [...toolCalls]
|
|
82
113
|
};
|
|
83
114
|
this.chatMessages.push(assistantChatMessage);
|
|
84
115
|
assistantChatMessage = this.chatMessages[this.chatMessages.length - 1];
|
|
85
|
-
this
|
|
86
|
-
if (this.$refs.messagesContainer) {
|
|
87
|
-
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
|
|
88
|
-
}
|
|
89
|
-
});
|
|
116
|
+
this.scrollToBottom();
|
|
90
117
|
} else {
|
|
91
118
|
assistantChatMessage.content += event.textPart;
|
|
92
|
-
this
|
|
93
|
-
if (this.$refs.messagesContainer) {
|
|
94
|
-
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
|
|
95
|
-
}
|
|
96
|
-
});
|
|
119
|
+
this.scrollToBottom();
|
|
97
120
|
}
|
|
98
121
|
} else if (event.message) {
|
|
99
122
|
throw new Error(event.message);
|
|
@@ -112,10 +135,38 @@ module.exports = {
|
|
|
112
135
|
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
|
|
113
136
|
}
|
|
114
137
|
});
|
|
138
|
+
} catch (err) {
|
|
139
|
+
this.$toast.error(err?.message || 'Failed to send message.');
|
|
115
140
|
} finally {
|
|
116
141
|
this.sendingMessage = false;
|
|
117
142
|
}
|
|
118
143
|
},
|
|
144
|
+
async toggleAgentMode() {
|
|
145
|
+
const wasEnabled = this.isAgentModeEnabled;
|
|
146
|
+
const newValue = !this.isAgentModeEnabled;
|
|
147
|
+
this.draftAgentMode = newValue;
|
|
148
|
+
this.persistAgentModePreference(newValue);
|
|
149
|
+
if (!this.chatThreadId) {
|
|
150
|
+
this.maybeOpenAgentSidebar({ wasEnabled, isEnabled: newValue });
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const { chatThread } = await api.ChatThread.toggleAgentMode({
|
|
154
|
+
chatThreadId: this.chatThreadId,
|
|
155
|
+
agentMode: newValue
|
|
156
|
+
});
|
|
157
|
+
const idx = this.chatThreads.findIndex(t => t._id === chatThread._id);
|
|
158
|
+
if (idx !== -1) {
|
|
159
|
+
this.chatThreads.splice(idx, 1, chatThread);
|
|
160
|
+
}
|
|
161
|
+
this.maybeOpenAgentSidebar({ wasEnabled, isEnabled: newValue });
|
|
162
|
+
},
|
|
163
|
+
scrollToBottom() {
|
|
164
|
+
this.$nextTick(() => {
|
|
165
|
+
if (this.$refs.messagesContainer) {
|
|
166
|
+
this.$refs.messagesContainer.scrollTop = this.$refs.messagesContainer.scrollHeight;
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
},
|
|
119
170
|
handleEnter(ev) {
|
|
120
171
|
if (!ev.shiftKey) {
|
|
121
172
|
this.sendMessage();
|
|
@@ -135,7 +186,9 @@ module.exports = {
|
|
|
135
186
|
return message.role === 'user' ? 'bg-muted' : '';
|
|
136
187
|
},
|
|
137
188
|
async createNewThread() {
|
|
138
|
-
const { chatThread } = await api.ChatThread.createChatThread(
|
|
189
|
+
const { chatThread } = await api.ChatThread.createChatThread({
|
|
190
|
+
agentMode: this.draftAgentMode
|
|
191
|
+
});
|
|
139
192
|
this.$toast.success('Chat thread created!');
|
|
140
193
|
this.$router.push('/chat/' + chatThread._id);
|
|
141
194
|
},
|
|
@@ -177,12 +230,57 @@ module.exports = {
|
|
|
177
230
|
} finally {
|
|
178
231
|
this.sharingThread = false;
|
|
179
232
|
}
|
|
233
|
+
},
|
|
234
|
+
isDesktopViewport() {
|
|
235
|
+
return typeof window !== 'undefined' &&
|
|
236
|
+
typeof window.matchMedia === 'function' &&
|
|
237
|
+
window.matchMedia('(min-width: 1024px)').matches;
|
|
238
|
+
},
|
|
239
|
+
getAgentModePreference() {
|
|
240
|
+
if (typeof window === 'undefined') {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
return window.localStorage?.getItem(AGENT_MODE_STORAGE_KEY) === 'true';
|
|
244
|
+
},
|
|
245
|
+
persistAgentModePreference(agentMode) {
|
|
246
|
+
if (typeof window !== 'undefined') {
|
|
247
|
+
window.localStorage?.setItem(AGENT_MODE_STORAGE_KEY, String(agentMode));
|
|
248
|
+
}
|
|
249
|
+
},
|
|
250
|
+
async syncCurrentThreadAgentMode() {
|
|
251
|
+
if (!this.chatThreadId || !this.currentThread || !this.draftAgentMode || this.currentThread.agentMode) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
const { chatThread } = await api.ChatThread.toggleAgentMode({
|
|
255
|
+
chatThreadId: this.chatThreadId,
|
|
256
|
+
agentMode: true
|
|
257
|
+
});
|
|
258
|
+
const idx = this.chatThreads.findIndex(t => t._id === chatThread._id);
|
|
259
|
+
if (idx !== -1) {
|
|
260
|
+
this.chatThreads.splice(idx, 1, chatThread);
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
maybeOpenAgentSidebar({ wasEnabled, isEnabled }) {
|
|
264
|
+
if (!isEnabled) {
|
|
265
|
+
this.showAgentSidebar = false;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (wasEnabled || !this.isDesktopViewport()) {
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
this.showAgentSidebar = true;
|
|
272
|
+
},
|
|
273
|
+
closeAgentSidebar() {
|
|
274
|
+
this.showAgentSidebar = false;
|
|
180
275
|
}
|
|
181
276
|
},
|
|
182
277
|
computed: {
|
|
183
278
|
currentThread() {
|
|
184
279
|
return this.chatThreads.find(t => t._id === this.chatThreadId);
|
|
185
280
|
},
|
|
281
|
+
isAgentModeEnabled() {
|
|
282
|
+
return this.currentThread?.agentMode ?? this.draftAgentMode;
|
|
283
|
+
},
|
|
186
284
|
hasWorkspace() {
|
|
187
285
|
return !!window.MONGOOSE_STUDIO_CONFIG.workspace?._id;
|
|
188
286
|
},
|
|
@@ -200,10 +298,12 @@ module.exports = {
|
|
|
200
298
|
async mounted() {
|
|
201
299
|
window.pageState = this;
|
|
202
300
|
|
|
301
|
+
this.draftAgentMode = this.getAgentModePreference();
|
|
203
302
|
this.chatThreadId = this.threadId;
|
|
204
303
|
const { chatThreads } = await api.ChatThread.listChatThreads();
|
|
205
304
|
this.chatThreads = chatThreads;
|
|
206
305
|
if (this.chatThreadId) {
|
|
306
|
+
await this.syncCurrentThreadAgentMode();
|
|
207
307
|
const { chatMessages } = await api.ChatThread.getChatThread({ chatThreadId: this.chatThreadId });
|
|
208
308
|
this.chatMessages = chatMessages;
|
|
209
309
|
}
|
|
@@ -53,6 +53,9 @@ module.exports = app => app.component('create-document', {
|
|
|
53
53
|
documentData: this.aiOriginalDocument,
|
|
54
54
|
currentDateTime: getCurrentDateTimeContext()
|
|
55
55
|
})) {
|
|
56
|
+
if (event?.message) {
|
|
57
|
+
throw new Error(event.message);
|
|
58
|
+
}
|
|
56
59
|
if (event?.textPart) {
|
|
57
60
|
this.aiSuggestion += event.textPart;
|
|
58
61
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mongoosejs/studio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "A Mongoose-native MongoDB UI with schema-aware autocomplete, AI-assisted queries, and dashboards that understand your models - not just your data.",
|
|
5
5
|
"homepage": "https://mongoosestudio.app/",
|
|
6
6
|
"repository": {
|
|
@@ -22,10 +22,11 @@
|
|
|
22
22
|
"node-inspect-extracted": "3.x",
|
|
23
23
|
"regexp.escape": "^2.0.1",
|
|
24
24
|
"tailwindcss": "3.4.0",
|
|
25
|
+
"time-commando": "1.0.1",
|
|
26
|
+
"typescript": "^6.0.2",
|
|
25
27
|
"vue": "3.x",
|
|
26
28
|
"vue-toastification": "^2.0.0-rc.5",
|
|
27
29
|
"webpack": "5.x",
|
|
28
|
-
"time-commando": "1.0.1",
|
|
29
30
|
"xss": "^1.0.15"
|
|
30
31
|
},
|
|
31
32
|
"peerDependencies": {
|