json-object-editor 0.10.633 → 0.10.636
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 +4 -0
- package/css/joe-styles.css +6 -2
- package/css/joe.css +6 -3
- package/css/joe.min.css +1 -1
- package/docs/JOE_AI_Overview.md +330 -0
- package/js/JsonObjectEditor.jquery.craydent.js +8 -2
- package/js/joe-ai.js +9 -4
- package/js/joe.js +9 -3
- package/js/joe.min.js +1 -1
- package/package.json +1 -1
- package/server/plugins/chatgpt.js +36 -11
- package/server/schemas/form.js +10 -7
- package/server/schemas/question.js +19 -2
package/package.json
CHANGED
|
@@ -580,16 +580,21 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
|
|
|
580
580
|
}
|
|
581
581
|
|
|
582
582
|
// Normalize model output that should contain JSON. Models often wrap JSON
|
|
583
|
-
// in markdown fences (```json ... ```)
|
|
584
|
-
//
|
|
583
|
+
// in markdown fences (```json ... ```), and may prepend/append prose. This
|
|
584
|
+
// helper strips fences and tries to isolate the first well-formed JSON
|
|
585
|
+
// object/array substring so JSON.parse has the best chance of succeeding.
|
|
585
586
|
function extractJsonText(raw) {
|
|
586
587
|
if (!raw) { return ''; }
|
|
587
588
|
let t = String(raw).trim();
|
|
588
|
-
//
|
|
589
|
-
|
|
590
|
-
|
|
589
|
+
// If there is any ```...``` fenced block, prefer its contents.
|
|
590
|
+
const fenceIdx = t.indexOf('```json') !== -1 ? t.indexOf('```json') : t.indexOf('```');
|
|
591
|
+
if (fenceIdx !== -1) {
|
|
592
|
+
let start = fenceIdx;
|
|
593
|
+
const firstNewline = t.indexOf('\n', start);
|
|
591
594
|
if (firstNewline !== -1) {
|
|
592
595
|
t = t.substring(firstNewline + 1);
|
|
596
|
+
} else {
|
|
597
|
+
t = t.substring(start + 3);
|
|
593
598
|
}
|
|
594
599
|
const lastFence = t.lastIndexOf('```');
|
|
595
600
|
if (lastFence !== -1) {
|
|
@@ -597,12 +602,17 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
|
|
|
597
602
|
}
|
|
598
603
|
t = t.trim();
|
|
599
604
|
}
|
|
600
|
-
// If there's extra prose around the JSON, slice from first { to last }
|
|
601
|
-
if (t[0] !== '{') {
|
|
605
|
+
// If there's extra prose around the JSON, slice from first {/[ to last }/]
|
|
606
|
+
if (t[0] !== '{' && t[0] !== '[') {
|
|
602
607
|
const firstBrace = t.indexOf('{');
|
|
603
|
-
const
|
|
604
|
-
|
|
605
|
-
|
|
608
|
+
const firstBracket = t.indexOf('[');
|
|
609
|
+
let first = -1;
|
|
610
|
+
if (firstBrace === -1) { first = firstBracket; }
|
|
611
|
+
else if (firstBracket === -1) { first = firstBrace; }
|
|
612
|
+
else { first = Math.min(firstBrace, firstBracket); }
|
|
613
|
+
const lastBrace = Math.max(t.lastIndexOf('}'), t.lastIndexOf(']'));
|
|
614
|
+
if (first !== -1 && lastBrace !== -1 && lastBrace > first) {
|
|
615
|
+
t = t.slice(first, lastBrace + 1);
|
|
606
616
|
}
|
|
607
617
|
}
|
|
608
618
|
return t.trim();
|
|
@@ -656,7 +666,7 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
|
|
|
656
666
|
}, null, ' ');
|
|
657
667
|
|
|
658
668
|
const openai = newClient();
|
|
659
|
-
const model = body.model || 'gpt-4o-mini';
|
|
669
|
+
const model = body.model || 'gpt-4o-mini';////'gpt-5-nano';
|
|
660
670
|
|
|
661
671
|
// For simplicity and robustness, use plain text output and instruct the
|
|
662
672
|
// model to return a strict JSON object. We previously attempted the
|
|
@@ -667,6 +677,14 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
|
|
|
667
677
|
instructions: systemText,
|
|
668
678
|
input: userInput
|
|
669
679
|
};
|
|
680
|
+
// Optional web_search tool: if the caller sets allow_web truthy, expose
|
|
681
|
+
// the built-in web_search capability and let the model decide when to
|
|
682
|
+
// call it.
|
|
683
|
+
if (body.allow_web) {
|
|
684
|
+
coloredLog("allowing web search");
|
|
685
|
+
requestBase.tools = [{ type: 'web_search' }];
|
|
686
|
+
requestBase.tool_choice = 'auto';
|
|
687
|
+
}
|
|
670
688
|
|
|
671
689
|
let response;
|
|
672
690
|
if (assistantId) {
|
|
@@ -706,6 +724,13 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
|
|
|
706
724
|
filteredPatch[f] = patch[f];
|
|
707
725
|
}
|
|
708
726
|
});
|
|
727
|
+
// If we got no fields back on the first attempt, retry once before
|
|
728
|
+
// giving up. Avoid infinite loops by marking a retry flag.
|
|
729
|
+
if (!Object.keys(filteredPatch).length && !body._retry) {
|
|
730
|
+
coloredLog('[autofill] empty patch, retrying once');
|
|
731
|
+
const retryBody = Object.assign({}, body, { _retry: true });
|
|
732
|
+
return await self.autofill(retryBody, req, res);
|
|
733
|
+
}
|
|
709
734
|
|
|
710
735
|
// Optional save
|
|
711
736
|
let savedItem = null;
|
package/server/schemas/form.js
CHANGED
|
@@ -25,7 +25,7 @@ var form ={
|
|
|
25
25
|
{section_start:'Content'},
|
|
26
26
|
{name:'sections',type:'objectList',properties:['name','id'],comment:'name will be displayed, id is for css and js'},
|
|
27
27
|
// {name:'questions',type:'objectReference',values:'question'},
|
|
28
|
-
{name:'questions',type:'buckets',values:'question',
|
|
28
|
+
{name:'questions',type:'buckets',values:'question',reloadable:true,
|
|
29
29
|
comment:'Drag questions to the section of the form they belong in. <joe-button onclick="_joe.Fields.rerender(\'questions\');" class="joe-reload-button joe-button joe-iconed-button">reload form sections</joe-button>',
|
|
30
30
|
bucketCount:function(item){
|
|
31
31
|
return (item.sections && item.sections.length) || 1;
|
|
@@ -37,12 +37,15 @@ var form ={
|
|
|
37
37
|
})
|
|
38
38
|
return names;
|
|
39
39
|
},
|
|
40
|
-
template:
|
|
41
|
-
|
|
40
|
+
template:function(f,q){
|
|
41
|
+
return `<joe-subtext>${q.question_type}</joe-subtext>
|
|
42
|
+
<joe-title>${q.name}</joe-title>
|
|
43
|
+
<joe-subtitle>${q.title || ''}</joe-subtitle>
|
|
44
|
+
<joe-subtitle>${q.fieldname||''}</joe-subtitle>`;
|
|
45
|
+
}
|
|
42
46
|
},
|
|
43
47
|
{section_end:'Content'},
|
|
44
|
-
{section_start:'
|
|
45
|
-
{label:'Submit Action'},
|
|
48
|
+
{section_start:'Functions',collapsed:true},
|
|
46
49
|
|
|
47
50
|
{label:'On Client'},
|
|
48
51
|
{name:'validate',type:'code',language:'javascript',
|
|
@@ -53,7 +56,7 @@ var form ={
|
|
|
53
56
|
{label:'On Server'},
|
|
54
57
|
{name:'server_action',type:'code',language:'javascript',
|
|
55
58
|
comment:'function called on server, function(submission,form_info,request)'},
|
|
56
|
-
{section_end:'
|
|
59
|
+
{section_end:'Functions'},
|
|
57
60
|
{sidebar_start:'right'},
|
|
58
61
|
'updated',
|
|
59
62
|
{section_start:'Preview'},
|
|
@@ -71,7 +74,7 @@ var form ={
|
|
|
71
74
|
},
|
|
72
75
|
{section_end:'Preview'},
|
|
73
76
|
{section_start:'Adv'},
|
|
74
|
-
'form_button_label',
|
|
77
|
+
{name:'form_button_label',display:'form button label',type:'text',comment:'label for the form submit button'},
|
|
75
78
|
{name:'hostname',comment:'joe hostname'},
|
|
76
79
|
{name:'save_submission', type:'boolean', display:'save submission',comment:"use standard submission object"},
|
|
77
80
|
{name:'upsert_submission', type:'boolean', display:'upsert submission',
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
var question ={
|
|
2
2
|
title: 'Q | ${name}',
|
|
3
3
|
info:"The question panel is where you can manage the questions used to build a form.",
|
|
4
|
+
subsets:function(){
|
|
5
|
+
return [{name:'Required',filter:{required:true},stripeColor:'#ff9999'}
|
|
6
|
+
|
|
7
|
+
].concat(_joe.Filter.Options.getDatasetPropertyValues(
|
|
8
|
+
'question',
|
|
9
|
+
'question_type',
|
|
10
|
+
{ group: 'fieldtype', collapsed: false } // optional grouping
|
|
11
|
+
));
|
|
12
|
+
},
|
|
13
|
+
stripeColor:function(item){
|
|
14
|
+
if(item.required){
|
|
15
|
+
return {
|
|
16
|
+
title:'Required',
|
|
17
|
+
color:'#ff9999'
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
},
|
|
4
21
|
filters:function(item){
|
|
5
22
|
return _joe.Filter.Options.tags({group:true,untagged:true,collapsed:true});
|
|
6
23
|
},
|
|
@@ -20,12 +37,12 @@ var question ={
|
|
|
20
37
|
return (['multiple','select'].indexOf(item.question_type) == -1);
|
|
21
38
|
}
|
|
22
39
|
},
|
|
23
|
-
{name:'option_template',width:'33%',
|
|
40
|
+
{name:'option_template',width:'33%',display:'option template',comment:'template for each option, use ${property} to display the property value.',
|
|
24
41
|
hidden:function(item){
|
|
25
42
|
return (['multiple','select'].indexOf(item.question_type) == -1);
|
|
26
43
|
}
|
|
27
44
|
},
|
|
28
|
-
{name:'value_template',width:'33%',
|
|
45
|
+
{name:'value_template',width:'33%',display:'value template',comment:'defaults to _id',
|
|
29
46
|
hidden:function(item){
|
|
30
47
|
return (['multiple','select'].indexOf(item.question_type) == -1);
|
|
31
48
|
}
|