@agenticmail/enterprise 0.5.23 → 0.5.25

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/dist/cli.js CHANGED
@@ -48,7 +48,7 @@ Skill Development:
48
48
  break;
49
49
  case "setup":
50
50
  default:
51
- import("./setup-JPW5RJVT.js").then((m) => m.runSetupWizard()).catch(fatal);
51
+ import("./setup-QZYRQ4CL.js").then((m) => m.runSetupWizard()).catch(fatal);
52
52
  break;
53
53
  }
54
54
  function fatal(err) {
@@ -233,7 +233,7 @@ export function DeploymentProgress({ agentId, onComplete }) {
233
233
  export function CreateAgentWizard({ onClose, onCreated, toast }) {
234
234
  const [step, setStep] = useState(0);
235
235
  const steps = ['Role', 'Basics', 'Persona', 'Skills', 'Permissions', 'Deployment', 'Review'];
236
- const [form, setForm] = useState({ name: '', email: '', role: 'assistant', description: '', personality: '', skills: [], preset: null, customTools: { allowed: [], blocked: [] }, deployTarget: 'docker', knowledgeBases: [], provider: 'anthropic', model: 'claude-sonnet-4-20250514', approvalRequired: true, soulId: null, avatar: null, gender: '', dateOfBirth: '', maritalStatus: '', culturalBackground: '', language: 'en-us', autoOnboard: true, maxRiskLevel: 'medium', blockedSideEffects: ['runs-code', 'deletes-data', 'financial', 'controls-device'], approvalForRiskLevels: ['high', 'critical'], approvalForSideEffects: ['sends-email', 'sends-message'], rateLimits: { toolCallsPerMinute: 30, toolCallsPerHour: 500, toolCallsPerDay: 5000, externalActionsPerHour: 50 }, constraints: { maxConcurrentTasks: 5, maxSessionDurationMinutes: 480, sandboxMode: false }, traits: { communication: 'direct', detail: 'detail-oriented', energy: 'calm', humor: 'warm', formality: 'adaptive', empathy: 'moderate', patience: 'patient', creativity: 'creative' } });
236
+ const [form, setForm] = useState({ name: '', email: '', role: 'assistant', description: '', personality: '', skills: [], preset: null, customTools: { allowed: [], blocked: [] }, deployTarget: 'docker', knowledgeBases: [], provider: '', model: '', approvalRequired: true, soulId: null, avatar: null, gender: '', dateOfBirth: '', maritalStatus: '', culturalBackground: '', language: 'en-us', autoOnboard: true, maxRiskLevel: 'medium', blockedSideEffects: ['runs-code', 'deletes-data', 'financial', 'controls-device'], approvalForRiskLevels: ['high', 'critical'], approvalForSideEffects: ['sends-email', 'sends-message'], rateLimits: { toolCallsPerMinute: 30, toolCallsPerHour: 500, toolCallsPerDay: 5000, externalActionsPerHour: 50 }, constraints: { maxConcurrentTasks: 5, maxSessionDurationMinutes: 480, sandboxMode: false }, traits: { communication: 'direct', detail: 'detail-oriented', energy: 'calm', humor: 'warm', formality: 'adaptive', empathy: 'moderate', patience: 'patient', creativity: 'creative' } });
237
237
  const [allSkills, setAllSkills] = useState({});
238
238
  const [providers, setProviders] = useState([]);
239
239
  const [providerModels, setProviderModels] = useState([]);
@@ -254,15 +254,25 @@ export function CreateAgentWizard({ onClose, onCreated, toast }) {
254
254
  apiCall('/providers').then(function(d) {
255
255
  var provList = d.providers || [];
256
256
  setProviders(provList);
257
- var hasConfigured = provList.some(function(p) { return p.configured; });
258
- if (!hasConfigured) { setShowSetupGuide(true); }
257
+ var configuredProviders = provList.filter(function(p) { return p.configured; });
258
+ if (configuredProviders.length === 0) { setShowSetupGuide(true); }
259
+ else {
260
+ // Auto-select first configured provider if none set
261
+ setForm(function(f) {
262
+ if (!f.provider) {
263
+ return Object.assign({}, f, { provider: configuredProviders[0].id });
264
+ }
265
+ return f;
266
+ });
267
+ }
259
268
  setSetupChecked(true);
260
269
  }).catch(function() { setShowSetupGuide(true); setSetupChecked(true); });
261
270
  }, []);
262
271
 
263
272
  // Fetch models when provider changes
264
273
  useEffect(function() {
265
- var p = form.provider || 'anthropic';
274
+ var p = form.provider;
275
+ if (!p) return;
266
276
  apiCall('/providers/' + p + '/models').then(function(d) {
267
277
  var models = d.models || [];
268
278
  setProviderModels(models);
@@ -1,4 +1,4 @@
1
- import { h, useState, useEffect, Fragment, useApp, engineCall, getOrgId } from '../components/utils.js';
1
+ import { h, useState, useEffect, useCallback, Fragment, useApp, engineCall, getOrgId } from '../components/utils.js';
2
2
  import { I } from '../components/icons.js';
3
3
  import { Modal } from '../components/modal.js';
4
4
 
@@ -7,9 +7,18 @@ export function KnowledgeBasePage() {
7
7
  const [kbs, setKbs] = useState([]);
8
8
  const [creating, setCreating] = useState(false);
9
9
  const [form, setForm] = useState({ name: '', description: '' });
10
+ const [selected, setSelected] = useState(null); // full KB detail
11
+ const [docs, setDocs] = useState([]);
12
+ const [chunks, setChunks] = useState([]);
13
+ const [selectedDoc, setSelectedDoc] = useState(null);
14
+ const [editing, setEditing] = useState(false);
15
+ const [editForm, setEditForm] = useState({ name: '', description: '' });
16
+ const [loading, setLoading] = useState(false);
10
17
 
11
- const load = () => engineCall('/knowledge-bases').then(d => setKbs(d.knowledgeBases || [])).catch(() => {});
12
- useEffect(() => { load(); }, []);
18
+ const load = useCallback(() => {
19
+ engineCall('/knowledge-bases').then(d => setKbs(d.knowledgeBases || [])).catch(() => {});
20
+ }, []);
21
+ useEffect(() => { load(); }, [load]);
13
22
 
14
23
  const create = async () => {
15
24
  try {
@@ -19,26 +28,202 @@ export function KnowledgeBasePage() {
19
28
  } catch (e) { toast(e.message, 'error'); }
20
29
  };
21
30
 
31
+ const selectKb = async (kb) => {
32
+ setLoading(true);
33
+ try {
34
+ const detail = await engineCall('/knowledge-bases/' + kb.id);
35
+ const kbData = detail.knowledgeBase || detail;
36
+ setSelected(kbData);
37
+ setDocs(kbData.documents || []);
38
+ setChunks([]);
39
+ setSelectedDoc(null);
40
+ setEditForm({ name: kbData.name || '', description: kbData.description || '' });
41
+ } catch (e) {
42
+ toast('Failed to load knowledge base: ' + e.message, 'error');
43
+ }
44
+ setLoading(false);
45
+ };
46
+
47
+ const loadDocChunks = async (doc) => {
48
+ setSelectedDoc(doc);
49
+ try {
50
+ const res = await engineCall('/knowledge-bases/' + selected.id + '/documents/' + doc.id + '/chunks');
51
+ setChunks(res.chunks || []);
52
+ } catch {
53
+ // chunks endpoint might not exist, try search with empty query
54
+ setChunks([]);
55
+ }
56
+ };
57
+
58
+ const deleteKb = async (id) => {
59
+ try {
60
+ await engineCall('/knowledge-bases/' + id, { method: 'DELETE' });
61
+ toast('Knowledge base deleted', 'success');
62
+ setSelected(null); load();
63
+ } catch (e) { toast(e.message, 'error'); }
64
+ };
65
+
66
+ const deleteDoc = async (docId) => {
67
+ if (!selected) return;
68
+ try {
69
+ await engineCall('/knowledge-bases/' + selected.id + '/documents/' + docId, { method: 'DELETE' });
70
+ toast('Document deleted', 'success');
71
+ setDocs(d => d.filter(x => x.id !== docId));
72
+ if (selectedDoc && selectedDoc.id === docId) { setSelectedDoc(null); setChunks([]); }
73
+ } catch (e) { toast(e.message, 'error'); }
74
+ };
75
+
76
+ const saveEdit = async () => {
77
+ if (!selected) return;
78
+ try {
79
+ await engineCall('/knowledge-bases/' + selected.id, { method: 'PUT', body: JSON.stringify({ name: editForm.name, description: editForm.description }) });
80
+ toast('Knowledge base updated', 'success');
81
+ setSelected(s => ({ ...s, name: editForm.name, description: editForm.description }));
82
+ setEditing(false);
83
+ load();
84
+ } catch (e) { toast(e.message, 'error'); }
85
+ };
86
+
87
+ // ── Detail View ──
88
+ if (selected) {
89
+ return h(Fragment, null,
90
+ h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 } },
91
+ h('div', { style: { display: 'flex', alignItems: 'center', gap: 12 } },
92
+ h('button', { className: 'btn btn-secondary btn-sm', onClick: () => setSelected(null) }, '\u2190 Back'),
93
+ editing
94
+ ? h('input', { className: 'input', value: editForm.name, onChange: e => setEditForm(f => ({ ...f, name: e.target.value })), style: { fontSize: 18, fontWeight: 700, padding: '4px 8px' } })
95
+ : h('h1', { style: { fontSize: 20, fontWeight: 700, margin: 0 } }, selected.name)
96
+ ),
97
+ h('div', { style: { display: 'flex', gap: 8 } },
98
+ editing
99
+ ? h(Fragment, null,
100
+ h('button', { className: 'btn btn-secondary btn-sm', onClick: () => setEditing(false) }, 'Cancel'),
101
+ h('button', { className: 'btn btn-primary btn-sm', onClick: saveEdit }, 'Save')
102
+ )
103
+ : h(Fragment, null,
104
+ h('button', { className: 'btn btn-secondary btn-sm', onClick: () => setEditing(true) }, I.journal(), ' Edit'),
105
+ h('button', { className: 'btn btn-danger btn-sm', onClick: () => deleteKb(selected.id) }, I.trash(), ' Delete')
106
+ )
107
+ )
108
+ ),
109
+
110
+ // Description
111
+ h('div', { className: 'card', style: { marginBottom: 16 } },
112
+ h('div', { className: 'card-body' },
113
+ editing
114
+ ? h('textarea', { className: 'input', rows: 3, value: editForm.description, onChange: e => setEditForm(f => ({ ...f, description: e.target.value })), placeholder: 'Knowledge base description...' })
115
+ : h('p', { style: { color: 'var(--text-secondary)', fontSize: 13, margin: 0 } }, selected.description || 'No description'),
116
+ h('div', { style: { display: 'flex', gap: 12, marginTop: 12, fontSize: 12, color: 'var(--text-muted)' } },
117
+ h('span', null, 'ID: ', h('code', null, selected.id)),
118
+ selected.createdAt && h('span', null, 'Created: ', new Date(selected.createdAt).toLocaleDateString()),
119
+ h('span', null, docs.length + ' document(s)'),
120
+ selected.agentIds && h('span', null, (selected.agentIds.length || 0) + ' agent(s)')
121
+ )
122
+ )
123
+ ),
124
+
125
+ // Stats
126
+ selected.stats && h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 12, marginBottom: 16 } },
127
+ [
128
+ { label: 'Documents', value: selected.stats.documentCount || docs.length },
129
+ { label: 'Chunks', value: selected.stats.chunkCount || 0 },
130
+ { label: 'Total Tokens', value: selected.stats.totalTokens || 0 },
131
+ { label: 'Queries', value: selected.stats.queryCount || 0 },
132
+ ].map(s => h('div', { key: s.label, className: 'card', style: { textAlign: 'center', padding: 12 } },
133
+ h('div', { style: { fontSize: 22, fontWeight: 700, color: 'var(--brand-color, #6366f1)' } }, typeof s.value === 'number' && s.value > 1000 ? (s.value / 1000).toFixed(1) + 'K' : s.value),
134
+ h('div', { style: { fontSize: 12, color: 'var(--text-muted)', marginTop: 2 } }, s.label)
135
+ ))
136
+ ),
137
+
138
+ // Two-panel layout: docs list + chunk preview
139
+ h('div', { style: { display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 } },
140
+
141
+ // Documents list
142
+ h('div', { className: 'card' },
143
+ h('div', { className: 'card-header' },
144
+ h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' } },
145
+ h('h3', { style: { margin: 0 } }, 'Documents'),
146
+ h('span', { className: 'badge badge-neutral' }, docs.length)
147
+ )
148
+ ),
149
+ h('div', { className: 'card-body-flush' },
150
+ docs.length === 0
151
+ ? h('div', { style: { padding: 24, textAlign: 'center', color: 'var(--text-muted)' } }, 'No documents in this knowledge base')
152
+ : docs.map(doc =>
153
+ h('div', { key: doc.id, style: {
154
+ padding: '10px 16px', borderBottom: '1px solid var(--border)', cursor: 'pointer',
155
+ background: selectedDoc && selectedDoc.id === doc.id ? 'var(--bg-secondary)' : 'transparent',
156
+ transition: 'background 0.15s'
157
+ }, onClick: () => loadDocChunks(doc) },
158
+ h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' } },
159
+ h('div', null,
160
+ h('div', { style: { fontWeight: 600, fontSize: 13 } }, doc.name || doc.id),
161
+ h('div', { style: { fontSize: 11, color: 'var(--text-muted)', marginTop: 2 } },
162
+ [doc.sourceType, doc.mimeType, doc.size ? (doc.size > 1024 ? (doc.size / 1024).toFixed(1) + ' KB' : doc.size + ' B') : null, doc.status].filter(Boolean).join(' \u2022 ')
163
+ )
164
+ ),
165
+ h('button', { className: 'btn btn-sm', style: { padding: '2px 6px', fontSize: 11, color: 'var(--danger)' }, onClick: (e) => { e.stopPropagation(); deleteDoc(doc.id); } }, I.trash())
166
+ )
167
+ )
168
+ )
169
+ )
170
+ ),
171
+
172
+ // Chunk preview
173
+ h('div', { className: 'card' },
174
+ h('div', { className: 'card-header' },
175
+ h('h3', { style: { margin: 0 } }, selectedDoc ? 'Chunks: ' + (selectedDoc.name || selectedDoc.id) : 'Select a document')
176
+ ),
177
+ h('div', { className: 'card-body', style: { maxHeight: 500, overflow: 'auto' } },
178
+ !selectedDoc
179
+ ? h('div', { style: { textAlign: 'center', color: 'var(--text-muted)', padding: 24 } }, 'Click a document to preview its chunks')
180
+ : chunks.length === 0
181
+ ? h('div', { style: { textAlign: 'center', color: 'var(--text-muted)', padding: 24 } }, 'No chunks found. The document may not have been processed yet.')
182
+ : chunks.map((chunk, i) =>
183
+ h('div', { key: chunk.id || i, style: { padding: '10px 0', borderBottom: '1px solid var(--border)' } },
184
+ h('div', { style: { display: 'flex', justifyContent: 'space-between', marginBottom: 4 } },
185
+ h('span', { style: { fontSize: 11, fontWeight: 600, color: 'var(--text-muted)' } }, 'Chunk #' + (chunk.position ?? i + 1)),
186
+ chunk.tokenCount && h('span', { style: { fontSize: 11, color: 'var(--text-muted)' } }, chunk.tokenCount + ' tokens')
187
+ ),
188
+ h('div', { style: { fontSize: 13, lineHeight: 1.5, whiteSpace: 'pre-wrap', color: 'var(--text-primary)' } }, chunk.content || '(empty)')
189
+ )
190
+ )
191
+ )
192
+ )
193
+ )
194
+ );
195
+ }
196
+
197
+ // ── List View ──
22
198
  return h(Fragment, null,
23
199
  h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 } },
