json-object-editor 0.10.400 → 0.10.422
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/js/JsonObjectEditor.jquery.craydent.js +11 -2
- package/js/joe-ai.js +376 -0
- package/js/joe-full.js +11 -2
- package/js/joe.js +11 -2
- package/package.json +1 -1
- package/pages/template.html +2 -0
- package/server/fields/core.js +22 -0
- package/server/schemas/ai_conversation.js +84 -0
- package/web-components/joe-button.js +1 -1
|
@@ -534,9 +534,11 @@ function JsonObjectEditor(specs){
|
|
|
534
534
|
var code = e.keyCode
|
|
535
535
|
var nonBackElements = ['input','select','textarea'];
|
|
536
536
|
var isInputElement = nonBackElements.indexOf(e.target.tagName.toLowerCase()) != -1;
|
|
537
|
+
var isEditable = e.target.isContentEditable || $(e.target).closest('joe-ai-chatbox').length;
|
|
538
|
+
|
|
537
539
|
if (code == 8) {//BACKBUTTON PRESSED
|
|
538
|
-
if(isInputElement){
|
|
539
|
-
|
|
540
|
+
if(isInputElement || isEditable){
|
|
541
|
+
return; // allow natural Backspace behavior
|
|
540
542
|
}
|
|
541
543
|
else{
|
|
542
544
|
self.goBack();
|
|
@@ -5766,6 +5768,7 @@ Y | Object Field
|
|
|
5766
5768
|
|
|
5767
5769
|
var display = self.propAsFuncOrValue(prop.display, itemObj);
|
|
5768
5770
|
var method = self.propAsFuncOrValue(prop.method, itemObj);
|
|
5771
|
+
var onclick = self.propAsFuncOrValue(prop.onclick, itemObj);
|
|
5769
5772
|
var color = self.propAsFuncOrValue(prop.color, itemObj);
|
|
5770
5773
|
var schema = self.propAsFuncOrValue(prop.schema, itemObj);
|
|
5771
5774
|
var svgOverride = self.propAsFuncOrValue(prop.svg, itemObj);
|
|
@@ -5794,6 +5797,7 @@ Y | Object Field
|
|
|
5794
5797
|
+ (method ? 'action="' + method + '" ' : '')
|
|
5795
5798
|
+ (color ? 'color="' + color + '" ' : '')
|
|
5796
5799
|
+ (title ? 'title="' + title + '" ' : '')
|
|
5800
|
+
+(onclick ? 'onclick="' + onclick + '" ' : '')
|
|
5797
5801
|
+ styleAttr + ' '
|
|
5798
5802
|
+ 'data-btnid="' + (prop.name || '') + '">';
|
|
5799
5803
|
|
|
@@ -10460,6 +10464,11 @@ logit(intent)
|
|
|
10460
10464
|
<--------------------------------------------------------------------*/
|
|
10461
10465
|
this.SVG = {
|
|
10462
10466
|
icon:{
|
|
10467
|
+
assistant:`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
|
10468
|
+
<path d="M294.49 618.18v64.49c0 22.42.95 35.46 2.84 39.12 2.4 4.94 6.93 8.52 12.29 9.71 9.18 2.13 18.6 3.01 28.02 2.64h17.31c18.81 0 28.22 6.04 28.22 18.11 0 13.96-9.93 22.51-29.8 25.64-24.41 2.74-48.98 3.87-73.55 3.37-29.87 0-51.01-5.79-63.44-17.38-12.42-11.59-18.66-31.41-18.7-59.47v-81.08c.85-11.33-1.15-22.68-5.81-33.04-5.69-7.66-14.07-12.88-23.46-14.6-11.09-2.78-18.54-13.19-17.58-24.58-1.07-11.43 6.42-21.9 17.58-24.58 9.41-1.95 17.77-7.32 23.46-15.07 4.7-10.35 6.7-21.71 5.81-33.04v-80.88c0-27.62 6.21-47.22 18.63-58.81 12.42-11.59 33.57-17.36 63.44-17.31 26.13-.73 52.27.66 78.17 4.16 6.92 1.05 13.37 4.16 18.5 8.92 4.27 4.08 6.66 9.75 6.61 15.66 0 12.07-9.41 18.11-28.22 18.11h-17.84c-16.04 0-27.05 1.72-33.04 5.15-5.92 3.96-9.36 10.72-9.05 17.84v92.71c-.35 31.23-8.72 52.03-25.11 62.38-1.29.88-2.06 2.34-2.05 3.9 0 2.42 2.93 6.06 8.79 10.9 6.54 5.96 11.3 13.63 13.74 22.14 3.19 11.34 4.62 23.11 4.23 34.89Zm435.01-134.4v-64.23c0-22.42-.95-35.46-2.84-39.12-2.4-4.94-6.93-8.52-12.29-9.71-9.18-2.13-18.6-3.01-28.02-2.64h-17.18c-18.81 0-28.22-6.04-28.22-18.11 0-13.96 9.93-22.42 29.8-25.37 24.42-2.73 48.98-3.86 73.55-3.37 29.87 0 51.01 5.79 63.44 17.38 12.42 11.59 18.63 31.19 18.63 58.81v81.28c-.88 11.33 1.12 22.69 5.81 33.04 5.75 7.62 14.1 12.87 23.46 14.74 11.16 2.71 18.62 13.22 17.51 24.65.74 9.18-4.03 17.93-12.16 22.27-4.09 1.86-8.33 3.34-12.69 4.43-8.51 2.69-15.35 9.08-18.63 17.38-2.71 9.15-3.85 18.69-3.37 28.22v81.01c0 27.8-6.21 47.47-18.63 59.01-12.42 11.54-33.57 17.33-63.44 17.38-26.13.74-52.27-.65-78.17-4.16-6.92-1.05-13.37-4.16-18.5-8.92-4.31-4.17-6.7-9.93-6.61-15.93 0-12.07 9.41-18.11 28.22-18.11 2.25 0 8.19.18 17.84.53 11.25.56 22.5-1.19 33.04-5.15 4.1-2.12 7.02-5.98 7.93-10.51 1.33-11.91 1.82-23.9 1.45-35.88v-64.49c-.51-12.88 1.38-25.74 5.55-37.93 4.19-9.77 11.07-18.15 19.82-24.18 1.29-.88 2.06-2.34 2.05-3.9 0-2.42-2.93-6.06-8.79-10.9-6.55-5.96-11.31-13.63-13.74-22.14-3.43-11.46-5.05-23.39-4.82-35.35Z"/>
|
|
10469
|
+
<rect width="74.5" height="189" x="409.75" y="456.75" rx="33.94" ry="33.94"/>
|
|
10470
|
+
<rect width="74.5" height="189" x="539.75" y="456.75" rx="33.94" ry="33.94"/>
|
|
10471
|
+
</svg>`,
|
|
10463
10472
|
'favorite':'<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M4 2h16a1 1 0 0 1 1 1v19.276a.5.5 0 0 1-.704.457L12 19.03l-8.296 3.702A.5.5 0 0 1 3 22.276V3a1 1 0 0 1 1-1zm8 11.5l2.939 1.545-.561-3.272 2.377-2.318-3.286-.478L12 6l-1.47 2.977-3.285.478 2.377 2.318-.56 3.272L12 13.5z"/></svg>',
|
|
10464
10473
|
'left':'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 36 36"><path d="M11.3 21C7.1 18.2 3.3 13.8 3.2 13.6 3.1 13.5 3 13.2 3 13 3 12.8 3.1 12.5 3.2 12.3 3.3 12.1 7.2 7.7 11.3 4.9 11.6 4.7 12 4.7 12.4 4.8 12.8 5.1 13 5.4 13 5.8L13 9.5C13 9.5 21.7 10 22.1 10.3 22.7 10.7 23 12 23 13 23 14.1 22.6 15.2 22.1 15.6 21.7 15.9 13 16.5 13 16.5L13 20.2C13 20.6 12.8 20.9 12.4 21.1 12.1 21.3 11.7 21.2 11.3 21Z"/></svg>',
|
|
10465
10474
|
'cancel':'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 36 36"><path d="M13 0.2C5.9 0.2 0.2 5.9 0.2 13 0.2 20.1 5.9 25.8 13 25.8 20.1 25.8 25.8 20.1 25.8 13 25.8 5.9 20.1 0.2 13 0.2ZM18.8 17.4L17.4 18.8C17.1 19 16.7 19 16.5 18.8L13 15.3 9.5 18.8C9.3 19 8.9 19 8.6 18.8L7.2 17.4C7 17.1 7 16.7 7.2 16.5L10.7 13 7.2 9.5C7 9.3 7 8.9 7.2 8.6L8.6 7.2C8.9 7 9.3 7 9.5 7.2L13 10.7 16.5 7.2C16.7 7 17.1 7 17.4 7.2L18.8 8.6C19 8.9 19 9.3 18.8 9.5L15.3 13 18.8 16.5C19 16.7 19 17.1 18.8 17.4Z"/></svg>',
|
package/js/joe-ai.js
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
(function(){
|
|
2
|
+
// Define the joeAI namespace
|
|
3
|
+
const Ai = {};
|
|
4
|
+
|
|
5
|
+
Ai._openChats = {}; // Conversation ID -> element
|
|
6
|
+
// ========== COMPONENTS ==========
|
|
7
|
+
|
|
8
|
+
class JoeAIChatbox extends HTMLElement {
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
this.attachShadow({ mode: 'open' });
|
|
12
|
+
this.messages = [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
connectedCallback() {
|
|
16
|
+
this.conversation_id = this.getAttribute('conversation_id');
|
|
17
|
+
this.selected_assistant_id = null;
|
|
18
|
+
this.ui = {};
|
|
19
|
+
if (!this.conversation_id) {
|
|
20
|
+
this.renderError("Missing conversation_id");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this.loadConversation();
|
|
24
|
+
this.getAllAssistants();
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
async getAllAssistants() {
|
|
28
|
+
const res = await fetch('/API/item/ai_assistant');
|
|
29
|
+
const result = await res.json();
|
|
30
|
+
if (result.error) {
|
|
31
|
+
console.error("Error fetching assistants:", result.error);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this.allAssistants = {};
|
|
35
|
+
|
|
36
|
+
if (Array.isArray(result.item)) {
|
|
37
|
+
result.item.map(a => {
|
|
38
|
+
if (a._id) {
|
|
39
|
+
this.allAssistants[a._id] = a;
|
|
40
|
+
}
|
|
41
|
+
if (a.openai_id) {
|
|
42
|
+
this.allAssistants[a.openai_id] = a; // Optional dual-key if you prefer
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
}
|
|
48
|
+
async loadConversation() {
|
|
49
|
+
try {
|
|
50
|
+
const res = await fetch(`/API/object/ai_conversation/_id/${this.conversation_id}`);
|
|
51
|
+
const convo = await res.json();
|
|
52
|
+
|
|
53
|
+
if (!convo || convo.error) {
|
|
54
|
+
this.renderError("Conversation not found.");
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
this.conversation = convo;
|
|
58
|
+
this.messages = [];
|
|
59
|
+
|
|
60
|
+
if (convo.thread_id) {
|
|
61
|
+
const resThread = await fetch(`/API/plugin/chatgpt-assistants/getThreadMessages?thread_id=${convo.thread_id}`);
|
|
62
|
+
const threadMessages = await resThread.json();
|
|
63
|
+
this.messages = threadMessages?.messages || [];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
this.render();
|
|
67
|
+
} catch (err) {
|
|
68
|
+
console.error("Chatbox load error:", err);
|
|
69
|
+
this.renderError("Error loading conversation.");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
getAssistantInfo(id){
|
|
73
|
+
const assistant = this.allAssistants[id];
|
|
74
|
+
if (assistant) {
|
|
75
|
+
return assistant;
|
|
76
|
+
} else {
|
|
77
|
+
console.warn("Assistant not found:", id);
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
render() {
|
|
82
|
+
const convoName = this.conversation.name || "Untitled Conversation";
|
|
83
|
+
const convoInfo = this.conversation.info || "";
|
|
84
|
+
|
|
85
|
+
const chatMessages = this.messages.map(msg => this.renderMessage(msg)).reverse().join('');
|
|
86
|
+
|
|
87
|
+
const assistantOptions = (this.conversation.assistants || []).map(a => {
|
|
88
|
+
const meta = this.getAssistantInfo(a) || {};
|
|
89
|
+
|
|
90
|
+
const label = meta.name || a.name || a.title || 'Assistant';
|
|
91
|
+
const value = meta._id;
|
|
92
|
+
const selected = value === this.selected_assistant_id ? 'selected' : '';
|
|
93
|
+
|
|
94
|
+
return `<option value="${value}" ${selected}>${label}</option>`;
|
|
95
|
+
}).join('');
|
|
96
|
+
|
|
97
|
+
const assistantSelect = `
|
|
98
|
+
<label-select-wrapper>
|
|
99
|
+
<label class="assistant-select-label" title="joe ai assistants">${_joe && _joe.SVG.icon.assistant}</label>
|
|
100
|
+
<select id="assistant-select">
|
|
101
|
+
${assistantOptions}
|
|
102
|
+
</select>
|
|
103
|
+
</label-select-wrapper>
|
|
104
|
+
`;
|
|
105
|
+
|
|
106
|
+
this.shadowRoot.innerHTML = `
|
|
107
|
+
<style>
|
|
108
|
+
|
|
109
|
+
.chatbox {
|
|
110
|
+
padding:10px; display:flex; flex-direction:column; height:100%;
|
|
111
|
+
}
|
|
112
|
+
.close-btn {
|
|
113
|
+
position: absolute;
|
|
114
|
+
top: 8px;
|
|
115
|
+
right: 8px;
|
|
116
|
+
width: 24px;
|
|
117
|
+
height: 24px;
|
|
118
|
+
cursor: pointer;
|
|
119
|
+
}
|
|
120
|
+
.close-btn svg { width:100%; height:100%; }
|
|
121
|
+
.header { margin-bottom:10px; }
|
|
122
|
+
.header h2 { margin:0; font-size:18px; }
|
|
123
|
+
.header p { margin:4px 0 0 0; font-size:12px; color:#666; }
|
|
124
|
+
.header svg{
|
|
125
|
+
width: 36px;
|
|
126
|
+
height: 36px;
|
|
127
|
+
}
|
|
128
|
+
label-select-wrapper{
|
|
129
|
+
display: flex; align-items: center; gap: 8px;
|
|
130
|
+
}
|
|
131
|
+
.messages { flex:1; overflow:auto; max-height:300px; margin-bottom:10px;
|
|
132
|
+
background: #fff;
|
|
133
|
+
border: 1px solid #ccc;
|
|
134
|
+
}
|
|
135
|
+
.thinking-message {
|
|
136
|
+
font-size: 13px;
|
|
137
|
+
color: #888;
|
|
138
|
+
font-style: italic;
|
|
139
|
+
margin: 10px 0;
|
|
140
|
+
text-align: center;
|
|
141
|
+
}
|
|
142
|
+
.meta {
|
|
143
|
+
font-size: 14px;
|
|
144
|
+
font-weight: bold;
|
|
145
|
+
margin-bottom: 2px;
|
|
146
|
+
display: flex;
|
|
147
|
+
align-items: center;
|
|
148
|
+
gap: 8px;
|
|
149
|
+
color:#99999999;
|
|
150
|
+
}
|
|
151
|
+
.content {
|
|
152
|
+
font-size: 14px;
|
|
153
|
+
white-space: pre-wrap;
|
|
154
|
+
}
|
|
155
|
+
.inputRow { display:flex; gap:8px; }
|
|
156
|
+
input[type="text"] { flex:1; padding:8px; border-radius:4px; border:1px solid #ccc; }
|
|
157
|
+
button { padding:8px 12px; background:#007bff; color:white; border:none; border-radius:4px; cursor:pointer; }
|
|
158
|
+
button:disabled { opacity:0.5; cursor:default; }
|
|
159
|
+
.message { margin-bottom:10px; padding:8px; border-radius:6px; background:#f5f5f5; }
|
|
160
|
+
.message.assistant { background:#eef; }
|
|
161
|
+
.message.system { background:#fee; }
|
|
162
|
+
</style>
|
|
163
|
+
|
|
164
|
+
<div class="chatbox">
|
|
165
|
+
<div class="close-btn" title="Close Chatbox">
|
|
166
|
+
${_joe.SVG.icon.close}
|
|
167
|
+
</div>
|
|
168
|
+
<div class="header">
|
|
169
|
+
<h2>${convoName}</h2>
|
|
170
|
+
<p>${convoInfo}</p>
|
|
171
|
+
${assistantSelect}
|
|
172
|
+
</div>
|
|
173
|
+
<div class="messages">
|
|
174
|
+
${chatMessages}
|
|
175
|
+
</div>
|
|
176
|
+
<div class="inputRow">
|
|
177
|
+
<input id="chat-input" type="text" placeholder="Type a message..." />
|
|
178
|
+
<button id="send-button">Send</button>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
`;
|
|
182
|
+
const messagesDiv = this.shadowRoot.querySelector('.messages');
|
|
183
|
+
messagesDiv.scrollTop = messagesDiv.scrollHeight;
|
|
184
|
+
this.shadowRoot.getElementById('send-button').addEventListener('click', () => this.sendMessage());
|
|
185
|
+
|
|
186
|
+
// Wire up the close button
|
|
187
|
+
this.shadowRoot.querySelector('.close-btn').addEventListener('click', () => this.closeChat());
|
|
188
|
+
this.ui.assistant_select = this.shadowRoot.querySelector('#assistant-select');
|
|
189
|
+
this.ui.assistant_select?.addEventListener('change', (e) => {
|
|
190
|
+
this.selected_assistant_id = e.target.value;
|
|
191
|
+
});
|
|
192
|
+
this.selected_assistant_id = this.ui.assistant_select?.value || null;
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
renderMessage(msg) {
|
|
197
|
+
const role = msg.role || 'user';
|
|
198
|
+
const classes = `message ${role}`;
|
|
199
|
+
|
|
200
|
+
let contentText = '';
|
|
201
|
+
|
|
202
|
+
if (Array.isArray(msg.content)) {
|
|
203
|
+
// OpenAI style: array of parts
|
|
204
|
+
contentText = msg.content.map(part => {
|
|
205
|
+
if (part.type === 'text' && part.text && part.text.value) {
|
|
206
|
+
return part.text.value;
|
|
207
|
+
}
|
|
208
|
+
return '';
|
|
209
|
+
}).join('\n');
|
|
210
|
+
} else if (typeof msg.content === 'string') {
|
|
211
|
+
contentText = msg.content;
|
|
212
|
+
} else {
|
|
213
|
+
contentText = '[Unsupported message format]';
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Build timestamp
|
|
217
|
+
const createdAt = msg.created_at ? new Date(msg.created_at * 1000) : null; // OpenAI sends timestamps in seconds
|
|
218
|
+
const timestamp = createdAt ? createdAt.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : '';
|
|
219
|
+
|
|
220
|
+
return `
|
|
221
|
+
<div class="${classes}">
|
|
222
|
+
<div class="meta"><strong>${role.toUpperCase()}</strong> ${timestamp ? `<span class="timestamp">${timestamp}</span>` : ''}</div>
|
|
223
|
+
<div class="content">${contentText}</div>
|
|
224
|
+
</div>
|
|
225
|
+
`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
renderError(message) {
|
|
229
|
+
this.shadowRoot.innerHTML = `<div style="color:red;">${message}</div>`;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async sendMessage() {
|
|
233
|
+
const input = this.shadowRoot.getElementById('chat-input');
|
|
234
|
+
const message = input.value.trim();
|
|
235
|
+
if (!message) return;
|
|
236
|
+
|
|
237
|
+
input.disabled = true;
|
|
238
|
+
this.shadowRoot.getElementById('send-button').disabled = true;
|
|
239
|
+
|
|
240
|
+
try {
|
|
241
|
+
const response = await fetch('/API/plugin/chatgpt-assistants/addMessage', {
|
|
242
|
+
method: 'POST',
|
|
243
|
+
headers: { 'Content-Type': 'application/json' },
|
|
244
|
+
body: JSON.stringify({
|
|
245
|
+
conversation_id: this.conversation_id,
|
|
246
|
+
content: message,
|
|
247
|
+
assistant_id: this.selected_assistant_id
|
|
248
|
+
})
|
|
249
|
+
}).then(res => res.json());
|
|
250
|
+
|
|
251
|
+
if (response.success && response.runObj) {
|
|
252
|
+
this.currentRunId = response.runObj.id; // Store the run ID for polling
|
|
253
|
+
await this.loadConversation(); // reload messages
|
|
254
|
+
this.startPolling(); // 🌸 start watching for assistant reply!
|
|
255
|
+
} else {
|
|
256
|
+
alert('Failed to send message.');
|
|
257
|
+
}
|
|
258
|
+
} catch (err) {
|
|
259
|
+
console.error('Send message error:', err);
|
|
260
|
+
alert('Error sending message.');
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
input.value = '';
|
|
264
|
+
input.disabled = false;
|
|
265
|
+
this.shadowRoot.getElementById('send-button').disabled = false;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
startPolling() {
|
|
269
|
+
if (this.pollingInterval) return; // Already polling
|
|
270
|
+
|
|
271
|
+
// Insert thinking message
|
|
272
|
+
this.showThinkingMessage();
|
|
273
|
+
|
|
274
|
+
this.pollingInterval = setInterval(async () => {
|
|
275
|
+
const runRes = await fetch(`/API/plugin/chatgpt-assistants/getRunStatus?thread_id=${this.conversation.thread_id}&run_id=${this.currentRunId}`);
|
|
276
|
+
const run = await runRes.json();
|
|
277
|
+
|
|
278
|
+
if (run.status === 'completed') {
|
|
279
|
+
const resThread = await fetch(`/API/plugin/chatgpt-assistants/getThreadMessages?thread_id=${this.conversation.thread_id}`);
|
|
280
|
+
//const activeAssistant = this.conversation.assistants.find(a => a.openai_id === run.assistant_id);
|
|
281
|
+
const threadMessages = await resThread.json();
|
|
282
|
+
|
|
283
|
+
if (threadMessages?.messages) {
|
|
284
|
+
this.messages = threadMessages.messages;
|
|
285
|
+
this.render();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
clearInterval(this.pollingInterval);
|
|
289
|
+
this.pollingInterval = null;
|
|
290
|
+
this.hideThinkingMessage();
|
|
291
|
+
}
|
|
292
|
+
}, 2000);
|
|
293
|
+
}
|
|
294
|
+
showThinkingMessage() {
|
|
295
|
+
const messagesDiv = this.shadowRoot.querySelector('.messages');
|
|
296
|
+
if (!messagesDiv) return;
|
|
297
|
+
|
|
298
|
+
// Pull assistant thinking text
|
|
299
|
+
const assistant = this.getAssistantInfo(this.selected_assistant_id);
|
|
300
|
+
const thinkingText = assistant?.assistant_thinking_text || 'Assistant is thinking...';
|
|
301
|
+
|
|
302
|
+
const div = document.createElement('div');
|
|
303
|
+
div.className = 'thinking-message';
|
|
304
|
+
div.textContent = thinkingText;
|
|
305
|
+
div.id = 'thinking-message';
|
|
306
|
+
messagesDiv.appendChild(div);
|
|
307
|
+
|
|
308
|
+
messagesDiv.scrollTop = messagesDiv.scrollHeight;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
hideThinkingMessage() {
|
|
312
|
+
const existing = this.shadowRoot.querySelector('#thinking-message');
|
|
313
|
+
if (existing) existing.remove();
|
|
314
|
+
}
|
|
315
|
+
closeChat() {
|
|
316
|
+
// Remove the element
|
|
317
|
+
this.remove();
|
|
318
|
+
|
|
319
|
+
// Clean up from open chat registry if possible
|
|
320
|
+
if (_joe && _joe.Ai && _joe.Ai._openChats) {
|
|
321
|
+
delete _joe.Ai._openChats[this.conversation_id];
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
customElements.define('joe-ai-chatbox', JoeAIChatbox);
|
|
327
|
+
|
|
328
|
+
// ========== HELPERS ==========
|
|
329
|
+
|
|
330
|
+
Ai.spawnChat = function(conversationId, options = {}) {
|
|
331
|
+
if (!conversationId) {
|
|
332
|
+
console.warn("Missing conversation ID for chat spawn.");
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// 1. Check if chatbox already open
|
|
337
|
+
if (Ai._openChats[conversationId]) {
|
|
338
|
+
console.log("Chatbox already open for", conversationId);
|
|
339
|
+
Ai._openChats[conversationId].scrollIntoView({ behavior: 'smooth', block: 'center' });
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// 2. Create new chatbox
|
|
344
|
+
const chat = document.createElement('joe-ai-chatbox');
|
|
345
|
+
chat.setAttribute('conversation_id', conversationId);
|
|
346
|
+
|
|
347
|
+
// Apply styles
|
|
348
|
+
chat.style.width = options.width || '400px';
|
|
349
|
+
chat.style.height = options.height || '420px';
|
|
350
|
+
chat.style.bottom = options.bottom || '20px';
|
|
351
|
+
chat.style.right = options.right || '20px';
|
|
352
|
+
chat.style.position = 'fixed';
|
|
353
|
+
chat.style.zIndex = '10000';
|
|
354
|
+
chat.style.background = '#efefef';
|
|
355
|
+
chat.style.border = '1px solid #fff';
|
|
356
|
+
chat.style.borderRadius = '8px';
|
|
357
|
+
chat.style.boxShadow = '0px 2px 10px rgba(0,0,0,0.1)';
|
|
358
|
+
chat.style.padding = '5px';
|
|
359
|
+
|
|
360
|
+
document.body.appendChild(chat);
|
|
361
|
+
|
|
362
|
+
// 3. Track it
|
|
363
|
+
Ai._openChats[conversationId] = chat;
|
|
364
|
+
return chat;
|
|
365
|
+
// 4. Optionally clean up when chatbox is removed (if you wire close buttons later)
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// Attach AI to _joe
|
|
369
|
+
if (window._joe) {
|
|
370
|
+
_joe.Ai = Ai;
|
|
371
|
+
} else {
|
|
372
|
+
console.warn('joeAI.js loaded before _joe was ready.');
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
})();
|
|
376
|
+
|
package/js/joe-full.js
CHANGED
|
@@ -11839,9 +11839,11 @@ function JsonObjectEditor(specs){
|
|
|
11839
11839
|
var code = e.keyCode
|
|
11840
11840
|
var nonBackElements = ['input','select','textarea'];
|
|
11841
11841
|
var isInputElement = nonBackElements.indexOf(e.target.tagName.toLowerCase()) != -1;
|
|
11842
|
+
var isEditable = e.target.isContentEditable || $(e.target).closest('joe-ai-chatbox').length;
|
|
11843
|
+
|
|
11842
11844
|
if (code == 8) {//BACKBUTTON PRESSED
|
|
11843
|
-
if(isInputElement){
|
|
11844
|
-
|
|
11845
|
+
if(isInputElement || isEditable){
|
|
11846
|
+
return; // allow natural Backspace behavior
|
|
11845
11847
|
}
|
|
11846
11848
|
else{
|
|
11847
11849
|
self.goBack();
|
|
@@ -17071,6 +17073,7 @@ Y | Object Field
|
|
|
17071
17073
|
|
|
17072
17074
|
var display = self.propAsFuncOrValue(prop.display, itemObj);
|
|
17073
17075
|
var method = self.propAsFuncOrValue(prop.method, itemObj);
|
|
17076
|
+
var onclick = self.propAsFuncOrValue(prop.onclick, itemObj);
|
|
17074
17077
|
var color = self.propAsFuncOrValue(prop.color, itemObj);
|
|
17075
17078
|
var schema = self.propAsFuncOrValue(prop.schema, itemObj);
|
|
17076
17079
|
var svgOverride = self.propAsFuncOrValue(prop.svg, itemObj);
|
|
@@ -17099,6 +17102,7 @@ Y | Object Field
|
|
|
17099
17102
|
+ (method ? 'action="' + method + '" ' : '')
|
|
17100
17103
|
+ (color ? 'color="' + color + '" ' : '')
|
|
17101
17104
|
+ (title ? 'title="' + title + '" ' : '')
|
|
17105
|
+
+(onclick ? 'onclick="' + onclick + '" ' : '')
|
|
17102
17106
|
+ styleAttr + ' '
|
|
17103
17107
|
+ 'data-btnid="' + (prop.name || '') + '">';
|
|
17104
17108
|
|
|
@@ -21765,6 +21769,11 @@ logit(intent)
|
|
|
21765
21769
|
<--------------------------------------------------------------------*/
|
|
21766
21770
|
this.SVG = {
|
|
21767
21771
|
icon:{
|
|
21772
|
+
assistant:`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
|
21773
|
+
<path d="M294.49 618.18v64.49c0 22.42.95 35.46 2.84 39.12 2.4 4.94 6.93 8.52 12.29 9.71 9.18 2.13 18.6 3.01 28.02 2.64h17.31c18.81 0 28.22 6.04 28.22 18.11 0 13.96-9.93 22.51-29.8 25.64-24.41 2.74-48.98 3.87-73.55 3.37-29.87 0-51.01-5.79-63.44-17.38-12.42-11.59-18.66-31.41-18.7-59.47v-81.08c.85-11.33-1.15-22.68-5.81-33.04-5.69-7.66-14.07-12.88-23.46-14.6-11.09-2.78-18.54-13.19-17.58-24.58-1.07-11.43 6.42-21.9 17.58-24.58 9.41-1.95 17.77-7.32 23.46-15.07 4.7-10.35 6.7-21.71 5.81-33.04v-80.88c0-27.62 6.21-47.22 18.63-58.81 12.42-11.59 33.57-17.36 63.44-17.31 26.13-.73 52.27.66 78.17 4.16 6.92 1.05 13.37 4.16 18.5 8.92 4.27 4.08 6.66 9.75 6.61 15.66 0 12.07-9.41 18.11-28.22 18.11h-17.84c-16.04 0-27.05 1.72-33.04 5.15-5.92 3.96-9.36 10.72-9.05 17.84v92.71c-.35 31.23-8.72 52.03-25.11 62.38-1.29.88-2.06 2.34-2.05 3.9 0 2.42 2.93 6.06 8.79 10.9 6.54 5.96 11.3 13.63 13.74 22.14 3.19 11.34 4.62 23.11 4.23 34.89Zm435.01-134.4v-64.23c0-22.42-.95-35.46-2.84-39.12-2.4-4.94-6.93-8.52-12.29-9.71-9.18-2.13-18.6-3.01-28.02-2.64h-17.18c-18.81 0-28.22-6.04-28.22-18.11 0-13.96 9.93-22.42 29.8-25.37 24.42-2.73 48.98-3.86 73.55-3.37 29.87 0 51.01 5.79 63.44 17.38 12.42 11.59 18.63 31.19 18.63 58.81v81.28c-.88 11.33 1.12 22.69 5.81 33.04 5.75 7.62 14.1 12.87 23.46 14.74 11.16 2.71 18.62 13.22 17.51 24.65.74 9.18-4.03 17.93-12.16 22.27-4.09 1.86-8.33 3.34-12.69 4.43-8.51 2.69-15.35 9.08-18.63 17.38-2.71 9.15-3.85 18.69-3.37 28.22v81.01c0 27.8-6.21 47.47-18.63 59.01-12.42 11.54-33.57 17.33-63.44 17.38-26.13.74-52.27-.65-78.17-4.16-6.92-1.05-13.37-4.16-18.5-8.92-4.31-4.17-6.7-9.93-6.61-15.93 0-12.07 9.41-18.11 28.22-18.11 2.25 0 8.19.18 17.84.53 11.25.56 22.5-1.19 33.04-5.15 4.1-2.12 7.02-5.98 7.93-10.51 1.33-11.91 1.82-23.9 1.45-35.88v-64.49c-.51-12.88 1.38-25.74 5.55-37.93 4.19-9.77 11.07-18.15 19.82-24.18 1.29-.88 2.06-2.34 2.05-3.9 0-2.42-2.93-6.06-8.79-10.9-6.55-5.96-11.31-13.63-13.74-22.14-3.43-11.46-5.05-23.39-4.82-35.35Z"/>
|
|
21774
|
+
<rect width="74.5" height="189" x="409.75" y="456.75" rx="33.94" ry="33.94"/>
|
|
21775
|
+
<rect width="74.5" height="189" x="539.75" y="456.75" rx="33.94" ry="33.94"/>
|
|
21776
|
+
</svg>`,
|
|
21768
21777
|
'favorite':'<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M4 2h16a1 1 0 0 1 1 1v19.276a.5.5 0 0 1-.704.457L12 19.03l-8.296 3.702A.5.5 0 0 1 3 22.276V3a1 1 0 0 1 1-1zm8 11.5l2.939 1.545-.561-3.272 2.377-2.318-3.286-.478L12 6l-1.47 2.977-3.285.478 2.377 2.318-.56 3.272L12 13.5z"/></svg>',
|
|
21769
21778
|
'left':'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 36 36"><path d="M11.3 21C7.1 18.2 3.3 13.8 3.2 13.6 3.1 13.5 3 13.2 3 13 3 12.8 3.1 12.5 3.2 12.3 3.3 12.1 7.2 7.7 11.3 4.9 11.6 4.7 12 4.7 12.4 4.8 12.8 5.1 13 5.4 13 5.8L13 9.5C13 9.5 21.7 10 22.1 10.3 22.7 10.7 23 12 23 13 23 14.1 22.6 15.2 22.1 15.6 21.7 15.9 13 16.5 13 16.5L13 20.2C13 20.6 12.8 20.9 12.4 21.1 12.1 21.3 11.7 21.2 11.3 21Z"/></svg>',
|
|
21770
21779
|
'cancel':'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 36 36"><path d="M13 0.2C5.9 0.2 0.2 5.9 0.2 13 0.2 20.1 5.9 25.8 13 25.8 20.1 25.8 25.8 20.1 25.8 13 25.8 5.9 20.1 0.2 13 0.2ZM18.8 17.4L17.4 18.8C17.1 19 16.7 19 16.5 18.8L13 15.3 9.5 18.8C9.3 19 8.9 19 8.6 18.8L7.2 17.4C7 17.1 7 16.7 7.2 16.5L10.7 13 7.2 9.5C7 9.3 7 8.9 7.2 8.6L8.6 7.2C8.9 7 9.3 7 9.5 7.2L13 10.7 16.5 7.2C16.7 7 17.1 7 17.4 7.2L18.8 8.6C19 8.9 19 9.3 18.8 9.5L15.3 13 18.8 16.5C19 16.7 19 17.1 18.8 17.4Z"/></svg>',
|
package/js/joe.js
CHANGED
|
@@ -540,9 +540,11 @@ function JsonObjectEditor(specs){
|
|
|
540
540
|
var code = e.keyCode
|
|
541
541
|
var nonBackElements = ['input','select','textarea'];
|
|
542
542
|
var isInputElement = nonBackElements.indexOf(e.target.tagName.toLowerCase()) != -1;
|
|
543
|
+
var isEditable = e.target.isContentEditable || $(e.target).closest('joe-ai-chatbox').length;
|
|
544
|
+
|
|
543
545
|
if (code == 8) {//BACKBUTTON PRESSED
|
|
544
|
-
if(isInputElement){
|
|
545
|
-
|
|
546
|
+
if(isInputElement || isEditable){
|
|
547
|
+
return; // allow natural Backspace behavior
|
|
546
548
|
}
|
|
547
549
|
else{
|
|
548
550
|
self.goBack();
|
|
@@ -5772,6 +5774,7 @@ Y | Object Field
|
|
|
5772
5774
|
|
|
5773
5775
|
var display = self.propAsFuncOrValue(prop.display, itemObj);
|
|
5774
5776
|
var method = self.propAsFuncOrValue(prop.method, itemObj);
|
|
5777
|
+
var onclick = self.propAsFuncOrValue(prop.onclick, itemObj);
|
|
5775
5778
|
var color = self.propAsFuncOrValue(prop.color, itemObj);
|
|
5776
5779
|
var schema = self.propAsFuncOrValue(prop.schema, itemObj);
|
|
5777
5780
|
var svgOverride = self.propAsFuncOrValue(prop.svg, itemObj);
|
|
@@ -5800,6 +5803,7 @@ Y | Object Field
|
|
|
5800
5803
|
+ (method ? 'action="' + method + '" ' : '')
|
|
5801
5804
|
+ (color ? 'color="' + color + '" ' : '')
|
|
5802
5805
|
+ (title ? 'title="' + title + '" ' : '')
|
|
5806
|
+
+(onclick ? 'onclick="' + onclick + '" ' : '')
|
|
5803
5807
|
+ styleAttr + ' '
|
|
5804
5808
|
+ 'data-btnid="' + (prop.name || '') + '">';
|
|
5805
5809
|
|
|
@@ -10466,6 +10470,11 @@ logit(intent)
|
|
|
10466
10470
|
<--------------------------------------------------------------------*/
|
|
10467
10471
|
this.SVG = {
|
|
10468
10472
|
icon:{
|
|
10473
|
+
assistant:`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
|
|
10474
|
+
<path d="M294.49 618.18v64.49c0 22.42.95 35.46 2.84 39.12 2.4 4.94 6.93 8.52 12.29 9.71 9.18 2.13 18.6 3.01 28.02 2.64h17.31c18.81 0 28.22 6.04 28.22 18.11 0 13.96-9.93 22.51-29.8 25.64-24.41 2.74-48.98 3.87-73.55 3.37-29.87 0-51.01-5.79-63.44-17.38-12.42-11.59-18.66-31.41-18.7-59.47v-81.08c.85-11.33-1.15-22.68-5.81-33.04-5.69-7.66-14.07-12.88-23.46-14.6-11.09-2.78-18.54-13.19-17.58-24.58-1.07-11.43 6.42-21.9 17.58-24.58 9.41-1.95 17.77-7.32 23.46-15.07 4.7-10.35 6.7-21.71 5.81-33.04v-80.88c0-27.62 6.21-47.22 18.63-58.81 12.42-11.59 33.57-17.36 63.44-17.31 26.13-.73 52.27.66 78.17 4.16 6.92 1.05 13.37 4.16 18.5 8.92 4.27 4.08 6.66 9.75 6.61 15.66 0 12.07-9.41 18.11-28.22 18.11h-17.84c-16.04 0-27.05 1.72-33.04 5.15-5.92 3.96-9.36 10.72-9.05 17.84v92.71c-.35 31.23-8.72 52.03-25.11 62.38-1.29.88-2.06 2.34-2.05 3.9 0 2.42 2.93 6.06 8.79 10.9 6.54 5.96 11.3 13.63 13.74 22.14 3.19 11.34 4.62 23.11 4.23 34.89Zm435.01-134.4v-64.23c0-22.42-.95-35.46-2.84-39.12-2.4-4.94-6.93-8.52-12.29-9.71-9.18-2.13-18.6-3.01-28.02-2.64h-17.18c-18.81 0-28.22-6.04-28.22-18.11 0-13.96 9.93-22.42 29.8-25.37 24.42-2.73 48.98-3.86 73.55-3.37 29.87 0 51.01 5.79 63.44 17.38 12.42 11.59 18.63 31.19 18.63 58.81v81.28c-.88 11.33 1.12 22.69 5.81 33.04 5.75 7.62 14.1 12.87 23.46 14.74 11.16 2.71 18.62 13.22 17.51 24.65.74 9.18-4.03 17.93-12.16 22.27-4.09 1.86-8.33 3.34-12.69 4.43-8.51 2.69-15.35 9.08-18.63 17.38-2.71 9.15-3.85 18.69-3.37 28.22v81.01c0 27.8-6.21 47.47-18.63 59.01-12.42 11.54-33.57 17.33-63.44 17.38-26.13.74-52.27-.65-78.17-4.16-6.92-1.05-13.37-4.16-18.5-8.92-4.31-4.17-6.7-9.93-6.61-15.93 0-12.07 9.41-18.11 28.22-18.11 2.25 0 8.19.18 17.84.53 11.25.56 22.5-1.19 33.04-5.15 4.1-2.12 7.02-5.98 7.93-10.51 1.33-11.91 1.82-23.9 1.45-35.88v-64.49c-.51-12.88 1.38-25.74 5.55-37.93 4.19-9.77 11.07-18.15 19.82-24.18 1.29-.88 2.06-2.34 2.05-3.9 0-2.42-2.93-6.06-8.79-10.9-6.55-5.96-11.31-13.63-13.74-22.14-3.43-11.46-5.05-23.39-4.82-35.35Z"/>
|
|
10475
|
+
<rect width="74.5" height="189" x="409.75" y="456.75" rx="33.94" ry="33.94"/>
|
|
10476
|
+
<rect width="74.5" height="189" x="539.75" y="456.75" rx="33.94" ry="33.94"/>
|
|
10477
|
+
</svg>`,
|
|
10469
10478
|
'favorite':'<?xml version="1.0" encoding="UTF-8"?><svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="M4 2h16a1 1 0 0 1 1 1v19.276a.5.5 0 0 1-.704.457L12 19.03l-8.296 3.702A.5.5 0 0 1 3 22.276V3a1 1 0 0 1 1-1zm8 11.5l2.939 1.545-.561-3.272 2.377-2.318-3.286-.478L12 6l-1.47 2.977-3.285.478 2.377 2.318-.56 3.272L12 13.5z"/></svg>',
|
|
10470
10479
|
'left':'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 36 36"><path d="M11.3 21C7.1 18.2 3.3 13.8 3.2 13.6 3.1 13.5 3 13.2 3 13 3 12.8 3.1 12.5 3.2 12.3 3.3 12.1 7.2 7.7 11.3 4.9 11.6 4.7 12 4.7 12.4 4.8 12.8 5.1 13 5.4 13 5.8L13 9.5C13 9.5 21.7 10 22.1 10.3 22.7 10.7 23 12 23 13 23 14.1 22.6 15.2 22.1 15.6 21.7 15.9 13 16.5 13 16.5L13 20.2C13 20.6 12.8 20.9 12.4 21.1 12.1 21.3 11.7 21.2 11.3 21Z"/></svg>',
|
|
10471
10480
|
'cancel':'<svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -5 36 36"><path d="M13 0.2C5.9 0.2 0.2 5.9 0.2 13 0.2 20.1 5.9 25.8 13 25.8 20.1 25.8 25.8 20.1 25.8 13 25.8 5.9 20.1 0.2 13 0.2ZM18.8 17.4L17.4 18.8C17.1 19 16.7 19 16.5 18.8L13 15.3 9.5 18.8C9.3 19 8.9 19 8.6 18.8L7.2 17.4C7 17.1 7 16.7 7.2 16.5L10.7 13 7.2 9.5C7 9.3 7 8.9 7.2 8.6L8.6 7.2C8.9 7 9.3 7 9.5 7.2L13 10.7 16.5 7.2C16.7 7 17.1 7 17.4 7.2L18.8 8.6C19 8.9 19 9.3 18.8 9.5L15.3 13 18.8 16.5C19 16.7 19 17.1 18.8 17.4Z"/></svg>',
|
package/package.json
CHANGED
package/pages/template.html
CHANGED
package/server/fields/core.js
CHANGED
|
@@ -68,6 +68,28 @@ var fields = {
|
|
|
68
68
|
'coords':{type:'geo'},
|
|
69
69
|
'state':{type:'select',values:usStates,idprop:'code',template:'${code}',width:'25%',minwidth:'100px',blank:true},
|
|
70
70
|
'name':{type:'text',onblur:'_joe.TITLE.set()'},
|
|
71
|
+
instructions_format:{type:'select',values:['wysiwyg','code'], rerender:'instructions',display:'Instructions Format'},
|
|
72
|
+
instructions:{
|
|
73
|
+
height:'auto',
|
|
74
|
+
display:'Instructions',
|
|
75
|
+
type:function(item){
|
|
76
|
+
if(!item.instructions_format){
|
|
77
|
+
return 'wysiwyg';
|
|
78
|
+
}
|
|
79
|
+
if(["code"].indexOf(item.instructions_format) != -1){
|
|
80
|
+
return 'code';
|
|
81
|
+
}
|
|
82
|
+
return item.instructions_format;
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
ai_model:{
|
|
86
|
+
type: "select",
|
|
87
|
+
display: "Ai Model",
|
|
88
|
+
values: [
|
|
89
|
+
{ value: "gpt-4o", name: "GPT-4o (Current Default)" }
|
|
90
|
+
],
|
|
91
|
+
default: "gpt-4o",
|
|
92
|
+
},
|
|
71
93
|
template:{
|
|
72
94
|
height:'600px',
|
|
73
95
|
type:function(item){
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
var schema = {
|
|
2
|
+
title: "Ai Conversation | ${name}",
|
|
3
|
+
info: "Tracks AI conversations across users, assistants, and external members, storing only summaries for performance.",
|
|
4
|
+
|
|
5
|
+
fields: function() {
|
|
6
|
+
return [
|
|
7
|
+
|
|
8
|
+
"name",
|
|
9
|
+
"info",
|
|
10
|
+
|
|
11
|
+
{ section_start: "participants", display: "Participants", collapsed: false },
|
|
12
|
+
{ name: "user", type: "objectReference", values: "user", display: "JOE User" },
|
|
13
|
+
{ name: "members", type: "objectReference", values: "members", display: "External Members"},
|
|
14
|
+
{ name: "assistants", type: "group", values: function() { return _joe.getDataset('ai_assistant'); }, display: "Assistants", cols:2 },
|
|
15
|
+
{ section_end: "participants" },
|
|
16
|
+
|
|
17
|
+
{ section_start: "thread", display: "Thread", collapsed: true },
|
|
18
|
+
{ name: "thread_id", type: "text", display: "OpenAI Thread ID", locked: true },
|
|
19
|
+
{ section_end: "thread" },
|
|
20
|
+
|
|
21
|
+
{ section_start: "summary", display: "Summary", collapsed: false },
|
|
22
|
+
{ name: "summary", type: "wysiwyg", display: "Conversation Summary", height: "300px", comment: "Auto-generated after key points or closing." },
|
|
23
|
+
{ section_end: "summary" },
|
|
24
|
+
|
|
25
|
+
{ section_start: "linked", display: "Linked Objects", collapsed: true },
|
|
26
|
+
{ name: "linked_objects", type: "objectlist", display: "Linked Objects", fields: [
|
|
27
|
+
{ name: "schema", type: "text", display: "Schema" },
|
|
28
|
+
{ name: "object_id", type: "text", display: "Object ID" }
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{ section_end: "linked" },
|
|
32
|
+
|
|
33
|
+
{ section_start: "system", collapsed: true },
|
|
34
|
+
"_id",
|
|
35
|
+
"created",
|
|
36
|
+
"updated",
|
|
37
|
+
"itemtype",
|
|
38
|
+
{ section_end: "system" },
|
|
39
|
+
|
|
40
|
+
{ sidebar_start: "right", collapsed: false },
|
|
41
|
+
'status',
|
|
42
|
+
"tags",
|
|
43
|
+
{
|
|
44
|
+
name: "openChat",
|
|
45
|
+
type: "button",
|
|
46
|
+
display: "Open Chat",
|
|
47
|
+
icon:"ai_assistant",
|
|
48
|
+
onclick:function(object){
|
|
49
|
+
if (!object || !object._id) return '';
|
|
50
|
+
return `_joe.Ai.spawnChat('${object._id}');`;
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{ sidebar_end: "right" },
|
|
54
|
+
|
|
55
|
+
];
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
idprop: "_id",
|
|
59
|
+
sorter: ["-created"],
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
module.exports = schema;
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* AI Conversation Schema
|
|
67
|
+
*
|
|
68
|
+
* Purpose:
|
|
69
|
+
* - Tracks live AI conversations linked to users, assistants, and external members.
|
|
70
|
+
* - Stores only metadata and final conversation summaries (not full chat messages).
|
|
71
|
+
* - Supports dynamic pulling of live thread content from OpenAI at runtime.
|
|
72
|
+
*
|
|
73
|
+
* Key Concepts:
|
|
74
|
+
* - user: Internal staff or admin account who initiated the conversation.
|
|
75
|
+
* - members: External participants (clients, business users), optional and multiple.
|
|
76
|
+
* - assistants: One or more AI assistants participating in the conversation.
|
|
77
|
+
* - thread_id: The OpenAI thread ID for live runtime message retrieval.
|
|
78
|
+
* - summary: Final AI-generated overview of the conversation (saved on close).
|
|
79
|
+
*
|
|
80
|
+
* Best Practices:
|
|
81
|
+
* - Messages are *not* stored permanently in Joe for performance and privacy.
|
|
82
|
+
* - Summaries provide lightweight snapshots for audits and reviews.
|
|
83
|
+
* - Chat UIs should always fetch full threads from OpenAI at runtime.
|
|
84
|
+
*/
|
|
@@ -55,7 +55,7 @@ class JoeButton extends HTMLElement {
|
|
|
55
55
|
actString = atts.action;
|
|
56
56
|
break;
|
|
57
57
|
}
|
|
58
|
-
this.setAttribute('onclick',actString);
|
|
58
|
+
!this.hasClass('joe-field') && this.setAttribute('onclick',actString);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
var guts = actionPreset?(newHTML|| this.initialHTML):(this.initialHTML || newHTML);
|