json-object-editor 0.10.610 → 0.10.623

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.
@@ -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: {
@@ -0,0 +1,110 @@
1
+ var schema = {
2
+ title: "AI Widget Conversation | ${name||_id}",
3
+ display: "AI Widget Conversation",
4
+ info: "Lightweight conversation log for external AI widgets.",
5
+ summary:{
6
+ description:'Lightweight, persistent conversation record for embeddable AI widgets.',
7
+ purpose:'Use ai_widget_conversation to store model choice, assistant linkage, system instructions, and a compact message array for widget chats. Widgets read/write this schema via the chatgpt widgetStart/widgetMessage/widgetHistory endpoints.',
8
+ wip:true,
9
+ labelField:'name',
10
+ defaultSort:{ field:'last_message_at', dir:'desc' },
11
+ searchableFields:['name','info','model','assistant_id','source','_id'],
12
+ allowedSorts:['last_message_at','created','joeUpdated','name'],
13
+ relationships:{
14
+ outbound:[
15
+ { field:'assistant', targetSchema:'ai_assistant', cardinality:'one' },
16
+ { field:'tags', targetSchema:'tag', 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_widget_conversation' },
24
+ { name:'name', type:'string' },
25
+ { name:'info', type:'string' },
26
+ { name:'model', type:'string' },
27
+ { name:'assistant', type:'string', isReference:true, targetSchema:'ai_assistant' },
28
+ { name:'assistant_id', type:'string' },
29
+ { name:'system', type:'string' },
30
+ { name:'messages', type:'objectList' },
31
+ { name:'last_message_at', type:'string', format:'date-time' },
32
+ { name:'source', type:'string' },
33
+ { name:'tags', type:'string', isArray:true, isReference:true, targetSchema:'tag' },
34
+ { name:'joeUpdated', type:'string', format:'date-time' },
35
+ { name:'created', type:'string', format:'date-time' }
36
+ ]
37
+ },
38
+ listView: {
39
+ title: "<joe-title>${name||_id}</joe-title><joe-subtitle>${model}</joe-subtitle><joe-subtext>${last_message_at}</joe-subtext>",
40
+ listWindowTitle: "AI Widget Conversations"
41
+ },
42
+ fields: function () {
43
+ return [
44
+ "name",
45
+ "info",
46
+
47
+ { section_start: "conversation", display: "Conversation", collapsed: false },
48
+ {
49
+ name: "model",
50
+ type: "select",
51
+ values: "ai_model",
52
+ display: "Model",
53
+ comment: "Default OpenAI model used for this conversation."
54
+ },
55
+ {
56
+ name: "assistant",
57
+ type: "objectReference",
58
+ values: "ai_assistant",
59
+ display: "Assistant (JOE)",
60
+ comment: "Optional link to an ai_assistant config used by this widget."
61
+ },
62
+ {
63
+ name: "assistant_id",
64
+ type: "text",
65
+ display: "OpenAI Assistant ID",
66
+ comment: "Optional OpenAI assistant used for this conversation."
67
+ },
68
+ {
69
+ name: "system",
70
+ type: "code",
71
+ display: "System Instructions",
72
+ height: "160px",
73
+ comment: "Effective system prompt used for this conversation."
74
+ },
75
+ {
76
+ name: "messages",
77
+ type: "code",
78
+ display: "Messages (JSON)",
79
+ height: "260px",
80
+ comment: "Array of {role, content, created_at}. Managed by the widget API."
81
+ },
82
+ {
83
+ name: "last_message_at",
84
+ type: "date",
85
+ display: "Last Message At",
86
+ locked: true
87
+ },
88
+ { section_end: "conversation" },
89
+
90
+ { section_start: "meta", collapsed: true },
91
+ "source",
92
+ "tags",
93
+ { section_end: "meta" },
94
+
95
+ { section_start: "system", collapsed: true },
96
+ "_id",
97
+ "created",
98
+ "joeUpdated",
99
+ "itemtype",
100
+ { section_end: "system" }
101
+ ];
102
+ },
103
+
104
+ idprop: "_id",
105
+ sorter: ["!last_message_at", "!created"]
106
+ };
107
+
108
+ module.exports = schema;
109
+
110
+