json-object-editor 0.10.650 → 0.10.653
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 +15 -0
- package/_www/mcp-test.html +18 -0
- package/css/joe-styles.css +2 -1
- package/css/joe.css +4 -2
- package/css/joe.min.css +1 -1
- package/docs/joe_agent_custom_gpt_instructions_v_3.md +57 -3
- package/js/JsonObjectEditor.jquery.craydent.js +185 -5
- package/js/joe-ai.js +10 -6
- package/js/joe.js +186 -6
- package/js/joe.min.js +1 -1
- package/package.json +1 -1
- package/readme.md +12 -0
- package/server/apps/aihub.js +1 -0
- package/server/fields/core.js +13 -4
- package/server/modules/MCP.js +1237 -914
- package/server/modules/ThoughtPipeline.js +17 -3
- package/server/plugins/chatgpt.js +76 -7
- package/server/schemas/ai_pipeline.js +90 -0
- package/server/schemas/ai_response.js +162 -17
- package/server/schemas/thought.js +57 -5
- package/server/webconfig.js +1 -1
|
@@ -392,7 +392,7 @@ ThoughtPipeline.compile = async function compile(pipelineId, scopeId, opts) {
|
|
|
392
392
|
* @param {string} agentId
|
|
393
393
|
* @param {string} userInput
|
|
394
394
|
* @param {string} scopeId
|
|
395
|
-
* @param {object} ctx - optional context (e.g., { req })
|
|
395
|
+
* @param {object} ctx - optional context (e.g., { req, model })
|
|
396
396
|
*/
|
|
397
397
|
ThoughtPipeline.runAgent = async function runAgent(agentId, userInput, scopeId, ctx) {
|
|
398
398
|
var agent = getAgent(agentId);
|
|
@@ -401,8 +401,11 @@ ThoughtPipeline.runAgent = async function runAgent(agentId, userInput, scopeId,
|
|
|
401
401
|
var apiKey = getAPIKey();
|
|
402
402
|
var openai = new OpenAI({ apiKey: apiKey });
|
|
403
403
|
|
|
404
|
+
var overrideModel = ctx && ctx.model;
|
|
405
|
+
var modelToUse = overrideModel || agent.model || 'gpt-4.1-mini';
|
|
406
|
+
|
|
404
407
|
var response = await openai.responses.create({
|
|
405
|
-
model:
|
|
408
|
+
model: modelToUse,
|
|
406
409
|
instructions: agent.system_prompt,
|
|
407
410
|
input: JSON.stringify({
|
|
408
411
|
pipeline_id: compiled.pipeline_id,
|
|
@@ -440,6 +443,15 @@ ThoughtPipeline.runAgent = async function runAgent(agentId, userInput, scopeId,
|
|
|
440
443
|
name: agent.name + ' → Thoughts',
|
|
441
444
|
response_type: 'thought_generation',
|
|
442
445
|
response: rawText || '',
|
|
446
|
+
response_json: (function () {
|
|
447
|
+
try {
|
|
448
|
+
var jt = extractJsonText(rawText);
|
|
449
|
+
if (!jt) return null;
|
|
450
|
+
return JSON.parse(jt);
|
|
451
|
+
} catch (_e) {
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
})(),
|
|
443
455
|
response_id: response.id || '',
|
|
444
456
|
user_prompt: userInput || '',
|
|
445
457
|
model_used: agent.model || 'gpt-4.1-mini',
|
|
@@ -518,7 +530,9 @@ ThoughtPipeline.runAgent = async function runAgent(agentId, userInput, scopeId,
|
|
|
518
530
|
created_by: 'agent:' + agent.id
|
|
519
531
|
},
|
|
520
532
|
source_ai_response: savedResponseId,
|
|
521
|
-
created_by: 'agent:' + agent.id
|
|
533
|
+
created_by: 'agent:' + agent.id,
|
|
534
|
+
creator_type: 'agent',
|
|
535
|
+
creator_id: agent.id
|
|
522
536
|
};
|
|
523
537
|
}).filter(function (obj) {
|
|
524
538
|
return obj.statement && obj.statement.length;
|
|
@@ -432,7 +432,40 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
|
|
|
432
432
|
model: 'gpt-4o',
|
|
433
433
|
});
|
|
434
434
|
coloredLog(chatCompletion);
|
|
435
|
-
|
|
435
|
+
const text = chatCompletion.choices && chatCompletion.choices[0] && chatCompletion.choices[0].message && chatCompletion.choices[0].message.content || '';
|
|
436
|
+
// Optionally persist as ai_response with parsed JSON when applicable
|
|
437
|
+
const parsed = (function(){
|
|
438
|
+
try {
|
|
439
|
+
const jt = extractJsonText(text);
|
|
440
|
+
return jt ? JSON.parse(jt) : null;
|
|
441
|
+
} catch(_e){ return null; }
|
|
442
|
+
})();
|
|
443
|
+
try {
|
|
444
|
+
var creator_type = null;
|
|
445
|
+
var creator_id = null;
|
|
446
|
+
try{
|
|
447
|
+
var u = req && req.User;
|
|
448
|
+
if (u && u._id){
|
|
449
|
+
creator_type = 'user';
|
|
450
|
+
creator_id = u._id;
|
|
451
|
+
}
|
|
452
|
+
}catch(_e){}
|
|
453
|
+
const aiResponse = {
|
|
454
|
+
itemtype: 'ai_response',
|
|
455
|
+
name: 'Test Prompt → ChatGPT',
|
|
456
|
+
response_type: 'testPrompt',
|
|
457
|
+
response: text,
|
|
458
|
+
response_json: parsed,
|
|
459
|
+
response_id: chatCompletion.id || '',
|
|
460
|
+
user_prompt: payload && payload.data && payload.data.prompt || 'Tell me a story about JOE: the json object editor in under 256 chars.',
|
|
461
|
+
model_used: 'gpt-4o',
|
|
462
|
+
created: (new Date()).toISOString(),
|
|
463
|
+
creator_type: creator_type,
|
|
464
|
+
creator_id: creator_id
|
|
465
|
+
};
|
|
466
|
+
JOE.Storage.save(aiResponse, 'ai_response', function(){}, { history: false, user: (req && req.User) || { name:'system' } });
|
|
467
|
+
} catch(_e){ /* best-effort only */ }
|
|
468
|
+
return {payload,chatCompletion,content:text};
|
|
436
469
|
} catch (error) {
|
|
437
470
|
if (error.status === 429) {
|
|
438
471
|
return { errors: 'You exceeded your current quota, please check your plan and billing details.' };
|
|
@@ -498,7 +531,7 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
|
|
|
498
531
|
response: chatContent,
|
|
499
532
|
payload,
|
|
500
533
|
prompt_method:req.params.method
|
|
501
|
-
});
|
|
534
|
+
}, req && req.User);
|
|
502
535
|
coloredLog("response saved -"+responseName);
|
|
503
536
|
return {payload,
|
|
504
537
|
businessOBJ,
|
|
@@ -549,8 +582,16 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
|
|
|
549
582
|
return match ? match[1] : null;
|
|
550
583
|
}
|
|
551
584
|
|
|
552
|
-
async function saveAIResponse(data) {
|
|
585
|
+
async function saveAIResponse(data, user) {
|
|
553
586
|
try {
|
|
587
|
+
var creator_type = null;
|
|
588
|
+
var creator_id = null;
|
|
589
|
+
try{
|
|
590
|
+
if (user && user._id){
|
|
591
|
+
creator_type = 'user';
|
|
592
|
+
creator_id = user._id;
|
|
593
|
+
}
|
|
594
|
+
}catch(_e){}
|
|
554
595
|
const aiResponse = {
|
|
555
596
|
name: data.name,
|
|
556
597
|
itemtype: 'ai_response',
|
|
@@ -560,7 +601,9 @@ function shrinkUnderstandObjectMessagesForTokens(messages) {
|
|
|
560
601
|
payload: data.payload,
|
|
561
602
|
prompt_method:data.prompt_method,
|
|
562
603
|
created: (new Date).toISOString(),
|
|
563
|
-
_id:cuid()
|
|
604
|
+
_id:cuid(),
|
|
605
|
+
creator_type: creator_type,
|
|
606
|
+
creator_id: creator_id
|
|
564
607
|
// Add any other fields you want to save
|
|
565
608
|
};
|
|
566
609
|
await new Promise((resolve, reject) => {
|
|
@@ -880,7 +923,9 @@ this.executeJOEAiPrompt = async function(data, req, res) {
|
|
|
880
923
|
params,
|
|
881
924
|
referenced_object_ids: referencedObjectIds,
|
|
882
925
|
response_id:response.id,
|
|
883
|
-
usage: response.usage || {}
|
|
926
|
+
usage: response.usage || {},
|
|
927
|
+
user: req && req.User,
|
|
928
|
+
ai_assistant_id: data.ai_assistant_id
|
|
884
929
|
});
|
|
885
930
|
|
|
886
931
|
return { success: true, ai_response_id: saved._id,response:response.output_text || "",usage:response.usage };
|
|
@@ -903,13 +948,34 @@ this.executeJOEAiPrompt = async function(data, req, res) {
|
|
|
903
948
|
max_tokens: prompt.max_tokens ?? 1200
|
|
904
949
|
};
|
|
905
950
|
}
|
|
906
|
-
async function saveAiResponseRefactor({ prompt, ai_response_content, user_prompt, params, referenced_object_ids,response_id,usage}) {
|
|
951
|
+
async function saveAiResponseRefactor({ prompt, ai_response_content, user_prompt, params, referenced_object_ids,response_id,usage,user,ai_assistant_id}) {
|
|
907
952
|
var response_keys = [];
|
|
908
953
|
try {
|
|
909
954
|
response_keys = Object.keys(JSON.parse(ai_response_content));
|
|
910
955
|
}catch (e) {
|
|
911
956
|
console.error('❌ Error parsing AI response content for keys:', e);
|
|
912
957
|
}
|
|
958
|
+
// Best-effort parse into JSON for downstream agents (Thought pipeline, etc.)
|
|
959
|
+
let parsedResponse = null;
|
|
960
|
+
try {
|
|
961
|
+
const jt = extractJsonText(ai_response_content);
|
|
962
|
+
if (jt) {
|
|
963
|
+
parsedResponse = JSON.parse(jt);
|
|
964
|
+
}
|
|
965
|
+
} catch(_e) {
|
|
966
|
+
parsedResponse = null;
|
|
967
|
+
}
|
|
968
|
+
var creator_type = null;
|
|
969
|
+
var creator_id = null;
|
|
970
|
+
try{
|
|
971
|
+
if (ai_assistant_id){
|
|
972
|
+
creator_type = 'ai_assistant';
|
|
973
|
+
creator_id = ai_assistant_id;
|
|
974
|
+
} else if (user && user._id){
|
|
975
|
+
creator_type = 'user';
|
|
976
|
+
creator_id = user._id;
|
|
977
|
+
}
|
|
978
|
+
}catch(_e){}
|
|
913
979
|
const aiResponse = {
|
|
914
980
|
name: `${prompt.name}`,
|
|
915
981
|
itemtype: 'ai_response',
|
|
@@ -917,6 +983,7 @@ this.executeJOEAiPrompt = async function(data, req, res) {
|
|
|
917
983
|
prompt_name: prompt.name,
|
|
918
984
|
prompt_method:prompt.prompt_method,
|
|
919
985
|
response: ai_response_content,
|
|
986
|
+
response_json: parsedResponse,
|
|
920
987
|
response_keys: response_keys,
|
|
921
988
|
response_id:response_id||'',
|
|
922
989
|
user_prompt: user_prompt,
|
|
@@ -926,7 +993,9 @@ this.executeJOEAiPrompt = async function(data, req, res) {
|
|
|
926
993
|
model_used: prompt.ai_model || "gpt-4o",
|
|
927
994
|
referenced_objects: referenced_object_ids, // new flexible array of referenced object ids
|
|
928
995
|
created: (new Date).toISOString(),
|
|
929
|
-
_id: cuid()
|
|
996
|
+
_id: cuid(),
|
|
997
|
+
creator_type: creator_type,
|
|
998
|
+
creator_id: creator_id
|
|
930
999
|
};
|
|
931
1000
|
|
|
932
1001
|
await new Promise((resolve, reject) => {
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
var schema = {
|
|
2
|
+
title: "AI Pipeline | ${name}",
|
|
3
|
+
display: "AI Pipeline",
|
|
4
|
+
info: "Configurable AI context pipelines composed of ordered steps, used to compile context for agents like the Thought Engine.",
|
|
5
|
+
summary: {
|
|
6
|
+
description: "Declarative definition of AI context pipelines: an ordered list of steps (schema summaries, thoughts, objects, etc.) that feed agents.",
|
|
7
|
+
purpose: "Use ai_pipeline to configure what context is compiled for a given agent run (e.g., which schemas, thoughts, and objects are included) without changing code.",
|
|
8
|
+
labelField: "name",
|
|
9
|
+
defaultSort: { field: "created", dir: "desc" },
|
|
10
|
+
searchableFields: ["name", "pipeline_id", "info", "_id"],
|
|
11
|
+
allowedSorts: ["created", "joeUpdated", "name"],
|
|
12
|
+
relationships: {
|
|
13
|
+
outbound: [
|
|
14
|
+
// Future: agents that reference this pipeline_id
|
|
15
|
+
],
|
|
16
|
+
inbound: { graphRef: "server/relationships.graph.json" }
|
|
17
|
+
},
|
|
18
|
+
joeManagedFields: ["created", "joeUpdated"],
|
|
19
|
+
fields: [
|
|
20
|
+
{ name: "_id", type: "string", required: true },
|
|
21
|
+
{ name: "itemtype", type: "string", required: true, const: "ai_pipeline" },
|
|
22
|
+
{ name: "name", type: "string", required: true },
|
|
23
|
+
{ name: "pipeline_id", type: "string", required: true },
|
|
24
|
+
{ name: "info", type: "string" },
|
|
25
|
+
// Steps are minimal, but expressive enough to mirror current PIPELINES config
|
|
26
|
+
{ name: "steps", type: "objectList" },
|
|
27
|
+
{ name: "joeUpdated", type: "string", format: "date-time" },
|
|
28
|
+
{ name: "created", type: "string", format: "date-time" }
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
listView: {
|
|
32
|
+
title: function (p) {
|
|
33
|
+
return `
|
|
34
|
+
<joe-subtext>${_joe.Utils.prettyPrintDTS(p.created)}</joe-subtext>
|
|
35
|
+
<joe-title>${p.name}</joe-title>
|
|
36
|
+
<joe-subtitle>${p.pipeline_id || ""}</joe-subtitle>
|
|
37
|
+
`;
|
|
38
|
+
},
|
|
39
|
+
listWindowTitle: "AI Pipelines"
|
|
40
|
+
},
|
|
41
|
+
sorter: ["!created", "name"],
|
|
42
|
+
fields: [
|
|
43
|
+
"name",
|
|
44
|
+
{ name: "pipeline_id", width: "50%", comment: "Logical id used by agents and ThoughtPipeline (e.g., thought_default, protocol_planning)." },
|
|
45
|
+
"info",
|
|
46
|
+
|
|
47
|
+
{ section_start: "steps", display: "Pipeline Steps", collapsed: false },
|
|
48
|
+
{
|
|
49
|
+
name: "steps",
|
|
50
|
+
type: "objectList",
|
|
51
|
+
display: "Steps",
|
|
52
|
+
comment: "Ordered steps that define how context is compiled.",
|
|
53
|
+
properties: [
|
|
54
|
+
{ name: "id", width: "20%", comment: "Stable step id (e.g., schema_summaries, accepted_thoughts)." },
|
|
55
|
+
{
|
|
56
|
+
name: "step_type",
|
|
57
|
+
type: "select",
|
|
58
|
+
values: ["schema_summaries", "thoughts", "objects", "scope_object", "text", "tools"],
|
|
59
|
+
width: "15%",
|
|
60
|
+
comment: "Determines how this step is executed."
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: "render_mode",
|
|
64
|
+
type: "select",
|
|
65
|
+
values: ["json", "compact_json", "bullets", "text"],
|
|
66
|
+
width: "15%",
|
|
67
|
+
comment: "How this step is rendered into the agent prompt."
|
|
68
|
+
},
|
|
69
|
+
{ name: "required", type: "boolean", width: "10%", comment: "If true, pipeline fails when this step cannot be resolved." },
|
|
70
|
+
{
|
|
71
|
+
name: "selector",
|
|
72
|
+
type: "code",
|
|
73
|
+
language: "json",
|
|
74
|
+
width: "40%",
|
|
75
|
+
comment: "Free-form selector JSON (e.g., { \"names\": [\"thought\",\"ai_prompt\" ] } or { \"query\": {\"itemtype\":\"thought\"}, \"sortBy\":\"joeUpdated\" } )."
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
},
|
|
79
|
+
{ section_end: "steps" },
|
|
80
|
+
|
|
81
|
+
{ section_start: "system", collapsed: true },
|
|
82
|
+
"_id",
|
|
83
|
+
"created",
|
|
84
|
+
"itemtype",
|
|
85
|
+
{ section_end: "system" }
|
|
86
|
+
],
|
|
87
|
+
idprop: "_id"
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
module.exports = schema;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var schema = {
|
|
2
2
|
title : 'Ai Response | ${name}',
|
|
3
|
+
display:'AI Response',
|
|
3
4
|
info:"An ai response from openai etc",
|
|
4
5
|
summary:{
|
|
5
6
|
description:'Stored AI response objects generated from ai_prompt and the chatgpt plugin.',
|
|
@@ -29,9 +30,12 @@ var schema = {
|
|
|
29
30
|
{ name:'model_used', type:'string' },
|
|
30
31
|
{ name:'response_type', type:'string' },
|
|
31
32
|
{ name:'response', type:'string' },
|
|
33
|
+
{ name:'response_json', type:'object' },
|
|
32
34
|
{ name:'response_keys', type:'string', isArray:true },
|
|
33
35
|
{ name:'response_id', type:'string' },
|
|
34
36
|
{ name:'usage', type:'object' },
|
|
37
|
+
// { name:'creator_type', type:'string', enumValues:['user','ai_assistant'] },
|
|
38
|
+
// { name:'creator_id', type:'string' },
|
|
35
39
|
{ name:'tags', type:'string', isArray:true, isReference:true, targetSchema:'tag' },
|
|
36
40
|
{ name:'joeUpdated', type:'string', format:'date-time' },
|
|
37
41
|
{ name:'created', type:'string', format:'date-time' }
|
|
@@ -61,18 +65,129 @@ var schema = {
|
|
|
61
65
|
},
|
|
62
66
|
listWindowTitle: 'Ai Responses'
|
|
63
67
|
},
|
|
64
|
-
subsets: function(){
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
68
|
+
subsets: function(a,b,c){
|
|
69
|
+
// Base subsets: tag-based and by ai_prompt
|
|
70
|
+
var subsets = _joe.Filter.Options.tags({group:true,collapsed:false}).concat(
|
|
71
|
+
_joe.getDataset('ai_prompt').map(function(prompt){
|
|
72
|
+
var color = prompt.status && $J.get(prompt.status,'status').color;
|
|
73
|
+
return {
|
|
74
|
+
name: prompt.name,
|
|
75
|
+
id: prompt._id,
|
|
76
|
+
filter: { ai_prompt: prompt._id },
|
|
77
|
+
stripecolor: color || null // optional
|
|
78
|
+
};
|
|
79
|
+
})
|
|
80
|
+
);
|
|
75
81
|
|
|
82
|
+
// Additional subset: "Generated Thoughts" – detect from raw JSON
|
|
83
|
+
// We look inside response_json for proposed_thoughts / thoughts arrays.
|
|
84
|
+
try{
|
|
85
|
+
var ds = _joe.getDataset('ai_response') || [];
|
|
86
|
+
var ids = [];
|
|
87
|
+
ds.map(function(r){
|
|
88
|
+
var j = r && r.response_json;
|
|
89
|
+
if (!j) { return; }
|
|
90
|
+
if (Array.isArray(j.proposed_thoughts) && j.proposed_thoughts.length) {
|
|
91
|
+
ids.push(r._id);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (Array.isArray(j.thoughts) && j.thoughts.length) {
|
|
95
|
+
ids.push(r._id);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
if (ids.length) {
|
|
99
|
+
subsets.push({
|
|
100
|
+
name: 'Generated Thoughts',
|
|
101
|
+
id: 'generated_thoughts',
|
|
102
|
+
filter: { _id: { $in: ids } },
|
|
103
|
+
stripecolor: _joe.Colors.ai
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}catch(_e){ /* best-effort only */ }
|
|
107
|
+
// subsets.push(
|
|
108
|
+
// {
|
|
109
|
+
// name: 'True',
|
|
110
|
+
// id: 'isTrue',
|
|
111
|
+
// filter: function(air,index, arra){
|
|
112
|
+
// return air.response_json && air.response_json.proposed_thoughts && air.response_json.proposed_thoughts.length > 0;
|
|
113
|
+
// },
|
|
114
|
+
// stripecolor: 'gold'
|
|
115
|
+
// }
|
|
116
|
+
// );
|
|
117
|
+
return subsets;
|
|
118
|
+
},
|
|
119
|
+
stripeColor:function(air){
|
|
120
|
+
if(air.response_json && air.response_json.proposed_thoughts){
|
|
121
|
+
return {color:_joe.Colors.ai,title:'Proposed '+air.response_json.proposed_thoughts.length+' Thoughts'};
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
},
|
|
125
|
+
filters:function(){
|
|
126
|
+
var filters = [];
|
|
127
|
+
// Tag filters
|
|
128
|
+
filters = filters.concat(
|
|
129
|
+
_joe.Filter.Options.tags({group:'tags',untagged:true,collapsed:true})
|
|
130
|
+
);
|
|
131
|
+
// creator_type simple value grouping
|
|
132
|
+
// try{
|
|
133
|
+
// filters = filters.concat(
|
|
134
|
+
// _joe.Filter.Options.getDatasetPropertyValues('ai_response','creator_type',{ group: 'creator_type', collapsed: true })
|
|
135
|
+
// );
|
|
136
|
+
// }catch(_e){}
|
|
137
|
+
// // creator_id filters with human-readable names
|
|
138
|
+
// try{
|
|
139
|
+
// var dataset = _joe.getDataset('ai_response') || [];
|
|
140
|
+
// var byCreator = {};
|
|
141
|
+
// dataset.map(function(r){
|
|
142
|
+
// if(!r.creator_id){ return; }
|
|
143
|
+
// var key = r.creator_type+':'+r.creator_id;
|
|
144
|
+
// if(!byCreator[key]){
|
|
145
|
+
// var name = r.creator_id;
|
|
146
|
+
// if(r.creator_type === 'user' && _joe.Data.user){
|
|
147
|
+
// var u = _joe.Data.user.find(function(x){ return x && x._id === r.creator_id; });
|
|
148
|
+
// if(u){ name = u.fullname || u.name || u.email || u._id; }
|
|
149
|
+
// }else if(r.creator_type === 'ai_assistant' && _joe.Data.ai_assistant){
|
|
150
|
+
// var a = _joe.Data.ai_assistant.find(function(x){ return x && x._id === r.creator_id; });
|
|
151
|
+
// if(a){ name = a.name || a._id; }
|
|
152
|
+
// }
|
|
153
|
+
// byCreator[key] = {
|
|
154
|
+
// name: name,
|
|
155
|
+
// filter: { creator_type: r.creator_type, creator_id: r.creator_id }
|
|
156
|
+
// };
|
|
157
|
+
// }
|
|
158
|
+
// });
|
|
159
|
+
// var keys = Object.keys(byCreator);
|
|
160
|
+
// if(keys.length){
|
|
161
|
+
// filters.push({ group_start:'creator', collapsed:true });
|
|
162
|
+
// keys.sort(function(a,b){
|
|
163
|
+
// var na = byCreator[a].name.toLowerCase();
|
|
164
|
+
// var nb = byCreator[b].name.toLowerCase();
|
|
165
|
+
// if(na>nb) return 1;
|
|
166
|
+
// if(na<nb) return -1;
|
|
167
|
+
// return 0;
|
|
168
|
+
// }).map(function(k){
|
|
169
|
+
// filters.push({
|
|
170
|
+
// name: byCreator[k].name,
|
|
171
|
+
// filter: byCreator[k].filter
|
|
172
|
+
// });
|
|
173
|
+
// });
|
|
174
|
+
// filters.push({ group_end:'creator' });
|
|
175
|
+
// }
|
|
176
|
+
// }catch(_e){}
|
|
177
|
+
return filters;
|
|
178
|
+
},
|
|
179
|
+
itemExpander:function(air){
|
|
180
|
+
if(air.response_json && air.response_json.proposed_thoughts){
|
|
181
|
+
//list proposed thoughts in html with header "Proposed Thoughts"
|
|
182
|
+
var html = `<joe-card><joe-title>Proposed Thoughts</joe-title>`;
|
|
183
|
+
air.response_json.proposed_thoughts.map(thought=>{
|
|
184
|
+
html += `<joe-subtitle>${thought.statement}</joe-subtitle><br/>`;
|
|
185
|
+
});
|
|
186
|
+
html += `</joe-card>`;
|
|
187
|
+
return html;
|
|
188
|
+
}
|
|
189
|
+
return _joe.schemas.thought.methods.listThoughts(air);
|
|
190
|
+
},
|
|
76
191
|
sorter:['!created','name'],
|
|
77
192
|
checkChanges:false,
|
|
78
193
|
fields:[
|
|
@@ -83,7 +198,7 @@ var schema = {
|
|
|
83
198
|
return $J.search({_id:{$in:air.referenced_objects}});
|
|
84
199
|
},display:'Referenced Objects',locked:true},
|
|
85
200
|
{name:'generated_thoughts',type:'objectReference',width:'50%',values:function(air,orList){
|
|
86
|
-
return $J.search({
|
|
201
|
+
return $J.search({source_ai_response:air._id,itemtype:'thought'});
|
|
87
202
|
},display:'Generated Thoughts',locked:true},
|
|
88
203
|
{name:'user_prompt', display:'Sent User Prompt',comment:"The input sent by the user after all processing",locked:true,type:'rendering'},
|
|
89
204
|
|
|
@@ -98,17 +213,47 @@ var schema = {
|
|
|
98
213
|
|
|
99
214
|
//{name:'params', type:'rendering', locked:true},
|
|
100
215
|
{section_start:'response',collapsed:false},
|
|
101
|
-
{
|
|
102
|
-
|
|
216
|
+
{
|
|
217
|
+
name:'response_type',
|
|
218
|
+
type:'text',
|
|
219
|
+
display:'Response Type',
|
|
220
|
+
placeholder:'(a code for the responsetype)',
|
|
221
|
+
locked:true,
|
|
222
|
+
width:'50%',
|
|
223
|
+
condition:function(v){
|
|
103
224
|
return v.length > 0;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
{name:'response', type:'rendering', locked:true,height:'500px'},
|
|
225
|
+
}
|
|
226
|
+
},
|
|
227
|
+
{name:'response', type:'rendering', locked:true, height:'500px'},
|
|
228
|
+
{
|
|
229
|
+
name:'response_json',
|
|
230
|
+
type:'content',
|
|
231
|
+
display:'Parsed Response (JSON)',
|
|
232
|
+
locked:true,
|
|
233
|
+
run:function(air){
|
|
234
|
+
if (!air || !air.response_json) { return ''; }
|
|
235
|
+
try{
|
|
236
|
+
var json = JSON.stringify(air.response_json, null, 2);
|
|
237
|
+
// basic HTML escape for safety
|
|
238
|
+
json = String(json)
|
|
239
|
+
.replace(/&/g,'&')
|
|
240
|
+
.replace(/</g,'<')
|
|
241
|
+
.replace(/>/g,'>');
|
|
242
|
+
return '<pre style="white-space:pre-wrap; max-height:260px; overflow:auto;">'+json+'</pre>';
|
|
243
|
+
}catch(e){
|
|
244
|
+
return '<pre>'+String(air.response_json)+'</pre>';
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
},
|
|
107
248
|
{name:'response_keys', type:'text', locked:true,display:'Response Keys'},
|
|
108
249
|
{name:'response_id', type:'text', display:'openAI response ID',locked:true},
|
|
109
250
|
{section_end:'response'},
|
|
110
251
|
{sidebar_start:'right', collapsed:false},
|
|
252
|
+
// {section_start:'creator'},
|
|
253
|
+
// 'creator_type','creator_id',
|
|
254
|
+
// {section_end:'creator'},
|
|
111
255
|
{section_start:'workflow'},
|
|
256
|
+
'status',
|
|
112
257
|
'tags',
|
|
113
258
|
{section_end:'workflow'},
|
|
114
259
|
{section_start:'tokens'},
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
const { methods } = require("./ai_prompt");
|
|
2
|
+
|
|
1
3
|
var thought = {
|
|
2
4
|
display:'Thought',
|
|
3
|
-
title: 'Thought | ${
|
|
5
|
+
title: 'Thought | ${name}',
|
|
4
6
|
info: "Persistent reasoning artifact (hypothesis, synthesis, or link) used to build an auditable world model in JOE.",
|
|
5
7
|
menuicon:`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
|
6
8
|
<path d="M418.79 152.21c54.1-4.68 106.11 14.11 145.57 50.7 179.88-61.28 357.82 94.91 322.09 281.77-17.7 92.57-93.99 170.46-185.58 191.53-7.83 1.8-34.03 4.23-38 6.47-2.3 1.29-14.64 18.32-18.65 22.27-82.76 81.43-218.9 67.72-286.83-24.62l-35.16 3.37c-205.89-4.36-263.08-280.1-74.73-364.78 10.05-87.72 83.39-159.08 171.29-166.69Zm-39.41 491.05c4.96 4.51 11.22 16.94 16.69 23.33 46.94 54.84 121.44 70.23 186.17 36.84 26.3-13.56 42.96-35.52 62.34-56.84 75.92-4.51 145.19-42.32 182.22-109.5 88.11-159.86-57.37-346.63-233.69-303.07-9.81 2.43-27.09 11.14-35.93 10.11-8.59-1-28.84-22.68-38.58-29.14-86.51-57.47-207.06-11.17-229.88 89.98-3.02 13.37-1.37 36.64-13.02 43.9-16.07 10.02-32.75 13.56-49.51 26.98-116.69 93.45-38.49 282 110.22 268.53 13.11-1.19 31.88-11.21 42.98-1.12Z"/>
|
|
@@ -12,7 +14,7 @@ var thought = {
|
|
|
12
14
|
purpose: 'Use thoughts to store inspectable reasoning: hypotheses to be vetted, syntheses that compress many objects, and binary links (A↔B) with receipts. Thoughts are reusable as context in pipelines and agent runs.',
|
|
13
15
|
labelField: 'name',
|
|
14
16
|
defaultSort: { field: 'joeUpdated', dir: 'desc' },
|
|
15
|
-
searchableFields: ['name', 'statement', 'info', 'thought_type', 'status', 'relationship_type', 'tags', '_id'],
|
|
17
|
+
searchableFields: ['name', 'statement', 'info', 'thought_type', 'status', 'relationship_type', 'created_by', 'creator_type', 'creator_id', 'tags', '_id'],
|
|
16
18
|
allowedSorts: ['joeUpdated', 'created', 'thought_type', 'status', 'certainty'],
|
|
17
19
|
relationships: {
|
|
18
20
|
outbound: [
|
|
@@ -47,9 +49,11 @@ var thought = {
|
|
|
47
49
|
{ name: 'b', type: 'object' },
|
|
48
50
|
{ name: 'relationship_type', type: 'string' },
|
|
49
51
|
{ name: 'rationale', type: 'string' },
|
|
50
|
-
// Lineage / provenance (ai_response_id, created_by, reviewed_by, etc.)
|
|
52
|
+
// Lineage / provenance (ai_response_id, created_by/creator, reviewed_by, etc.)
|
|
51
53
|
{ name: 'source_ai_response', type: 'string', isReference: true, targetSchema: 'ai_response' },
|
|
52
54
|
{ name: 'created_by', type: 'string' },
|
|
55
|
+
{ name: 'creator_type', type: 'string', enumValues: ['user','agent'] },
|
|
56
|
+
{ name: 'creator_id', type: 'string' },
|
|
53
57
|
{ name: 'lineage', type: 'object' },
|
|
54
58
|
{ name: 'joeUpdated', type: 'string', format: 'date-time', required: true },
|
|
55
59
|
{ name: 'created', type: 'string', format: 'date-time', required: true }
|
|
@@ -68,9 +72,54 @@ var thought = {
|
|
|
68
72
|
var filters = [];
|
|
69
73
|
// Tag-based filters are the main cross-cutting dimension for Thoughts
|
|
70
74
|
filters = filters.concat(
|
|
71
|
-
_joe.Filter.Options.tags({ group: 'tags', untagged: true, collapsed: true })
|
|
75
|
+
_joe.Filter.Options.tags({ group: 'tags', untagged: true, collapsed: true }),
|
|
76
|
+
_joe.Filter.Options.getDatasetPropertyValues('thought','created_by',{ group: 'created_by', collapsed: true }),
|
|
77
|
+
_joe.Filter.Options.getDatasetPropertyValues('thought','creator_type',{ group: 'creator_type', collapsed: true })
|
|
78
|
+
|
|
72
79
|
);
|
|
73
80
|
|
|
81
|
+
// Creator_id filters with human-readable labels
|
|
82
|
+
try{
|
|
83
|
+
var dataset = _joe.getDataset('thought') || [];
|
|
84
|
+
var byCreator = {};
|
|
85
|
+
dataset.map(function(t){
|
|
86
|
+
if(!t.creator_id){ return; }
|
|
87
|
+
var key = t.creator_type+':'+t.creator_id;
|
|
88
|
+
if(!byCreator[key]){
|
|
89
|
+
// Try to resolve a nice display name
|
|
90
|
+
var name = t.creator_id;
|
|
91
|
+
if(t.creator_type === 'user' && _joe.Data.user){
|
|
92
|
+
var u = _joe.Data.user.find(function(x){ return x && x._id === t.creator_id; });
|
|
93
|
+
if(u){ name = u.fullname || u.name || u.email || u._id; }
|
|
94
|
+
}else if(t.creator_type === 'agent'){
|
|
95
|
+
// For agents we only have logical ids like thought_agent_default
|
|
96
|
+
name = t.creator_id;
|
|
97
|
+
}
|
|
98
|
+
byCreator[key] = {
|
|
99
|
+
name: name,
|
|
100
|
+
filter: { creator_type: t.creator_type, creator_id: t.creator_id }
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
var keys = Object.keys(byCreator);
|
|
105
|
+
if(keys.length){
|
|
106
|
+
filters.push({ group_start:'creator', collapsed:true });
|
|
107
|
+
keys.sort(function(a,b){
|
|
108
|
+
var na = byCreator[a].name.toLowerCase();
|
|
109
|
+
var nb = byCreator[b].name.toLowerCase();
|
|
110
|
+
if(na>nb) return 1;
|
|
111
|
+
if(na<nb) return -1;
|
|
112
|
+
return 0;
|
|
113
|
+
}).map(function(k){
|
|
114
|
+
filters.push({
|
|
115
|
+
name: byCreator[k].name,
|
|
116
|
+
filter: byCreator[k].filter
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
filters.push({ group_end:'creator' });
|
|
120
|
+
}
|
|
121
|
+
}catch(_e){}
|
|
122
|
+
|
|
74
123
|
// Group thoughts by what they are about (about[].itemtype).
|
|
75
124
|
// We build filters manually so that each itemtype gets its own filter
|
|
76
125
|
// on the nested path "about.itemtype". JOE's search engine treats this
|
|
@@ -104,7 +153,7 @@ var thought = {
|
|
|
104
153
|
},
|
|
105
154
|
listView: {
|
|
106
155
|
title: function (th) {
|
|
107
|
-
var html = `<joe-subtext>${_joe.Utils.prettyPrintDTS(th.created)}</joe-subtext><joe-title>${th.name}</joe-title>`;
|
|
156
|
+
var html = `<joe-subtext>${th.created_by} - ${_joe.Utils.prettyPrintDTS(th.created)}</joe-subtext><joe-title>${th.name}</joe-title>`;
|
|
108
157
|
html += `<joe-subtitle>${th.statement}</joe-subtitle>`;
|
|
109
158
|
|
|
110
159
|
return html;
|
|
@@ -237,6 +286,8 @@ var thought = {
|
|
|
237
286
|
locked: true
|
|
238
287
|
},
|
|
239
288
|
{ name: 'created_by', type: 'string', locked: true },
|
|
289
|
+
{ name: 'creator_type', type: 'select', values:['user','agent'], locked: true },
|
|
290
|
+
{ name: 'creator_id', type: 'string', locked: true },
|
|
240
291
|
{
|
|
241
292
|
name: 'lineage',
|
|
242
293
|
type: 'rendering',
|
|
@@ -272,6 +323,7 @@ var thought = {
|
|
|
272
323
|
}
|
|
273
324
|
});
|
|
274
325
|
},
|
|
326
|
+
methods:{},
|
|
275
327
|
idprop: '_id'
|
|
276
328
|
};
|
|
277
329
|
|
package/server/webconfig.js
CHANGED
|
@@ -21,7 +21,7 @@ var joewebconfig = {
|
|
|
21
21
|
templatesDir:'_templates',
|
|
22
22
|
//httpsPort:2100,
|
|
23
23
|
default_schemas:['user','group','goal','initiative','event','report','tag','status','workflow','list','notification','note','include','instance','setting',
|
|
24
|
-
'ai_assistant','ai_conversation','ai_response','ai_tool','ai_prompt','ai_widget_conversation','thought'
|
|
24
|
+
'ai_assistant','ai_conversation','ai_response','ai_tool','ai_prompt','ai_widget_conversation','ai_pipeline','thought'
|
|
25
25
|
]
|
|
26
26
|
};
|
|
27
27
|
|