@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.
@@ -10,7 +10,8 @@ const ExecuteScriptParams = new Archetype({
10
10
  $type: mongoose.Types.ObjectId
11
11
  },
12
12
  chatMessageId: {
13
- $type: mongoose.Types.ObjectId
13
+ $type: mongoose.Types.ObjectId,
14
+ $required: true
14
15
  },
15
16
  script: {
16
17
  $type: 'string'
@@ -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();
@@ -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.