@mongoosejs/studio 0.2.5 → 0.2.7
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/ChatMessage/executeScript.js +2 -1
- package/backend/actions/Model/createChatMessage.js +54 -0
- package/backend/actions/Model/index.js +2 -0
- package/backend/actions/Model/streamChatMessage.js +58 -0
- package/backend/authorize.js +1 -0
- package/backend/helpers/getModelDescriptions.js +8 -0
- package/backend/integrations/callLLM.js +1 -1
- package/backend/integrations/streamLLM.js +1 -1
- package/docs/user_stories.md +13 -0
- package/frontend/public/app.js +20149 -16871
- package/frontend/public/tw.css +95 -0
- package/frontend/src/api.js +60 -0
- package/frontend/src/chat/chat.js +6 -2
- package/frontend/src/create-document/create-document.html +36 -1
- package/frontend/src/create-document/create-document.js +51 -1
- package/frontend/src/detail-default/detail-default.html +15 -2
- package/frontend/src/detail-default/detail-default.js +1066 -2
- package/frontend/src/document-details/document-property/document-property.html +71 -3
- package/frontend/src/document-details/document-property/document-property.js +67 -1
- package/frontend/src/models/models.html +41 -3
- package/frontend/src/models/models.js +252 -3
- package/package.json +3 -2
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Archetype = require('archetype');
|
|
4
|
+
const authorize = require('../../authorize');
|
|
5
|
+
const callLLM = require('../../integrations/callLLM');
|
|
6
|
+
const getModelDescriptions = require('../../helpers/getModelDescriptions');
|
|
7
|
+
|
|
8
|
+
const CreateChatMessageParams = new Archetype({
|
|
9
|
+
model: {
|
|
10
|
+
$type: 'string',
|
|
11
|
+
$required: true
|
|
12
|
+
},
|
|
13
|
+
content: {
|
|
14
|
+
$type: 'string',
|
|
15
|
+
$required: true
|
|
16
|
+
},
|
|
17
|
+
documentData: {
|
|
18
|
+
$type: 'string'
|
|
19
|
+
},
|
|
20
|
+
roles: {
|
|
21
|
+
$type: ['string']
|
|
22
|
+
}
|
|
23
|
+
}).compile('CreateChatMessageParams');
|
|
24
|
+
|
|
25
|
+
module.exports = ({ db, options }) => async function createChatMessage(params) {
|
|
26
|
+
const { model, content, documentData, roles } = new CreateChatMessageParams(params);
|
|
27
|
+
|
|
28
|
+
await authorize('Model.createChatMessage', roles);
|
|
29
|
+
|
|
30
|
+
const Model = db.models[model];
|
|
31
|
+
if (Model == null) {
|
|
32
|
+
throw new Error(`Model ${model} not found`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const modelDescriptions = getModelDescriptions({ models: { [Model.modelName]: Model } });
|
|
36
|
+
const context = [
|
|
37
|
+
modelDescriptions,
|
|
38
|
+
'Current draft document:\n' + (documentData || '')
|
|
39
|
+
].join('\n\n');
|
|
40
|
+
const system = systemPrompt + '\n\n' + context + (options?.context ? '\n\n' + options.context : '');
|
|
41
|
+
|
|
42
|
+
const llmMessages = [{ role: 'user', content: [{ type: 'text', text: content }] }];
|
|
43
|
+
const res = await callLLM(llmMessages, system, options);
|
|
44
|
+
|
|
45
|
+
return { text: res.text };
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const systemPrompt = `
|
|
49
|
+
You are a helpful assistant that drafts MongoDB documents for the user.
|
|
50
|
+
|
|
51
|
+
Use the model description and the current draft document to refine the user's intent.
|
|
52
|
+
|
|
53
|
+
Return only the updated document body as a JavaScript object literal. Do not use Markdown or code fences.
|
|
54
|
+
`.trim();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
exports.addField = require('./addField');
|
|
4
|
+
exports.createChatMessage = require('./createChatMessage');
|
|
4
5
|
exports.createDocument = require('./createDocument');
|
|
5
6
|
exports.deleteDocument = require('./deleteDocument');
|
|
6
7
|
exports.deleteDocuments = require('./deleteDocuments');
|
|
@@ -12,5 +13,6 @@ exports.getDocumentsStream = require('./getDocumentsStream');
|
|
|
12
13
|
exports.getCollectionInfo = require('./getCollectionInfo');
|
|
13
14
|
exports.getIndexes = require('./getIndexes');
|
|
14
15
|
exports.listModels = require('./listModels');
|
|
16
|
+
exports.streamChatMessage = require('./streamChatMessage');
|
|
15
17
|
exports.updateDocument = require('./updateDocument');
|
|
16
18
|
exports.updateDocuments = require('./updateDocuments');
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Archetype = require('archetype');
|
|
4
|
+
const authorize = require('../../authorize');
|
|
5
|
+
const streamLLM = require('../../integrations/streamLLM');
|
|
6
|
+
const getModelDescriptions = require('../../helpers/getModelDescriptions');
|
|
7
|
+
|
|
8
|
+
const StreamChatMessageParams = new Archetype({
|
|
9
|
+
model: {
|
|
10
|
+
$type: 'string',
|
|
11
|
+
$required: true
|
|
12
|
+
},
|
|
13
|
+
content: {
|
|
14
|
+
$type: 'string',
|
|
15
|
+
$required: true
|
|
16
|
+
},
|
|
17
|
+
documentData: {
|
|
18
|
+
$type: 'string'
|
|
19
|
+
},
|
|
20
|
+
roles: {
|
|
21
|
+
$type: ['string']
|
|
22
|
+
}
|
|
23
|
+
}).compile('StreamChatMessageParams');
|
|
24
|
+
|
|
25
|
+
module.exports = ({ db, options }) => async function* streamChatMessage(params) {
|
|
26
|
+
const { model, content, documentData, roles } = new StreamChatMessageParams(params);
|
|
27
|
+
|
|
28
|
+
await authorize('Model.streamChatMessage', roles);
|
|
29
|
+
|
|
30
|
+
const Model = db.models[model];
|
|
31
|
+
if (Model == null) {
|
|
32
|
+
throw new Error(`Model ${model} not found`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const modelDescriptions = getModelDescriptions({ models: { [Model.modelName]: Model } });
|
|
36
|
+
const context = [
|
|
37
|
+
modelDescriptions,
|
|
38
|
+
'Current draft document:\n' + (documentData || '')
|
|
39
|
+
].join('\n\n');
|
|
40
|
+
const system = systemPrompt + '\n\n' + context + (options?.context ? '\n\n' + options.context : '');
|
|
41
|
+
|
|
42
|
+
const llmMessages = [{ role: 'user', content: [{ type: 'text', text: content }] }];
|
|
43
|
+
const textStream = streamLLM(llmMessages, system, options);
|
|
44
|
+
|
|
45
|
+
for await (const textPart of textStream) {
|
|
46
|
+
yield { textPart };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const systemPrompt = `
|
|
53
|
+
You are a helpful assistant that drafts MongoDB documents for the user.
|
|
54
|
+
|
|
55
|
+
Use the model description and the current draft document to refine the user's intent.
|
|
56
|
+
|
|
57
|
+
Return only the updated document body as a JavaScript object literal. Do not use Markdown or code fences.
|
|
58
|
+
`.trim();
|
package/backend/authorize.js
CHANGED
|
@@ -23,6 +23,7 @@ const actionsToRequiredRoles = {
|
|
|
23
23
|
'Model.getDocumentsStream': ['owner', 'admin', 'member', 'readonly'],
|
|
24
24
|
'Model.getIndexes': ['owner', 'admin', 'member', 'readonly'],
|
|
25
25
|
'Model.listModels': ['owner', 'admin', 'member', 'readonly'],
|
|
26
|
+
'Model.streamChatMessage': ['owner', 'admin', 'member', 'readonly'],
|
|
26
27
|
'Model.updateDocuments': ['owner', 'admin', 'member']
|
|
27
28
|
};
|
|
28
29
|
|
|
@@ -17,8 +17,16 @@ const formatSchemaTypeInstance = schemaType => {
|
|
|
17
17
|
return schemaType.instance;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
+
const formatEnum = schemaType => {
|
|
21
|
+
if (!schemaType.options?.enum) {
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
24
|
+
return ` (enum: ${JSON.stringify(schemaType.options.enum)})`;
|
|
25
|
+
};
|
|
26
|
+
|
|
20
27
|
const formatSchemaPath = (path, schemaType) => `- ${path}: ${formatSchemaTypeInstance(schemaType)}` +
|
|
21
28
|
formatRef(schemaType) +
|
|
29
|
+
formatEnum(schemaType) +
|
|
22
30
|
(schemaType.schema ? formatNestedSchema(schemaType) : '');
|
|
23
31
|
|
|
24
32
|
const listModelPaths = Model => [
|
|
@@ -54,7 +54,7 @@ module.exports = async function callLLM(messages, system, options) {
|
|
|
54
54
|
method: 'POST',
|
|
55
55
|
headers,
|
|
56
56
|
body: JSON.stringify({
|
|
57
|
-
messages,
|
|
57
|
+
messages: [{ role: 'system', content: { type: 'text', text: system } }, ...messages],
|
|
58
58
|
model: options?.model
|
|
59
59
|
})
|
|
60
60
|
}).then(response => {
|
|
@@ -66,7 +66,7 @@ module.exports = async function* streamLLM(messages, system, options) {
|
|
|
66
66
|
method: 'POST',
|
|
67
67
|
headers,
|
|
68
68
|
body: JSON.stringify({
|
|
69
|
-
messages,
|
|
69
|
+
messages: [{ role: 'system', content: { type: 'text', text: system } }, ...messages],
|
|
70
70
|
model: options?.model
|
|
71
71
|
})
|
|
72
72
|
}).then(response => {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# User Stories
|
|
2
|
+
|
|
3
|
+
## Document Details
|
|
4
|
+
|
|
5
|
+
/model/:modelName/document/:documentId
|
|
6
|
+
|
|
7
|
+
### Maps
|
|
8
|
+
|
|
9
|
+
1. As a user, I want to be able to see GeoJSON points on a map so I don't have to go somewhere else to view latitude/longitude.
|
|
10
|
+
2. As a user, I want to be able to see GeoJSON polygons on a map so I don't have to go somewhere else to view latitude/longitude.
|
|
11
|
+
3. As a user, I want to be able to drag to edit the coordinates of a GeoJSON point so I don't have to copy/paste latitude/longitude.
|
|
12
|
+
4. As a user, I want to be able to drag to edit the vertexes of a GeoJSON polygon so I don't have to copy/paste latitude/longitude.
|
|
13
|
+
5. As a user, I want to be able to remove a vertex from a GeoJSON polygon down to a triangle and then drag to edit the coordinates of the remaining vertexes.
|