24
- h('div', null, h('h1', { style: { fontSize: 20, fontWeight: 700 } }, 'Knowledge Bases'), h('p', { style: { color: 'var(--text-muted)', fontSize: 13 } }, 'Document ingestion and RAG retrieval for agents')),
200
+ h('div', null,
201
+ h('h1', { style: { fontSize: 20, fontWeight: 700 } }, 'Knowledge Bases'),
202
+ h('p', { style: { color: 'var(--text-muted)', fontSize: 13 } }, 'Document ingestion and RAG retrieval for agents')
203
+ ),
25
204
  h('button', { className: 'btn btn-primary', onClick: () => setCreating(true) }, I.plus(), ' New Knowledge Base')
26
205
  ),
206
+
27
207
  creating && h(Modal, { title: 'Create Knowledge Base', onClose: () => setCreating(false), footer: h(Fragment, null, h('button', { className: 'btn btn-secondary', onClick: () => setCreating(false) }, 'Cancel'), h('button', { className: 'btn btn-primary', onClick: create, disabled: !form.name }, 'Create')) },
28
208
  h('div', { className: 'form-group' }, h('label', { className: 'form-label' }, 'Name'), h('input', { className: 'input', value: form.name, onChange: e => setForm(f => ({ ...f, name: e.target.value })) })),
29
209
  h('div', { className: 'form-group' }, h('label', { className: 'form-label' }, 'Description'), h('textarea', { className: 'input', value: form.description, onChange: e => setForm(f => ({ ...f, description: e.target.value })) }))
30
210
  ),
