json-object-editor 0.10.521 → 0.10.622
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/CHANGELOG.md +14 -0
- package/_www/mcp-nav.js +1 -0
- package/app.js +26 -2
- package/css/joe-styles.css +5 -0
- package/css/joe.css +23 -18
- package/css/joe.min.css +4 -4
- package/js/JsonObjectEditor.jquery.craydent.js +52 -61
- package/js/joe-ai.js +399 -0
- package/js/joe.js +54 -61
- package/js/joe.min.js +1 -1
- package/package.json +5 -5
- package/readme.md +139 -2
- package/server/app-config.js +2 -1
- package/server/fields/core.js +35 -17
- package/server/modules/Server.js +50 -0
- package/server/modules/Storage.js +7 -1
- package/server/modules/Utils.js +2 -1
- package/server/plugins/awsConnect.js +51 -20
- package/server/plugins/chatgpt-assistants.js +3 -3
- package/server/plugins/chatgpt-responses.js +45 -0
- package/server/plugins/chatgpt.js +729 -0
- package/server/plugins/notifier.js +122 -8
- package/server/schemas/ai_assistant.js +255 -0
- package/server/schemas/ai_conversation.js +34 -0
- package/server/schemas/ai_prompt.js +323 -0
- package/server/schemas/ai_response.js +217 -0
- package/server/schemas/ai_tool.js +30 -0
- package/server/schemas/ai_widget_conversation.js +110 -0
- package/server/schemas/notification.js +48 -0
- package/server/schemas/task.js +5 -0
- package/server/webconfig.js +3 -1
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
var schema = {
|
|
2
|
+
display:'Ai Prompt',
|
|
3
|
+
title : 'Ai Prompt | ${name}',
|
|
4
|
+
info:"An ai prompt that can be sent to openAi, etc",
|
|
5
|
+
summary:{
|
|
6
|
+
description:'Reusable AI prompt definition that describes how to call the chatgpt plugin or Responses API.',
|
|
7
|
+
purpose:'Use ai_prompt to define prompt methods, helper functions, and instructions for generating structured AI responses or content. Prompts can be tagged, scoped to datasets, and linked to ai_response records.',
|
|
8
|
+
labelField:'name',
|
|
9
|
+
defaultSort:{ field:'joeUpdated', dir:'desc' },
|
|
10
|
+
searchableFields:['name','info','prompt_method','ai_model','tags','datasets'],
|
|
11
|
+
allowedSorts:['joeUpdated','created','name','ai_model'],
|
|
12
|
+
relationships:{
|
|
13
|
+
outbound:[
|
|
14
|
+
{ field:'status', targetSchema:'status', cardinality:'one' },
|
|
15
|
+
{ field:'tags', targetSchema:'tag', cardinality:'many' },
|
|
16
|
+
{ field:'datasets', targetSchema:'<schemaName>', cardinality:'many' }
|
|
17
|
+
],
|
|
18
|
+
inbound:{ graphRef:'server/relationships.graph.json' }
|
|
19
|
+
},
|
|
20
|
+
joeManagedFields:['created','joeUpdated'],
|
|
21
|
+
fields:[
|
|
22
|
+
{ name:'_id', type:'string', required:true },
|
|
23
|
+
{ name:'itemtype', type:'string', required:true, const:'ai_prompt' },
|
|
24
|
+
{ name:'name', type:'string', required:true },
|
|
25
|
+
{ name:'info', type:'string' },
|
|
26
|
+
{ name:'prompt_method', type:'string' },
|
|
27
|
+
{ name:'content_items', type:'objectList' },
|
|
28
|
+
{ name:'functions', type:'string' },
|
|
29
|
+
{ name:'instructions_format', type:'string' },
|
|
30
|
+
{ name:'instructions', type:'string' },
|
|
31
|
+
{ name:'user_prompt', type:'string' },
|
|
32
|
+
{ name:'status', type:'string', isReference:true, targetSchema:'status' },
|
|
33
|
+
{ name:'tags', type:'string', isArray:true, isReference:true, targetSchema:'tag' },
|
|
34
|
+
{ name:'ai_model', type:'string' },
|
|
35
|
+
{ name:'temperature', type:'number' },
|
|
36
|
+
{ name:'datasets', type:'string', isArray:true },
|
|
37
|
+
{ name:'joeUpdated', type:'string', format:'date-time' },
|
|
38
|
+
{ name:'created', type:'string', format:'date-time' }
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
menuicon:`<svg xmlns="http://www.w3.org/2000/svg" viewBox="-128 -128 1280 1280">
|
|
42
|
+
<path d="M356.52 692.84v31.84c0 11.07.47 17.51 1.4 19.31 1.19 2.44 3.42 4.2 6.07 4.8 4.53 1.05 9.18 1.49 13.83 1.31h8.55c9.29 0 13.93 2.98 13.93 8.94 0 6.89-4.9 11.11-14.71 12.66-12.05 1.35-24.18 1.91-36.31 1.66-14.75 0-25.19-2.86-31.32-8.58-6.13-5.72-9.21-15.51-9.23-29.36v-40.03c.42-5.59-.57-11.2-2.87-16.31-2.81-3.78-6.95-6.36-11.58-7.21-5.48-1.37-9.15-6.51-8.68-12.14-.53-5.64 3.17-10.81 8.68-12.14 4.65-.96 8.77-3.61 11.58-7.44 2.32-5.11 3.31-10.72 2.87-16.31v-39.93c0-13.64 3.07-23.32 9.2-29.04 6.13-5.72 16.57-8.57 31.32-8.55 12.9-.36 25.81.33 38.6 2.06 3.42.52 6.6 2.05 9.14 4.4 2.11 2.02 3.29 4.82 3.26 7.73 0 5.96-4.64 8.94-13.93 8.94h-8.81c-7.92 0-13.35.85-16.31 2.54-2.92 1.96-4.62 5.29-4.47 8.81v45.77c-.17 15.42-4.31 25.69-12.4 30.8-.64.43-1.02 1.16-1.01 1.92 0 1.2 1.45 2.99 4.34 5.38 3.23 2.94 5.58 6.73 6.79 10.93 1.58 5.6 2.28 11.41 2.09 17.23Zm90.28-100.23c16.42.07 29.72 13.37 29.79 29.79.25 8.33-3.05 16.37-9.07 22.12-11.82 11.24-30.37 11.24-42.18 0-6.02-5.75-9.32-13.79-9.07-22.12-.18-7.36 2.58-14.49 7.67-19.8 5.8-6.5 14.16-10.15 22.87-9.98Zm0 73.9c16.42.07 29.72 13.37 29.79 29.79.25 8.34-3.06 16.4-9.1 22.15-11.82 11.24-30.37 11.24-42.18 0-6.02-5.75-9.32-13.79-9.07-22.12-.18-7.36 2.58-14.49 7.67-19.8 5.8-6.52 14.17-10.18 22.9-10.02Zm89.36-40.03v-31.71c0-11.07-.47-17.51-1.4-19.31-1.19-2.44-3.42-4.2-6.07-4.8-4.53-1.05-9.18-1.49-13.83-1.31h-8.48c-9.29 0-13.93-2.98-13.93-8.94 0-6.89 4.9-11.07 14.71-12.53 12.05-1.35 24.18-1.9 36.31-1.66 14.75 0 25.19 2.86 31.32 8.58 6.13 5.72 9.2 15.4 9.2 29.04v40.13c-.44 5.59.55 11.2 2.87 16.31 2.84 3.76 6.96 6.35 11.58 7.28 5.51 1.34 9.2 6.53 8.65 12.17.37 4.53-1.99 8.85-6 10.99-2.02.92-4.11 1.65-6.26 2.19-4.2 1.33-7.58 4.48-9.2 8.58-1.34 4.52-1.9 9.23-1.66 13.93v40c0 13.72-3.07 23.44-9.2 29.13-6.13 5.7-16.57 8.56-31.32 8.58-12.9.36-25.81-.32-38.6-2.06-3.42-.52-6.6-2.05-9.14-4.4-2.13-2.06-3.31-4.9-3.26-7.86 0-5.96 4.64-8.94 13.93-8.94 1.11 0 4.05.09 8.81.26 5.55.28 11.11-.59 16.31-2.54 2.02-1.05 3.47-2.95 3.92-5.19.66-5.88.9-11.8.72-17.72v-31.84c-.25-6.36.68-12.71 2.74-18.73 2.07-4.82 5.46-8.96 9.79-11.94.64-.43 1.02-1.16 1.01-1.92 0-1.2-1.45-2.99-4.34-5.38-3.23-2.94-5.58-6.73-6.79-10.93-1.69-5.66-2.5-11.55-2.38-17.45Zm164.47-327.03 197.56 40.87-197.56 40.86-40.86 197.57-40.87-197.57-197.56-40.86 197.56-40.87 40.87-197.56 40.86 197.56z"/>
|
|
43
|
+
<path d="m516.05 158.53 81.14 16.79-81.14 16.78-16.78 81.15-16.79-81.15-81.14-16.78 81.14-16.79 16.79-81.14 16.78 81.14zm43.7 281.88 41.02 8.48-41.02 8.48-8.48 41.02-8.49-41.02-41.01-8.48 41.01-8.48 8.49-41.02 8.48 41.02z"/>
|
|
44
|
+
<path d="M698.87 563.96c16.22 26.17 25.29 55.26 25.29 85.9 0 117.09-105.49 205.38-245.39 205.38-3.01 0-6.03-.04-9.07-.12-13.15-.34-27.52-2.1-42.74-3.96-16.83-2.06-34.23-4.19-52.19-4.67l-8.81-.24-8.65 1.71-138.94 27.52 12.32-30.18 18.2-44.57-32.74-35.61c-22.03-23.96-48.3-63.4-48.3-115.27 0-113.76 124.78-206.3 278.15-206.3 10.26 0 20.38.43 30.35 1.23l-48.12-48.12C259.65 403.99 125.8 514.97 125.8 650.82c0 56.11 22.89 107.94 61.57 150.01l-59.5 145.77 252.16-49.95c26.34.7 55.86 6.99 85.42 7.76 3.35.09 6.69.13 10.01.13 171.44 0 290.73-115.81 290.73-253.72 0-42.53-13.14-82.62-36.34-117.86l-30.99 30.99Z"/>
|
|
45
|
+
</svg>`,
|
|
46
|
+
listView:{
|
|
47
|
+
title: function(aip){
|
|
48
|
+
return `
|
|
49
|
+
<joe-title>${aip.name}</joe-title>
|
|
50
|
+
<joe-subtitle>${aip.info}</joe-subtitle><br/>
|
|
51
|
+
|
|
52
|
+
<joe-subtext class="fright"><div><b>${aip.ai_model}</b></div>${aip.prompt_method}</joe-subtext>
|
|
53
|
+
<joe-subtext>${aip.content_items.map(i=>{
|
|
54
|
+
return `<b>${i.itemtype}</b>: ${i.reference}`;
|
|
55
|
+
}).join('')}</joe-subtext>
|
|
56
|
+
${_joe.schemas.tag.methods.renderTags(aip.tags,'fleft')}
|
|
57
|
+
`;
|
|
58
|
+
},
|
|
59
|
+
listWindowTitle: 'Ai Prompts'
|
|
60
|
+
},
|
|
61
|
+
subsets:function(i){
|
|
62
|
+
|
|
63
|
+
return _joe.Filter.Options.status();
|
|
64
|
+
},
|
|
65
|
+
filters:function(i){
|
|
66
|
+
|
|
67
|
+
return _joe.Filter.Options.tags();
|
|
68
|
+
},
|
|
69
|
+
stripeColor: function(item) {
|
|
70
|
+
//use the stripe color from ai_assistant status object if it has one
|
|
71
|
+
if (item.status){
|
|
72
|
+
var status = _joe.Cache.get(item.status);
|
|
73
|
+
if (status && status.color) {
|
|
74
|
+
return {color:status.color,title:status.name};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
onload:function(dataset){
|
|
79
|
+
//replace the blank instructions field with the populated template field && the blank instrctions format field with the populated template type field
|
|
80
|
+
dataset.map(function(item){
|
|
81
|
+
if(item.template){
|
|
82
|
+
item.instructions = item.template;
|
|
83
|
+
delete item.template;
|
|
84
|
+
}
|
|
85
|
+
if(item.template_type){
|
|
86
|
+
item.instructions_format = item.template_type;
|
|
87
|
+
delete item.template_type;
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
},
|
|
91
|
+
fields:[
|
|
92
|
+
'name',
|
|
93
|
+
'info',
|
|
94
|
+
{name:"prompt_method",placeholder:"name of method to call in plugin", comment:'use executeJOEAiPrompt to use the JOE ui here for all smarts', default:"executeJOEAiPrompt",display:"Prompt Plugin Method",type:'text'},
|
|
95
|
+
{name:'content_items',type:'objectList',
|
|
96
|
+
properties:['itemtype','reference']
|
|
97
|
+
},
|
|
98
|
+
{section_start:'Input'},
|
|
99
|
+
{name: 'functions', type: 'code', display: 'Helper Functions', language:'javascript',comment: `
|
|
100
|
+
<div>AI Prompt Helper Function
|
|
101
|
+
|
|
102
|
+
<h4>Usage:</h4>
|
|
103
|
+
<ul>
|
|
104
|
+
<li>Must export an async function.</li>
|
|
105
|
+
<li>Receives: { instructions, params, ai_prompt } as a single argument.</li>
|
|
106
|
+
<li>Must return a final modified instructions string.</li>
|
|
107
|
+
</ul>
|
|
108
|
+
|
|
109
|
+
<h4>Example:</h4>
|
|
110
|
+
<div class="pad10">
|
|
111
|
+
<pre>
|
|
112
|
+
module.exports = async function({ instructions, params, ai_prompt })
|
|
113
|
+
// Your code here to modify the instructions based off params
|
|
114
|
+
const object = $J.get(params.idToLookup);
|
|
115
|
+
|
|
116
|
+
trackObject(params.idToLookup); // Tell parent we used this
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
instructions: "Updated system-level instructions string",
|
|
120
|
+
input: "Specific input text (URL, query, etc)"
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
};
|
|
124
|
+
</pre>
|
|
125
|
+
</div>
|
|
126
|
+
</div>`},
|
|
127
|
+
{section_end:'Input'},
|
|
128
|
+
{section_start:'Instruct'},
|
|
129
|
+
{label:'Instructions'},
|
|
130
|
+
"instructions_format",
|
|
131
|
+
"instructions",
|
|
132
|
+
{name:"user_prompt",display:'User Prompt',type:'rendering',comment:'speciific input to the prompt if any, such as campaign intent'},
|
|
133
|
+
|
|
134
|
+
// 'template_type',
|
|
135
|
+
// {extend:'template',specs:{comment:'legacy field, use instructions instead',
|
|
136
|
+
// // comment:`<div>use $\\{this.AI_PROMPT.name\\} $\\{this.CONTENT\\} <br/></div><div>for <b>module</b>: export function(data) that returns an html string.
|
|
137
|
+
// // data.request, data.REPORT,
|
|
138
|
+
// // <br/>shorthand: $J.get(itemid) $J.schema(schemaname)</div>`,
|
|
139
|
+
// language:function(item){
|
|
140
|
+
// switch(item.template_type){
|
|
141
|
+
// case 'module':
|
|
142
|
+
// return 'javascript';
|
|
143
|
+
// break;
|
|
144
|
+
// default:
|
|
145
|
+
// return '';
|
|
146
|
+
// }
|
|
147
|
+
|
|
148
|
+
// }
|
|
149
|
+
// }},
|
|
150
|
+
{section_end:'Instruct'},
|
|
151
|
+
|
|
152
|
+
{section_start:'system',collapsed:true},
|
|
153
|
+
'_id','created','itemtype',
|
|
154
|
+
{section_end:'system'},
|
|
155
|
+
{sidebar_start:'right',collapsed:true},
|
|
156
|
+
{section_start:'workflow'},
|
|
157
|
+
'status',
|
|
158
|
+
'tags',
|
|
159
|
+
// {name:'merge_status',comment:'status to add when this data is merged in', allowMultiple:false,type:"objectReference",display:'Merge Status',values:function(){
|
|
160
|
+
// return _joe.getDataset('status');
|
|
161
|
+
// }},
|
|
162
|
+
{section_end:'workflow'},
|
|
163
|
+
{section_start:'openAi',collapsed:true},
|
|
164
|
+
'ai_model',
|
|
165
|
+
{name:'temperature', type:'number',display:'Temperature', default:.7, step:"0.1",comment:'0-1, 0 is deterministic, 1 is random'},
|
|
166
|
+
//{name:'max_tokens', type:'number',display:'Max Tokens',comment:'max tokens to return',default:4096},
|
|
167
|
+
{section_end:'openAi'},
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
{section_start:'examples',collapsed:true},
|
|
171
|
+
{name:'examples', display:'prompt examples', comment:'runs the prompt to create a response',type:'content', reloadable:true,run:function(item){
|
|
172
|
+
return $J.schema('ai_prompt').methods.listExamples(item);
|
|
173
|
+
} },
|
|
174
|
+
{section_end:'examples'},
|
|
175
|
+
|
|
176
|
+
{sidebar_end:'right'},
|
|
177
|
+
{sidebar_start:'left',collapsed:function(aip){
|
|
178
|
+
return aip.datasets.length != 0;
|
|
179
|
+
}},
|
|
180
|
+
{section_start:'categorization',collapsed:false},
|
|
181
|
+
'datasets',
|
|
182
|
+
{section_end:'categorization'},
|
|
183
|
+
{sidebar_end:'left'},
|
|
184
|
+
],
|
|
185
|
+
idprop : "_id",
|
|
186
|
+
sorter:['name','!joeUpdated'],
|
|
187
|
+
methods:{
|
|
188
|
+
buildURL: function(prompt, items = []) {
|
|
189
|
+
const method = prompt.prompt_method || '';
|
|
190
|
+
let url = `/API/plugin/chatgpt/${method}?ai_prompt=${prompt._id}`;
|
|
191
|
+
|
|
192
|
+
if (!Array.isArray(items)) {
|
|
193
|
+
console.warn('Expected items to be an array.');
|
|
194
|
+
return url;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (prompt.content_items) {
|
|
198
|
+
prompt.content_items.forEach(ci => {
|
|
199
|
+
const matchingItem = items.find(it => it.itemtype === ci.itemtype );
|
|
200
|
+
if (matchingItem) {
|
|
201
|
+
url += `&${ci.reference}=${matchingItem._id}`;
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return url;
|
|
207
|
+
},
|
|
208
|
+
// listItemClickHandler:function(itemid,promptid){
|
|
209
|
+
// var item = $J.get(itemid);
|
|
210
|
+
// var prompt;
|
|
211
|
+
// if(promptid){
|
|
212
|
+
// prompt = $J.get(promptid);
|
|
213
|
+
// }else{
|
|
214
|
+
// prompt = _jco();
|
|
215
|
+
// }
|
|
216
|
+
// window.open(this.buildURL(prompt,[item]));
|
|
217
|
+
// },
|
|
218
|
+
listItemClickHandler: function (itemMap, promptId) {
|
|
219
|
+
const prompt = promptId ? $J.get(promptId,'ai_prompt') : _jco();
|
|
220
|
+
const items = [];
|
|
221
|
+
|
|
222
|
+
for (const [itemtype, id] of Object.entries(itemMap)) {
|
|
223
|
+
const obj = $J.get(id,itemtype);
|
|
224
|
+
if (obj) {
|
|
225
|
+
items.push(obj);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
window.open(this.buildURL(prompt, items));
|
|
230
|
+
},
|
|
231
|
+
listExamples:function(prompt){
|
|
232
|
+
var examples = [];
|
|
233
|
+
var html ='';
|
|
234
|
+
var ref0;
|
|
235
|
+
var it0;
|
|
236
|
+
if(!prompt.content_items){
|
|
237
|
+
return 'select content items to send with this prompt';
|
|
238
|
+
}
|
|
239
|
+
prompt.content_items.map(function(ci){
|
|
240
|
+
if(_joe.Data[ci.itemtype]){
|
|
241
|
+
examples = examples.concat(_joe.Data[ci.itemtype]);
|
|
242
|
+
it0 = ci.itemtype;
|
|
243
|
+
ref0 = ci.reference;
|
|
244
|
+
}
|
|
245
|
+
})
|
|
246
|
+
var finalExamples = [];
|
|
247
|
+
|
|
248
|
+
while(finalExamples.length < 5 && finalExamples.length < examples.length){
|
|
249
|
+
let ci = examples[Math.floor(Math.random()*examples.length)];
|
|
250
|
+
if(finalExamples.indexOf(ci) == -1){
|
|
251
|
+
finalExamples.push(ci);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
var rep_url;
|
|
255
|
+
var method =
|
|
256
|
+
finalExamples.map(function(ex){
|
|
257
|
+
//rep_url = '/API/plugin/chatgpt'+'?ai_prompt='+prompt._id+'&'+ref0+'='+ex._id;
|
|
258
|
+
html += _joe.renderFieldListItem(ex,
|
|
259
|
+
'<joe-subtext>'+it0+'</joe-subtext>'+
|
|
260
|
+
'<joe-title>${name} ${date}</joe-title>\
|
|
261
|
+
<joe-subtext>${website}</joe-subtext>',
|
|
262
|
+
it0,
|
|
263
|
+
{
|
|
264
|
+
//action:'onclick="window.open(\''+rep_url+'\');"',
|
|
265
|
+
action:`onclick="_joe.schemas.ai_prompt.methods.listItemClickHandler('${ex._id}');"`,
|
|
266
|
+
icon:'ai_prompt'
|
|
267
|
+
}
|
|
268
|
+
);
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
return html;
|
|
272
|
+
},
|
|
273
|
+
listPrompts: function (objectMap) {
|
|
274
|
+
if (!objectMap || typeof objectMap !== 'object') return '';
|
|
275
|
+
|
|
276
|
+
const activeStatuses = _joe.getDataset('status')
|
|
277
|
+
.filter(f => f.datasets.includes('ai_prompt') && f.active)
|
|
278
|
+
.map(f => f._id);
|
|
279
|
+
|
|
280
|
+
const prompts = _joe.getDataset('ai_prompt').filter(prompt =>
|
|
281
|
+
activeStatuses.includes(prompt.status)
|
|
282
|
+
);
|
|
283
|
+
|
|
284
|
+
const context_items = {}
|
|
285
|
+
// Inline helper: reduce objects to { itemtype: _id }
|
|
286
|
+
const extractIds = map => {
|
|
287
|
+
const idMap = {};
|
|
288
|
+
for (const [type, obj] of Object.entries(map)) {
|
|
289
|
+
if (obj && obj._id) idMap[type] = obj._id;
|
|
290
|
+
}
|
|
291
|
+
return idMap;
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
const objectIdMap = extractIds(objectMap);
|
|
295
|
+
const paramStr = JSON.stringify(objectIdMap).replace(/"/g, '"');
|
|
296
|
+
|
|
297
|
+
let html = '';
|
|
298
|
+
const temp = '<joe-title>${name}</joe-title>';
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
let itemtype = _joe.current.object.itemtype;
|
|
302
|
+
const matchingPrompts = prompts.filter(prompt =>
|
|
303
|
+
(prompt.content_items || []).some(ci => ci.itemtype === itemtype)
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
matchingPrompts.forEach(prompt => {
|
|
307
|
+
html += _joe.renderFieldListItem(prompt, temp, 'ai_prompt', {
|
|
308
|
+
icon: 'ai_prompt',
|
|
309
|
+
action: `onclick="(function(){ _joe.schemas.ai_prompt.methods.listItemClickHandler(${paramStr}, '${prompt._id}'); })()"`
|
|
310
|
+
|
|
311
|
+
//action: `onclick="_joe.schemas.ai_prompt.methods.listItemClickHandler(${paramStr}, "${prompt._id}");"`
|
|
312
|
+
});
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
return html;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
module.exports = schema;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
var schema = {
|
|
2
|
+
title : 'Ai Response | ${name}',
|
|
3
|
+
info:"An ai response from openai etc",
|
|
4
|
+
summary:{
|
|
5
|
+
description:'Stored AI response objects generated from ai_prompt and the chatgpt plugin.',
|
|
6
|
+
purpose:'Use ai_response to persist responses, token usage, and referenced objects from OpenAI calls for auditing, reuse, and comparison back to JOE objects.',
|
|
7
|
+
labelField:'name',
|
|
8
|
+
defaultSort:{ field:'created', dir:'desc' },
|
|
9
|
+
searchableFields:['name','prompt_method','model_used','response_type','response_id','tags','_id'],
|
|
10
|
+
allowedSorts:['created','joeUpdated','name','model_used'],
|
|
11
|
+
relationships:{
|
|
12
|
+
outbound:[
|
|
13
|
+
{ field:'ai_prompt', targetSchema:'ai_prompt', cardinality:'one' },
|
|
14
|
+
{ field:'referenced_objects', targetSchema:'<schemaName>', cardinality:'many' },
|
|
15
|
+
{ field:'tags', targetSchema:'tag', cardinality:'many' }
|
|
16
|
+
],
|
|
17
|
+
inbound:{ graphRef:'server/relationships.graph.json' }
|
|
18
|
+
},
|
|
19
|
+
joeManagedFields:['created','joeUpdated'],
|
|
20
|
+
fields:[
|
|
21
|
+
{ name:'_id', type:'string', required:true },
|
|
22
|
+
{ name:'itemtype', type:'string', required:true, const:'ai_response' },
|
|
23
|
+
{ name:'name', type:'string', required:true },
|
|
24
|
+
{ name:'ai_prompt', type:'string', isReference:true, targetSchema:'ai_prompt' },
|
|
25
|
+
{ name:'referenced_objects', type:'string', isArray:true },
|
|
26
|
+
{ name:'user_prompt', type:'string' },
|
|
27
|
+
{ name:'prompt_method', type:'string' },
|
|
28
|
+
{ name:'model_used', type:'string' },
|
|
29
|
+
{ name:'response_type', type:'string' },
|
|
30
|
+
{ name:'response', type:'string' },
|
|
31
|
+
{ name:'response_keys', type:'string', isArray:true },
|
|
32
|
+
{ name:'response_id', type:'string' },
|
|
33
|
+
{ name:'usage', type:'object' },
|
|
34
|
+
{ name:'tags', type:'string', isArray:true, isReference:true, targetSchema:'tag' },
|
|
35
|
+
{ name:'joeUpdated', type:'string', format:'date-time' },
|
|
36
|
+
{ name:'created', type:'string', format:'date-time' }
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
menuicon:`
|
|
40
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-150 -150 1324 1324">
|
|
41
|
+
<path d="M314.57 597.81h376.06v28.2H314.57zm0 75.21h376.06v28.2H314.57zm0 75.21h376.06v28.2H314.57zm239.99-498.47 151.31 31.3c12.23 2.53 12.23 20 0 22.53l-151.31 31.3-31.3 151.31c-2.53 12.23-20 12.23-22.53 0l-31.3-151.31-151.31-31.3c-12.23-2.53-12.23-20 0-22.53l151.31-31.3 31.3-151.31c2.53-12.23 20-12.23 22.53 0l31.3 151.31ZM388.55 102.88l65.55 13.56c5.3 1.1 5.3 8.66 0 9.76l-65.55 13.56-13.56 65.55c-1.1 5.3-8.66 5.3-9.76 0l-13.56-65.55-65.55-13.56c-5.3-1.1-5.3-8.66 0-9.76l65.55-13.56 13.56-65.55c1.1-5.3 8.66-5.3 9.76 0l13.56 65.55Zm20.9 365.17 63.07 13.04c5.1 1.05 5.1 8.33 0 9.39l-63.07 13.04-13.04 63.07c-1.05 5.1-8.33 5.1-9.39 0l-13.04-63.07-63.07-13.04c-5.1-1.05-5.1-8.33 0-9.39l63.07-13.04 13.04-63.07c1.05-5.1 8.33-5.1 9.39 0l13.04 63.07Z"/>
|
|
42
|
+
<path d="M689 155.94v37.61h67.44v676.9H267.56v-676.9H319v-37.61h-89.04v752.12h564.08V155.94H689z"/>
|
|
43
|
+
</svg>`,
|
|
44
|
+
listView:{
|
|
45
|
+
title: function(air){
|
|
46
|
+
var html = `<joe-subtext class="fright">${_joe.Utils.prettyPrintDTS(air.created)}</joe-subtext>
|
|
47
|
+
<joe-title>${air.name}</joe-title>
|
|
48
|
+
<joe-subtitle>${(air.response_keys?.length && `returns <b>${air.response_keys}</b>`) ||''}</joe-subtitle>
|
|
49
|
+
${air.prompt_method?`<joe-subtext class="fright">method ${air.prompt_method}</joe-subtext>`:''}
|
|
50
|
+
<div>${(air.referenced_objects||[]).map(function(ref){
|
|
51
|
+
var obj = $J.get(ref);
|
|
52
|
+
if(obj){
|
|
53
|
+
return `<joe-subtext>${obj.itemtype}:<b>${obj.name}</b> - ${obj._id}</joe-subtext>`;
|
|
54
|
+
}else{
|
|
55
|
+
return `<joe-subtext>${ref}</joe-subtext>`;
|
|
56
|
+
}
|
|
57
|
+
}).join('')}</div>`;
|
|
58
|
+
air.tags?.length && (html+=_joe.schemas.tag.methods.renderTags(air.tags,'fright'));
|
|
59
|
+
return html;
|
|
60
|
+
},
|
|
61
|
+
listWindowTitle: 'Ai Responses'
|
|
62
|
+
},
|
|
63
|
+
subsets: function(){
|
|
64
|
+
return _joe.Filter.Options.tags({group:true,collapsed:false}).concat(_joe.getDataset('ai_prompt').map(prompt => {
|
|
65
|
+
var color = prompt.status && $J.get(prompt.status,'status').color;
|
|
66
|
+
return {
|
|
67
|
+
name: prompt.name,
|
|
68
|
+
id: prompt._id,
|
|
69
|
+
filter: { ai_prompt: prompt._id },
|
|
70
|
+
stripecolor: color || null // optional
|
|
71
|
+
};
|
|
72
|
+
}))
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
sorter:['!created','name'],
|
|
76
|
+
checkChanges:false,
|
|
77
|
+
fields:[
|
|
78
|
+
'name',
|
|
79
|
+
//'info',
|
|
80
|
+
{name:'ai_prompt',type:'objectReference', values:'ai_prompt',display:'Ai Prompt',width:'50%',locked:true},
|
|
81
|
+
{name:'referenced_objects',type:'objectReference',width:'50%',values:function(air,orList){
|
|
82
|
+
return $J.search({_id:{$in:air.referenced_objects}});
|
|
83
|
+
},display:'Referenced Objects',locked:true},
|
|
84
|
+
{name:'user_prompt', display:'Sent User Prompt',comment:"The input sent by the user after all processing",locked:true,type:'rendering'},
|
|
85
|
+
|
|
86
|
+
{name:'prompt_method',locked:true,width:'50%'},
|
|
87
|
+
{name:'model_used',locked:true,width:'50%'},
|
|
88
|
+
|
|
89
|
+
// {name:'ai_prompt',type:'select', values:'ai_prompt',display:'Ai Prompt',width:'50%',template:function(resp,prompt){
|
|
90
|
+
// return prompt.name;
|
|
91
|
+
// }},
|
|
92
|
+
//{name:'business',type:'objectReference', values:'business',display:'Business',locked:true},
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
//{name:'params', type:'rendering', locked:true},
|
|
96
|
+
{section_start:'response',collapsed:false},
|
|
97
|
+
{name:'response_type',type:'text',display:'Response Type',
|
|
98
|
+
placeholder:'(a code for the responsetype)',locked:true,width:'50%',condition:function(v){
|
|
99
|
+
return v.length > 0;
|
|
100
|
+
}},
|
|
101
|
+
|
|
102
|
+
{name:'response', type:'rendering', locked:true,height:'500px'},
|
|
103
|
+
{name:'response_keys', type:'text', locked:true,display:'Response Keys'},
|
|
104
|
+
{name:'response_id', type:'text', display:'openAI response ID',locked:true},
|
|
105
|
+
{section_end:'response'},
|
|
106
|
+
{sidebar_start:'right', collapsed:false},
|
|
107
|
+
{section_start:'workflow'},
|
|
108
|
+
'tags',
|
|
109
|
+
{section_end:'workflow'},
|
|
110
|
+
{section_start:'tokens'},
|
|
111
|
+
{name:'usage',type:'content',display:'Tokens Used',run:function(air){
|
|
112
|
+
if(!air.usage || !air.usage.total_tokens){return '';}
|
|
113
|
+
var html=`<joe-text>input <b>${air.usage.input_tokens}</b></joe-text>
|
|
114
|
+
<joe-text>output <b>${air.usage.output_tokens}</b></joe-text>
|
|
115
|
+
<joe-text>total <b>${air.usage.total_tokens}</b></joe-text>`
|
|
116
|
+
return html;
|
|
117
|
+
}},
|
|
118
|
+
{section_end:'tokens'},
|
|
119
|
+
{sidebar_end:'right'},
|
|
120
|
+
//{name:'payload', type:'code', locked:true,height:'500px'},
|
|
121
|
+
//{name:'raw_response', type:'code', language:'json',locked:true},
|
|
122
|
+
{section_start:'system',collapsed:true},
|
|
123
|
+
'_id','created','itemtype',
|
|
124
|
+
{section_end:'system'},
|
|
125
|
+
|
|
126
|
+
],
|
|
127
|
+
methods:{
|
|
128
|
+
compareResponseToObject:function(response_id,object_id,do_alert){
|
|
129
|
+
let response =$J.get(response_id);
|
|
130
|
+
var object;
|
|
131
|
+
let object_keys;
|
|
132
|
+
if(_joe.current.object._id == object_id){
|
|
133
|
+
object = _jco(true);
|
|
134
|
+
object_keys = _joe.current.fields.map(f=>f.name)
|
|
135
|
+
}
|
|
136
|
+
else{
|
|
137
|
+
object = $J.get(object_id);
|
|
138
|
+
object_keys = Object.keys(object);
|
|
139
|
+
}
|
|
140
|
+
if(!response || !object){return false;}
|
|
141
|
+
//evaluate the response to see if it is valid json
|
|
142
|
+
try{
|
|
143
|
+
let parsed = JSON.parse(response.response);
|
|
144
|
+
//find the keys in the response that are in the object
|
|
145
|
+
let keys = Object.keys(parsed);
|
|
146
|
+
|
|
147
|
+
let match = keys.filter(k=>object_keys.includes(k));
|
|
148
|
+
//if there are no keys that match, return false
|
|
149
|
+
if(!match.length){
|
|
150
|
+
do_alert && alert('Response does not match any object keys: '+keys.join(','));
|
|
151
|
+
return false;}
|
|
152
|
+
//return an array of matching keys
|
|
153
|
+
do_alert && ( doit = confirm('Replace object values with responses for: '+match.join(',')));
|
|
154
|
+
if(doit){
|
|
155
|
+
_joe.schemas.ai_response.methods.updateObjectFromResponse(response_id,object_id,match);
|
|
156
|
+
}
|
|
157
|
+
return match;
|
|
158
|
+
}catch(e){
|
|
159
|
+
//if the response is not valid json, return false
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
updateObjectFromResponse:function(response_id,object_id,fields){
|
|
164
|
+
let response =$J.get(response_id);
|
|
165
|
+
let parsed = JSON.parse(response.response);
|
|
166
|
+
var object;
|
|
167
|
+
if(_joe.current.object._id == object_id){
|
|
168
|
+
object = _jco(true);
|
|
169
|
+
}
|
|
170
|
+
else{
|
|
171
|
+
object = $J.get(object_id);
|
|
172
|
+
}
|
|
173
|
+
//handle tags
|
|
174
|
+
if(response.tags && response.tags.length){
|
|
175
|
+
let newTags = (object.tags||[]).concat(response.tags);
|
|
176
|
+
//tags array to a set, then back to array
|
|
177
|
+
newTags = [...new Set(newTags)];
|
|
178
|
+
_joe.Fields.set('tags',newTags);
|
|
179
|
+
|
|
180
|
+
}
|
|
181
|
+
fields.map(function(field){
|
|
182
|
+
let newVal = object[field];
|
|
183
|
+
//update the object with the response
|
|
184
|
+
if(object[field].isArray()){
|
|
185
|
+
//append the response to the array
|
|
186
|
+
newVal = object[field].concat(parsed[field]);
|
|
187
|
+
}else if(typeof object[field] == 'string'){
|
|
188
|
+
//merge the response with the object
|
|
189
|
+
newVal = parsed[field]
|
|
190
|
+
}
|
|
191
|
+
_joe.Fields.set(field,newVal);
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
listResponses:function(obj){
|
|
195
|
+
let html ='';
|
|
196
|
+
let responses = _joe.getDataset('ai_response').filter(r=>{
|
|
197
|
+
return r.referenced_objects && r.referenced_objects.includes(obj._id);
|
|
198
|
+
})
|
|
199
|
+
$c.sortBy(responses,'!created');
|
|
200
|
+
|
|
201
|
+
responses.map(resp=>{
|
|
202
|
+
let temp = `<joe-subtitle>${resp.name}</joe-subtitle>
|
|
203
|
+
<joe-subtext>${_joe.Utils.prettyPrintDTS(resp.created)}</joe-subtext>
|
|
204
|
+
${resp.tags && _joe.schemas.tag.methods.renderTags(resp.tags) || ''}`;
|
|
205
|
+
|
|
206
|
+
resp.response_keys && (temp += `<joe-button-wrapper class="bottom"><joe-button class="joe-button joe-blue-button" onclick="_joe.Utils.stopPropagation(event);_joe.schemas.ai_response.methods.compareResponseToObject('${resp._id}','${obj._id}',true);">< merge ${resp.response_keys.length} fields</joe-button><joe-button-wrapper>`);
|
|
207
|
+
html+=_joe.renderFieldListItem(resp,temp,'ai_response',{icon:'ai_assistant',link:function(item){
|
|
208
|
+
return location.href.replace(location.hash,`#/${item.itemtype}/${item._id}`);
|
|
209
|
+
}});
|
|
210
|
+
})
|
|
211
|
+
return html;
|
|
212
|
+
}
|
|
213
|
+
},
|
|
214
|
+
idprop : "_id"
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
module.exports = schema;
|
|
@@ -6,6 +6,36 @@ var schema = {
|
|
|
6
6
|
title: "Ai Tool | ${name}",
|
|
7
7
|
display: "Ai Tool",
|
|
8
8
|
info: "Reusable Ai tool function for OpenAI tool calling and local execution.",
|
|
9
|
+
summary:{
|
|
10
|
+
description:'Definition of a reusable AI tool (function) that can be called by OpenAI assistants or prompts.',
|
|
11
|
+
purpose:'Use ai_tool to describe function-calling tools (name, parameters) and optional server-side execution code that JOE can invoke when OpenAI calls the tool.',
|
|
12
|
+
labelField:'name',
|
|
13
|
+
defaultSort:{ field:'name', dir:'asc' },
|
|
14
|
+
searchableFields:['name','info','description','tool_id','datasets','tags'],
|
|
15
|
+
allowedSorts:['name','joeUpdated','created'],
|
|
16
|
+
relationships:{
|
|
17
|
+
outbound:[
|
|
18
|
+
{ field:'datasets', targetSchema:'<schemaName>', cardinality:'many' },
|
|
19
|
+
{ field:'tags', targetSchema:'tag', cardinality:'many' }
|
|
20
|
+
],
|
|
21
|
+
inbound:{ graphRef:'server/relationships.graph.json' }
|
|
22
|
+
},
|
|
23
|
+
joeManagedFields:['created','joeUpdated'],
|
|
24
|
+
fields:[
|
|
25
|
+
{ name:'_id', type:'string', required:true },
|
|
26
|
+
{ name:'itemtype', type:'string', required:true, const:'ai_tool' },
|
|
27
|
+
{ name:'name', type:'string', required:true },
|
|
28
|
+
{ name:'info', type:'string' },
|
|
29
|
+
{ name:'description', type:'string' },
|
|
30
|
+
{ name:'tool_id', type:'string' },
|
|
31
|
+
{ name:'tool_properties', type:'string' },
|
|
32
|
+
{ name:'server_code', type:'string' },
|
|
33
|
+
{ name:'tags', type:'string', isArray:true, isReference:true, targetSchema:'tag' },
|
|
34
|
+
{ name:'datasets', type:'string', isArray:true },
|
|
35
|
+
{ name:'joeUpdated', type:'string', format:'date-time' },
|
|
36
|
+
{ name:'created', type:'string', format:'date-time' }
|
|
37
|
+
]
|
|
38
|
+
},
|
|
9
39
|
//menuicon: `<svg viewBox="0 0 24 24"><path d="M3 6h18M3 12h18M3 18h18"/></svg>`,
|
|
10
40
|
|
|
11
41
|
listView: {
|