json-object-editor
Version:
JOE the Json Object Editor | Platform Edition
281 lines (267 loc) • 15.2 kB
JavaScript
var thought = {
display:'Thought',
title: 'Thought | ${thought_type}: ${statement}',
info: "Persistent reasoning artifact (hypothesis, synthesis, or link) used to build an auditable world model in JOE.",
menuicon:`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
<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"/>
<path d="M272.86 721.35c102.07-14 117.43 140.12 22.44 150.52-105.24 11.51-116.96-137.56-22.44-150.52Zm7.15 37.31c-50.22 5.28-41.54 82.79 10.03 75.91 46.11-6.15 39.26-81.09-10.03-75.91Zm164.98-272.61v24.28c0 8.44.36 13.35 1.07 14.73a6.8 6.8 0 0 0 4.63 3.66c3.46.8 7 1.14 10.55 1h6.52c7.08 0 10.62 2.27 10.62 6.82 0 5.26-3.74 8.48-11.22 9.65a209.9 209.9 0 0 1-27.69 1.27c-11.25 0-19.21-2.18-23.89-6.54-4.68-4.36-7.02-11.83-7.04-22.39V488c.32-4.26-.43-8.54-2.19-12.44a14.22 14.22 0 0 0-8.83-5.5 8.79 8.79 0 0 1-6.62-9.26 8.7 8.7 0 0 1 6.62-9.26 14.7 14.7 0 0 0 8.83-5.67 25.36 25.36 0 0 0 2.19-12.44v-30.45c0-10.4 2.34-17.78 7.02-22.14 4.68-4.36 12.64-6.54 23.89-6.52 9.84-.27 19.68.25 29.43 1.57 2.61.4 5.03 1.57 6.97 3.36a8.05 8.05 0 0 1 2.49 5.9c0 4.54-3.54 6.82-10.62 6.82H461c-6.04 0-10.18.65-12.44 1.94a7.7 7.7 0 0 0-3.41 6.72v34.91c-.13 11.76-3.28 19.59-9.45 23.49-.49.33-.77.88-.77 1.47 0 .91 1.1 2.28 3.31 4.11a18.05 18.05 0 0 1 5.18 8.34c1.2 4.27 1.74 8.7 1.59 13.14Zm68.84-76.43a22.82 22.82 0 0 1 22.72 22.72 22.38 22.38 0 0 1-6.92 16.87 23.34 23.34 0 0 1-32.17 0 22.42 22.42 0 0 1-6.92-16.87 21.04 21.04 0 0 1 5.85-15.1 22.79 22.79 0 0 1 17.44-7.61Zm0 56.35a22.82 22.82 0 0 1 22.72 22.72 22.38 22.38 0 0 1-6.94 16.89 23.34 23.34 0 0 1-32.17 0 22.42 22.42 0 0 1-6.92-16.87 21.08 21.08 0 0 1 5.85-15.1 22.78 22.78 0 0 1 17.47-7.64Zm68.15-30.53v-24.18c0-8.44-.36-13.35-1.07-14.73a6.8 6.8 0 0 0-4.63-3.66c-3.46-.8-7-1.14-10.55-1h-6.47c-7.08 0-10.62-2.27-10.62-6.82 0-5.26 3.74-8.44 11.22-9.55a211.64 211.64 0 0 1 27.69-1.27c11.25 0 19.21 2.18 23.89 6.54 4.68 4.36 7.02 11.74 7.02 22.14v30.6c-.33 4.27.42 8.55 2.19 12.44a14.68 14.68 0 0 0 8.83 5.55 8.68 8.68 0 0 1 6.59 9.28 8.7 8.7 0 0 1-4.58 8.38c-1.54.7-3.14 1.26-4.78 1.67a11.2 11.2 0 0 0-7.02 6.54 31.79 31.79 0 0 0-1.27 10.62v30.5c0 10.47-2.34 17.87-7.02 22.22-4.68 4.35-12.64 6.53-23.89 6.54-9.84.28-19.68-.25-29.43-1.57a13.22 13.22 0 0 1-6.97-3.36 8.2 8.2 0 0 1-2.49-6c0-4.54 3.54-6.82 10.62-6.82.85 0 3.09.07 6.72.2 4.24.21 8.47-.45 12.44-1.94a5.76 5.76 0 0 0 2.99-3.96c.5-4.48.68-9 .55-13.51v-24.28c-.19-4.85.52-9.69 2.09-14.28a21.27 21.27 0 0 1 7.46-9.11c.49-.33.77-.88.77-1.47 0-.91-1.1-2.28-3.31-4.11a17.91 17.91 0 0 1-5.18-8.34 43.8 43.8 0 0 1-1.82-13.31Z"/>
</svg>`,
// Curated summary for agents and tools
summary: {
description: 'Structured “Thought” records that capture hypotheses, syntheses, and explicit links between JOE objects.',
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.',
labelField: 'name',
defaultSort: { field: 'joeUpdated', dir: 'desc' },
searchableFields: ['name', 'statement', 'info', 'thought_type', 'status', 'relationship_type', 'tags', '_id'],
allowedSorts: ['joeUpdated', 'created', 'thought_type', 'status', 'certainty'],
relationships: {
outbound: [
{ field: 'tags', targetSchema: 'tag', cardinality: 'many' },
// Polymorphic references: the actual target schema comes from each entry's itemtype/id
{ field: 'about', targetSchema: '<schemaName>', cardinality: 'many' },
{ field: 'because', targetSchema: '<schemaName>', cardinality: 'many' },
{ field: 'a', targetSchema: '<schemaName>', cardinality: 'one' },
{ field: 'b', targetSchema: '<schemaName>', cardinality: 'one' }
],
inbound: { graphRef: 'server/relationships.graph.json' }
},
joeManagedFields: ['created', 'joeUpdated'],
fields: [
{ name: '_id', type: 'string', required: true },
{ name: 'itemtype', type: 'string', required: true, const: 'thought' },
{ name: 'name', type: 'string', required: true },
{ name: 'thought_type', type: 'string', required: true, enumValues: ['hypothesis', 'synthesis', 'link'] },
{ name: 'statement', type: 'string', required: true },
{ name: 'certainty', type: 'number' },
// Reference to the status object used for this Thought
{ name: 'status', type: 'string', isReference: true, targetSchema: 'status' },
{ name: 'tags', type: 'string', isArray: true, isReference: true, targetSchema: 'tag' },
// Derived field built in onload: array of itemtypes from about[]
{ name: 'about_itemtypes', type: 'string', isArray: true },
// What this thought is about (objects or schemas)
{ name: 'about', type: 'objectList' },
// Why we believe the thought (receipts / evidence)
{ name: 'because', type: 'objectList' },
// Link-specific shape (only used when thought_type === 'link')
{ name: 'a', type: 'object' },
{ name: 'b', type: 'object' },
{ name: 'relationship_type', type: 'string' },
{ name: 'rationale', type: 'string' },
// Lineage / provenance (ai_response_id, created_by, reviewed_by, etc.)
{ name: 'source_ai_response', type: 'string', isReference: true, targetSchema: 'ai_response' },
{ name: 'created_by', type: 'string' },
{ name: 'lineage', type: 'object' },
{ name: 'joeUpdated', type: 'string', format: 'date-time', required: true },
{ name: 'created', type: 'string', format: 'date-time', required: true }
]
},
sorter:['!created','name'],
// Simple subsets to quickly slice by type/status
subsets: function () {
return [
{ name: 'Hypotheses', filter: { thought_type: 'hypothesis' } },
{ name: 'Syntheses', filter: { thought_type: 'synthesis' } },
{ name: 'Links', filter: { thought_type: 'link' } }].concat(_joe.Filter.Options.status({group:'status',collapsed:false}));
},
filters: function () {
var filters = [];
// Tag-based filters are the main cross-cutting dimension for Thoughts
filters = filters.concat(
_joe.Filter.Options.tags({ group: 'tags', untagged: true, collapsed: true })
);
// Group thoughts by what they are about (about[].itemtype).
// We build filters manually so that each itemtype gets its own filter
// on the nested path "about.itemtype". JOE's search engine treats this
// as "array of objects contains an element whose itemtype matches".
try {
var dataset = _joe.getDataset('thought') || [];
var typeMap = {};
dataset.map(function (t) {
if (Array.isArray(t.about)) {
t.about.map(function (a) {
if (a && a.itemtype) {
typeMap[a.itemtype] = true;
}
});
}
});
var types = Object.keys(typeMap).sort();
if (types.length) {
filters.push({ group_start: 'about itemtype', collapsed: true });
types.map(function (tp) {
filters.push({
name: tp,
filter: { 'about.itemtype': tp }
});
});
filters.push({ group_end: 'about itemtype' });
}
} catch (_e) { /* best-effort only */ }
return filters;
},
listView: {
title: function (th) {
var html = `<joe-subtext>${_joe.Utils.prettyPrintDTS(th.created)}</joe-subtext><joe-title>${th.name}</joe-title>`;
html += `<joe-subtitle>${th.statement}</joe-subtitle>`;
return html;
},
listWindowTitle: 'Thoughts'
},
// No special stripe color logic for now; could later reflect status/certainty.
stripeColor: function () { },
fields: [
{ extend: 'name', specs:{ comment: 'Short label for this Thought used in lists and filters.' }},
{ name: 'thought_type', type: 'select', values: ['hypothesis', 'synthesis', 'link'], width: '25%' },
//{ name: 'status', type: 'select', values: ['draft', 'proposed', 'accepted', 'rejected', 'superseded'], width: '25%' },
{ name: 'certainty', type: 'number', width: '25%', comment: '0–1 confidence score for this thought.' },
{ name: 'statement', width: '100%', comment: 'Short, human-readable statement of the thought.' },
{ section_start: 'about', display: 'About (what this thought concerns)', anchor:'about', collapsed: false },
{
name: 'about',
type: 'objectList',
properties: [
{
name: 'itemtype',
type: 'select',
width: '140px',
values: function () {
return (typeof __collectionNames !== 'undefined' && __collectionNames) || [];
}
},
{ name: 'id', width: '220px' },
'role',
'note'
],
comment: 'Objects or schemas this thought is about. Each entry can include an optional role and note.'
},
{ section_end: 'about' },
{ section_start: 'because', display: 'Because (why we believe it)', anchor:'because', collapsed: false },
{
name: 'because',
type: 'objectList',
properties: [
{
name: 'itemtype',
type: 'select',
width: '140px',
values: function () {
return (typeof __collectionNames !== 'undefined' && __collectionNames) || [];
}
},
{ name: 'id', width: '220px' },
'role',
'note'
],
comment: 'Receipts/evidence supporting this thought. Each entry can include a role (why it matters) and note.'
},
{ section_end: 'because' },
{
section_start: 'link',
display: 'Link details (only for link thoughts)',
anchor:'link',
collapsed: false,
hidden: function (item) {
return item.thought_type !== 'link';
}
},
{
name: 'a',
type: 'objectList',
properties: [
{
name: 'itemtype',
type: 'select',
width: '140px',
values: function () {
return (typeof __collectionNames !== 'undefined' && __collectionNames) || [];
}
},
{ name: 'id', width: '220px' }
],
display: 'Endpoint A',
comment: 'First endpoint of the link. Store itemtype and id.',
hidden: function (item) {
return item.thought_type !== 'link';
}
},
{
name: 'b',
type: 'objectList',
properties: [
{
name: 'itemtype',
type: 'select',
width: '140px',
values: function () {
return (typeof __collectionNames !== 'undefined' && __collectionNames) || [];
}
},
{ name: 'id', width: '220px' }
],
display: 'Endpoint B',
comment: 'Second endpoint of the link. Store itemtype and id.',
hidden: function (item) {
return item.thought_type !== 'link';
}
},
{
name: 'relationship_type',
comment: 'Short verb/label for how A relates to B (e.g., included_in, supports, contradicts).',
hidden: function (item) {
return item.thought_type !== 'link';
}
},
{
name: 'rationale',
comment: 'One-sentence rationale for why this link exists.',
hidden: function (item) {
return item.thought_type !== 'link';
}
},
{ section_end: 'link' },
{ section_start: 'lineage', display: 'Lineage & provenance', collapsed: true },
{
name: 'source_ai_response',
type: 'objectReference',
values: 'ai_response',
display: 'Source AI Response',
locked: true
},
{ name: 'created_by', type: 'string', locked: true },
{
name: 'lineage',
type: 'rendering',
hidden: false,
run:function(item){
console.log(item.lineage);
return JSON.stringify(item.lineage, null, 2);
},
comment: 'Provenance for this thought (ai_response_id, created_by, created_at, reviewed_by, reviewed_at, etc.).'
},
{ section_end: 'lineage' },
{ sidebar_start:'right'},
'status',
'tags',
{ sidebar_end:'right'},
{ section_start: 'system', collapsed: true },
'_id',
'created',
'itemtype',
{ section_end: 'system' }
],
// Populate derived helper fields on load
onload: function (dataset) {
if (!Array.isArray(dataset)) {
return;
}
dataset.map(function (t) {
if (Array.isArray(t.about)) {
var types = t.about.map(function (a) { return a && a.itemtype; }).filter(Boolean);
// Deduplicate
t.about_itemtypes = Array.from(new Set(types));
}
});
},
idprop: '_id'
};
module.exports = thought;