clementine-agent 1.2.1 → 1.2.2
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/dashboard.js
CHANGED
|
@@ -16618,6 +16618,144 @@ async function saveUserModelSlot(slot) {
|
|
|
16618
16618
|
} catch (e) { toast('Save failed: ' + String(e), 'error'); }
|
|
16619
16619
|
}
|
|
16620
16620
|
|
|
16621
|
+
async function seedUserModel() {
|
|
16622
|
+
var seedPanel = document.getElementById('user-model-seed-panel');
|
|
16623
|
+
if (!seedPanel) return;
|
|
16624
|
+
seedPanel.style.display = 'block';
|
|
16625
|
+
seedPanel.innerHTML =
|
|
16626
|
+
'<div class="card" style="padding:14px;border-left:3px solid var(--accent,#f59e0b)">'
|
|
16627
|
+
+ '<div style="font-weight:600;margin-bottom:6px">✨ Analyzing your existing memory…</div>'
|
|
16628
|
+
+ '<div style="font-size:12px;color:var(--text-muted)">Running Haiku over MEMORY.md, top-salience chunks, and recent session summaries. Usually 5–15 seconds.</div>'
|
|
16629
|
+
+ '</div>';
|
|
16630
|
+
try {
|
|
16631
|
+
var r = await apiFetch('/api/user-model/seed', {
|
|
16632
|
+
method: 'POST',
|
|
16633
|
+
headers: { 'Content-Type': 'application/json' },
|
|
16634
|
+
body: '{}',
|
|
16635
|
+
});
|
|
16636
|
+
var d = await r.json();
|
|
16637
|
+
if (!d.ok || !d.proposals) {
|
|
16638
|
+
seedPanel.innerHTML =
|
|
16639
|
+
'<div class="card" style="padding:14px;border-left:3px solid var(--red,#ef4444)">'
|
|
16640
|
+
+ '<div style="font-weight:600;margin-bottom:6px">Seed failed</div>'
|
|
16641
|
+
+ '<div style="font-size:12px;color:var(--text-muted)">' + esc(d.error || 'Unknown error') + '</div>'
|
|
16642
|
+
+ '<div style="margin-top:10px"><button class="btn" onclick="dismissSeedPanel()" style="font-size:12px">Dismiss</button></div>'
|
|
16643
|
+
+ '</div>';
|
|
16644
|
+
return;
|
|
16645
|
+
}
|
|
16646
|
+
renderSeedProposals(d.proposals);
|
|
16647
|
+
} catch (e) {
|
|
16648
|
+
seedPanel.innerHTML =
|
|
16649
|
+
'<div class="card" style="padding:14px;border-left:3px solid var(--red,#ef4444)">'
|
|
16650
|
+
+ '<div style="font-weight:600">Seed failed: ' + esc(String(e)) + '</div>'
|
|
16651
|
+
+ '<div style="margin-top:10px"><button class="btn" onclick="dismissSeedPanel()" style="font-size:12px">Dismiss</button></div>'
|
|
16652
|
+
+ '</div>';
|
|
16653
|
+
}
|
|
16654
|
+
}
|
|
16655
|
+
|
|
16656
|
+
function renderSeedProposals(p) {
|
|
16657
|
+
var seedPanel = document.getElementById('user-model-seed-panel');
|
|
16658
|
+
if (!seedPanel) return;
|
|
16659
|
+
var labelMap = {
|
|
16660
|
+
user_facts: 'User Facts',
|
|
16661
|
+
goals: 'Active Goals',
|
|
16662
|
+
relationships: 'Key Relationships',
|
|
16663
|
+
agent_persona: 'Agent Persona',
|
|
16664
|
+
};
|
|
16665
|
+
var slots = ['user_facts', 'goals', 'relationships', 'agent_persona'];
|
|
16666
|
+
var anyContent = slots.some(function(s) { return (p[s] || '').trim().length > 0; });
|
|
16667
|
+
if (!anyContent) {
|
|
16668
|
+
seedPanel.innerHTML =
|
|
16669
|
+
'<div class="card" style="padding:14px;border-left:3px solid var(--accent,#f59e0b)">'
|
|
16670
|
+
+ '<div style="font-weight:600;margin-bottom:4px">No clear signal in memory yet</div>'
|
|
16671
|
+
+ '<div style="font-size:12px;color:var(--text-muted)">Haiku analyzed ' + (p.sourceCount || 0) + ' source items but found no facts strong enough to seed slots. Have a few conversations and try again, or fill the slots manually below.</div>'
|
|
16672
|
+
+ '<div style="margin-top:10px"><button class="btn" onclick="dismissSeedPanel()" style="font-size:12px">Dismiss</button></div>'
|
|
16673
|
+
+ '</div>';
|
|
16674
|
+
return;
|
|
16675
|
+
}
|
|
16676
|
+
var html = '<div class="card" style="padding:14px;border-left:3px solid var(--accent,#f59e0b)">';
|
|
16677
|
+
html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;gap:8px;flex-wrap:wrap">';
|
|
16678
|
+
html += '<div><div style="font-weight:600">✨ Proposed values from memory</div>';
|
|
16679
|
+
html += '<div style="font-size:11px;color:var(--text-muted)">Reviewed ' + (p.sourceCount || 0) + ' source items. Edit any slot before applying. Skipped slots stay empty.</div></div>';
|
|
16680
|
+
html += '<div style="display:flex;gap:6px"><button class="btn-primary" onclick="applyAllSeedSlots()" style="font-size:12px">Apply all</button><button class="btn" onclick="dismissSeedPanel()" style="font-size:12px">Dismiss</button></div>';
|
|
16681
|
+
html += '</div>';
|
|
16682
|
+
for (var i = 0; i < slots.length; i++) {
|
|
16683
|
+
var slot = slots[i];
|
|
16684
|
+
var content = (p[slot] || '').trim();
|
|
16685
|
+
if (!content) continue;
|
|
16686
|
+
var label = labelMap[slot] || slot;
|
|
16687
|
+
html += '<div class="seed-slot-card" data-slot="' + esc(slot) + '" style="margin-top:10px;padding:10px;background:var(--bg-input);border-radius:6px">';
|
|
16688
|
+
html += '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px">';
|
|
16689
|
+
html += '<div style="font-weight:600;font-size:13px">' + esc(label) + '</div>';
|
|
16690
|
+
html += '<div style="display:flex;gap:6px"><button class="btn-primary" onclick="applySeedSlot(\\'' + esc(slot) + '\\')" style="font-size:11px;padding:2px 10px">Apply</button><button class="btn" onclick="skipSeedSlot(\\'' + esc(slot) + '\\')" style="font-size:11px;padding:2px 10px">Skip</button></div>';
|
|
16691
|
+
html += '</div>';
|
|
16692
|
+
html += '<textarea id="seed-textarea-' + esc(slot) + '" style="width:100%;min-height:70px;padding:6px;border:1px solid var(--border);border-radius:4px;background:var(--bg);color:var(--text);font-family:inherit;font-size:12px;resize:vertical">' + esc(content) + '</textarea>';
|
|
16693
|
+
html += '</div>';
|
|
16694
|
+
}
|
|
16695
|
+
html += '</div>';
|
|
16696
|
+
seedPanel.innerHTML = html;
|
|
16697
|
+
}
|
|
16698
|
+
|
|
16699
|
+
async function applySeedSlot(slot) {
|
|
16700
|
+
var ta = document.getElementById('seed-textarea-' + slot);
|
|
16701
|
+
if (!ta) return;
|
|
16702
|
+
var content = ta.value;
|
|
16703
|
+
var scope = document.getElementById('user-model-scope');
|
|
16704
|
+
var agentSlug = scope && scope.value ? scope.value : null;
|
|
16705
|
+
try {
|
|
16706
|
+
var r = await apiFetch('/api/user-model/' + encodeURIComponent(slot), {
|
|
16707
|
+
method: 'PUT',
|
|
16708
|
+
headers: { 'Content-Type': 'application/json' },
|
|
16709
|
+
body: JSON.stringify({ content: content, agentSlug: agentSlug }),
|
|
16710
|
+
});
|
|
16711
|
+
var d = await r.json();
|
|
16712
|
+
if (d.ok) {
|
|
16713
|
+
toast('Applied ' + slot, 'success');
|
|
16714
|
+
var card = document.querySelector('.seed-slot-card[data-slot="' + slot + '"]');
|
|
16715
|
+
if (card) card.remove();
|
|
16716
|
+
loadUserModel();
|
|
16717
|
+
} else {
|
|
16718
|
+
toast('Apply failed: ' + (d.error || 'unknown'), 'error');
|
|
16719
|
+
}
|
|
16720
|
+
} catch (e) { toast('Apply failed: ' + String(e), 'error'); }
|
|
16721
|
+
}
|
|
16722
|
+
|
|
16723
|
+
function skipSeedSlot(slot) {
|
|
16724
|
+
var card = document.querySelector('.seed-slot-card[data-slot="' + slot + '"]');
|
|
16725
|
+
if (card) card.remove();
|
|
16726
|
+
}
|
|
16727
|
+
|
|
16728
|
+
async function applyAllSeedSlots() {
|
|
16729
|
+
var slots = ['user_facts', 'goals', 'relationships', 'agent_persona'];
|
|
16730
|
+
var applied = 0;
|
|
16731
|
+
for (var i = 0; i < slots.length; i++) {
|
|
16732
|
+
var ta = document.getElementById('seed-textarea-' + slots[i]);
|
|
16733
|
+
if (!ta || !ta.value.trim()) continue;
|
|
16734
|
+
var scope = document.getElementById('user-model-scope');
|
|
16735
|
+
var agentSlug = scope && scope.value ? scope.value : null;
|
|
16736
|
+
try {
|
|
16737
|
+
var r = await apiFetch('/api/user-model/' + encodeURIComponent(slots[i]), {
|
|
16738
|
+
method: 'PUT',
|
|
16739
|
+
headers: { 'Content-Type': 'application/json' },
|
|
16740
|
+
body: JSON.stringify({ content: ta.value, agentSlug: agentSlug }),
|
|
16741
|
+
});
|
|
16742
|
+
var d = await r.json();
|
|
16743
|
+
if (d.ok) applied++;
|
|
16744
|
+
} catch (e) { /* continue */ }
|
|
16745
|
+
}
|
|
16746
|
+
toast('Applied ' + applied + ' slot' + (applied === 1 ? '' : 's'), 'success');
|
|
16747
|
+
dismissSeedPanel();
|
|
16748
|
+
loadUserModel();
|
|
16749
|
+
}
|
|
16750
|
+
|
|
16751
|
+
function dismissSeedPanel() {
|
|
16752
|
+
var seedPanel = document.getElementById('user-model-seed-panel');
|
|
16753
|
+
if (seedPanel) {
|
|
16754
|
+
seedPanel.style.display = 'none';
|
|
16755
|
+
seedPanel.innerHTML = '';
|
|
16756
|
+
}
|
|
16757
|
+
}
|
|
16758
|
+
|
|
16621
16759
|
async function clearUserModelSlot(slot) {
|
|
16622
16760
|
if (!confirm('Clear the "' + slot + '" slot? This deletes everything currently stored there.')) return;
|
|
16623
16761
|
var scope = document.getElementById('user-model-scope');
|
|
@@ -33,6 +33,8 @@ export interface UserModelProposals {
|
|
|
33
33
|
/** Raw model output, for debugging. */
|
|
34
34
|
rawResponse?: string;
|
|
35
35
|
}
|
|
36
|
-
export declare function seedUserModelFromMemory(store: SeedSourceStore, llmCall: (prompt: string) => Promise<string
|
|
36
|
+
export declare function seedUserModelFromMemory(store: SeedSourceStore, llmCall: (prompt: string) => Promise<string>, opts?: {
|
|
37
|
+
memoryFilePath?: string;
|
|
38
|
+
}): Promise<UserModelProposals>;
|
|
37
39
|
export {};
|
|
38
40
|
//# sourceMappingURL=seed-user-model.d.ts.map
|
|
@@ -18,13 +18,13 @@ const logger = pino({ name: 'clementine.seed-user-model' });
|
|
|
18
18
|
const MAX_MEMORY_MD_CHARS = 4000;
|
|
19
19
|
const MAX_CHUNK_CHARS = 4000;
|
|
20
20
|
const MAX_SUMMARIES_CHARS = 1500;
|
|
21
|
-
function gatherCorpus(store) {
|
|
21
|
+
function gatherCorpus(store, memoryFilePath) {
|
|
22
22
|
const parts = [];
|
|
23
23
|
let sourceCount = 0;
|
|
24
24
|
// 1. MEMORY.md — highest-signal source, the agent's curated profile note
|
|
25
|
-
if (existsSync(
|
|
25
|
+
if (existsSync(memoryFilePath)) {
|
|
26
26
|
try {
|
|
27
|
-
const md = readFileSync(
|
|
27
|
+
const md = readFileSync(memoryFilePath, 'utf-8').slice(0, MAX_MEMORY_MD_CHARS);
|
|
28
28
|
if (md.trim()) {
|
|
29
29
|
parts.push(`## MEMORY.md\n${md}`);
|
|
30
30
|
sourceCount++;
|
|
@@ -147,8 +147,9 @@ function parseProposals(raw) {
|
|
|
147
147
|
}
|
|
148
148
|
return out;
|
|
149
149
|
}
|
|
150
|
-
export async function seedUserModelFromMemory(store, llmCall) {
|
|
151
|
-
const
|
|
150
|
+
export async function seedUserModelFromMemory(store, llmCall, opts = {}) {
|
|
151
|
+
const memFile = opts.memoryFilePath ?? MEMORY_FILE;
|
|
152
|
+
const { corpus, sourceCount } = gatherCorpus(store, memFile);
|
|
152
153
|
if (!corpus.trim() || sourceCount === 0) {
|
|
153
154
|
return {
|
|
154
155
|
user_facts: '', goals: '', relationships: '', agent_persona: '',
|