31
- kbs.length === 0
211
+
212
+ loading && h('div', { style: { textAlign: 'center', padding: 40 } }, 'Loading...'),
213
+
214
+ !loading && kbs.length === 0
32
215
  ? h('div', { className: 'card' }, h('div', { className: 'card-body' }, h('div', { className: 'empty-state' }, I.knowledge(), h('h3', null, 'No knowledge bases'), h('p', null, 'Create a knowledge base to give agents access to your documents, policies, and data.'))))
33
- : h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: 16 } }, kbs.map(kb =>
34
- h('div', { key: kb.id, className: 'card' },
216
+ : !loading && h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(300px, 1fr))', gap: 16 } }, kbs.map(kb =>
217
+ h('div', { key: kb.id, className: 'card', style: { cursor: 'pointer', transition: 'border-color 0.15s' }, onClick: () => selectKb(kb) },
35
218
  h('div', { className: 'card-body' },
36
219
  h('h3', { style: { fontSize: 15, fontWeight: 600, marginBottom: 4 } }, kb.name),
37
- h('p', { style: { fontSize: 12, color: 'var(--text-muted)', marginBottom: 12 } }, kb.description || 'No description'),
38
- h('div', { style: { display: 'flex', gap: 8 } },
39
- h('span', { className: 'badge badge-info' }, (kb.documents?.length || 0) + ' documents'),
40
- h('span', { className: 'badge badge-neutral' }, (kb.agentIds?.length || 0) + ' agents')
41
- )
220
+ h('p', { style: { fontSize: 12, color: 'var(--text-muted)', marginBottom: 12, minHeight: 32 } }, kb.description || 'No description'),
221
+ h('div', { style: { display: 'flex', gap: 8, flexWrap: 'wrap' } },
222
+ h('span', { className: 'badge badge-info' }, (kb.stats?.documentCount || kb.documents?.length || 0) + ' docs'),
223
+ h('span', { className: 'badge badge-neutral' }, (kb.stats?.chunkCount || 0) + ' chunks'),
224
+ kb.agentIds && kb.agentIds.length > 0 && h('span', { className: 'badge badge-success' }, kb.agentIds.length + ' agent(s)')
225
+ ),
226
+ h('div', { style: { fontSize: 11, color: 'var(--text-muted)', marginTop: 8 } }, 'Click to view details \u2192')
42
227
  )
43
228
  )
44
229
  ))
package/dist/index.js CHANGED
@@ -35,7 +35,7 @@ import {
35
35
  executeTool,
36
36
  runAgentLoop,
37
37
  toolsToDefinitions
38
- } from "./chunk-I5C76NBS.js";
38
+ } from "./chunk-ATHZCB2M.js";
39
39
  import "./chunk-TYW5XTOW.js";
40
40
  import {
41
41
  ValidationError,
@@ -50,11 +50,11 @@ import {
50
50
  requireRole,
51
51
  securityHeaders,
52
52
  validate
53
- } from "./chunk-MGZTOPY6.js";
53
+ } from "./chunk-JIZXHTCS.js";
54
54
  import {
55
55
  provision,
56
56
  runSetupWizard
57
- } from "./chunk-2JB6N2JV.js";
57
+ } from "./chunk-ZI6WADMQ.js";
58
58
  import {
59
59
  ENGINE_TABLES,
60
60
  ENGINE_TABLES_POSTGRES,