json-object-editor
Version:
JOE the Json Object Editor | Platform Edition
230 lines (214 loc) • 8.06 kB
JavaScript
var schema = {
title: "AI Widget Conversation | ${name||_id}",
display: "AI Convo (new)",
info: "Lightweight conversation log for external AI widgets.",
summary:{
description:'Lightweight, persistent conversation record for embeddable AI widgets.',
purpose:'Use ai_widget_conversation to track widget chats, including model choice, linked ai_assistant, effective system instructions, and a compact messages array. External sites and test pages create/update these records via the chatgpt widgetStart/widgetMessage/widgetHistory endpoints.',
wip:false,
labelField:'name',
defaultSort:{ field:'last_message_at', dir:'desc' },
searchableFields:['name','info','model','assistant_id','source','user_name','_id'],
allowedSorts:['last_message_at','created','joeUpdated','name'],
relationships:{
outbound:[
{ field:'assistant', targetSchema:'ai_assistant', cardinality:'one' },
{ field:'user', targetSchema:'user', cardinality:'one' },
{ field:'tags', targetSchema:'tag', cardinality:'many' }
],
inbound:{ graphRef:'server/relationships.graph.json' }
},
joeManagedFields:['created','joeUpdated'],
fields:[
{ name:'_id', type:'string', required:true },
{ name:'itemtype', type:'string', required:true, const:'ai_widget_conversation' },
{ name:'name', type:'string' },
{ name:'info', type:'string' },
{ name:'model', type:'string' },
{ name:'assistant', type:'string', isReference:true, targetSchema:'ai_assistant' },
{ name:'assistant_id', type:'string' },
{ name:'system', type:'string' },
{ name:'messages', type:'objectList' },
{ name:'last_message_at', type:'string', format:'date-time' },
{ name:'source', type:'string' },
{ name:'user', type:'string', isReference:true, targetSchema:'user' },
{ name:'user_name', type:'string' },
{ name:'user_color', type:'string' },
{ name:'assistant_color', type:'string' },
{ name:'tags', type:'string', isArray:true, isReference:true, targetSchema:'tag' },
{ name:'joeUpdated', type:'string', format:'date-time' },
{ name:'created', type:'string', format:'date-time' }
]
},
listView: {
title: function (convo) {
try{
var ts = convo.last_message_at || convo.joeUpdated || convo.created || '';
var prettyTs = (_joe && _joe.Utils && typeof _joe.Utils.prettyPrintDTS === 'function')
? _joe.Utils.prettyPrintDTS(ts)
: ts;
var title = convo.name || prettyTs || convo._id;
function textColorForBg(hex){
if (!hex || typeof hex !== 'string' || !/^#?[0-9a-fA-F]{6}$/.test(hex)) return '#000';
var h = (hex[0] === '#') ? hex.slice(1) : hex;
var n = parseInt(h, 16);
var r = (n >> 16) & 0xff;
var g = (n >> 8) & 0xff;
var b = n & 0xff;
var luminance = r * 0.299 + g * 0.587 + b * 0.114;
return luminance > 186 ? '#000' : '#fff';
}
function chip(label,bg){
if(!label){ return ''; }
var fg = textColorForBg(bg);
return '<span style="display:inline-block;padding:1px 6px;border-radius:999px;font-size:10px;margin-right:4px;background:'+bg+';color:'+fg+';">'
+ label + '</span>';
}
// User chip
var userName = '';
var userColor = convo.user_color || '';
if (convo.user){
var u = $J.get(convo.user,'user') || $J.get(convo.user);
if (u){
userName = u.fullname || u.name || convo.user_name || '';
userColor = u.color || userColor;
}
} else if (convo.user_name){
userName = convo.user_name;
}
var userChip = userName ? chip(userName, userColor || '#4b5563') : '';
// Assistant chip
var asstName = '';
var asstColor = convo.assistant_color || '';
if (convo.assistant && _joe && _joe.Data && _joe.Data.ai_assistant){
var a = $J.get(convo.assistant,'ai_assistant') ||
_joe.Data.ai_assistant.where({_id:convo.assistant})[0];
if (a){
asstName = a.name || a.title || a.assistant_id || a._id;
asstColor = a.assistant_color || a.color || asstColor;
}
}
if (!asstName && convo.assistant_id && _joe && _joe.Data && _joe.Data.ai_assistant){
var a2 = _joe.Data.ai_assistant.where({assistant_id:convo.assistant_id})[0];
if (a2){
asstName = a2.name || a2.title || a2.assistant_id || a2._id;
asstColor = a2.assistant_color || a2.color || asstColor;
}else{
asstName = convo.assistant_id;
}
}
var asstChip = asstName ? chip(asstName, asstColor || '#2563eb') : '';
return ''
+ '<joe-title>'+title+'</joe-title>'
+ '<joe-subtitle>'+userChip+asstChip+'</joe-subtitle>'
+ (prettyTs ? '<joe-subtext>'+prettyTs+'</joe-subtext>' : '');
}catch(e){
return '<joe-title>'+(convo.name||convo._id)+'</joe-title>';
}
},
listWindowTitle: "AI Widget Conversations"
},
fields: function () {
return [
"name",
"info",
{section_start:"participants"},
{
name: "user",
type: "select",
values: "user",
display: "User (JOE)",
comment: "User of this conversation.",
width: "50%",
blank:true
},
{
name: "assistant",
type: "select",
values: "ai_assistant",
display: "Assistant (JOE)",
comment: "Optional link to an ai_assistant config used by this widget.",
width: "50%",
blank:true
},
{section_end:"participants"},
{ section_start: "conversation", display: "Conversation", collapsed: false },
{
name: "model",
type: "select",
values: "ai_model",
display: "Model",
comment: "Default OpenAI model used for this conversation.",
width: "50%"
},
{
name: "assistant_id",
type: "text",
display: "OpenAI Assistant ID",
comment: "Optional OpenAI assistant used for this conversation."
},
{
name: "system",
type: "code",
display: "System Instructions",
height: "160px",
comment: "Effective system prompt used for this conversation."
},
{
name: "messages",
type: "code",
display: "Messages (JSON)",
height: "260px",
comment: "Array of {role, content, created_at}. Managed by the widget API."
},
{
name: "last_message_at",
type: "date",
display: "Last Message At",
locked: true
},
{ section_end: "conversation" },
{ section_start: "meta", collapsed: true },
"source",
"tags",
{ section_end: "meta" },
{ section_start: "system", collapsed: true },
"_id",
"created",
"joeUpdated",
"itemtype",
{ section_end: "system" }
];
},
// Subsets: grouped quick-filters in the list submenu
subsets:function(){
var sets = [];
// Group by source (e.g., aihub_card, widget, etc.)
sets = sets.concat(
_joe.Filter.Options.getDatasetPropertyValues('ai_widget_conversation','source',{
group:'source'
})
);
return sets;
},
// Filters: sidebar filters
filters:function(){
var filters = [];
// Distinct users referenced by ai_widget_conversation.user
filters = filters.concat(
_joe.Filter.Options.datasetProperty('user','user',{
group:'user',
collapsed:true
}),
// Distinct assistants (JOE ai_assistant) referenced by this conversation
_joe.Filter.Options.datasetProperty('ai_assistant','assistant',{
group:'assistant',
collapsed:true
})
);
return filters;
},
idprop: "_id",
sorter: ["!last_message_at", "!created"]
};
module.exports = schema;