clementine-agent 1.18.58 → 1.18.59
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.
|
@@ -81,17 +81,13 @@ export async function runAgentHeartbeat(opts) {
|
|
|
81
81
|
allowedTools: [],
|
|
82
82
|
abortSignal: opts.abortSignal,
|
|
83
83
|
});
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
catch {
|
|
92
|
-
/* non-fatal */
|
|
93
|
-
}
|
|
94
|
-
}
|
|
84
|
+
// Heartbeat output is NOT mirrored to transcripts. Heartbeats fire
|
|
85
|
+
// up to 28x/day per agent and most output is low-value (status
|
|
86
|
+
// pings, dedup'd reminders). The heartbeat dedup that prior versions
|
|
87
|
+
// wanted recall for actually lives in the prompt itself (the
|
|
88
|
+
// dedupContext block + the __NOTHING__ sentinel), not in DB queries.
|
|
89
|
+
// Saving rows here just polluted FTS and the dashboard memory panel
|
|
90
|
+
// for no recall benefit.
|
|
95
91
|
return result;
|
|
96
92
|
}
|
|
97
93
|
//# sourceMappingURL=run-agent-heartbeat.js.map
|
|
@@ -7,6 +7,8 @@ import { type RunAgentResult } from './run-agent.js';
|
|
|
7
7
|
* the full assistant graph. */
|
|
8
8
|
export interface TeamTaskPostHooks {
|
|
9
9
|
triggerMemoryExtractionPostExchange: (userMessage: string, assistantResponse: string, sessionKey?: string, profile?: AgentProfile) => Promise<void>;
|
|
10
|
+
triggerSkillExtractionFromExecution: (source: 'unleashed' | 'cron' | 'chat', jobName: string, prompt: string, output: string, durationMs: number, agentSlug?: string) => Promise<void>;
|
|
11
|
+
triggerCronReflection: (jobName: string, jobPrompt: string, deliverable: string, successCriteria?: string[]) => Promise<void>;
|
|
10
12
|
}
|
|
11
13
|
export interface RunAgentTeamTaskOptions {
|
|
12
14
|
fromName: string;
|
|
@@ -56,6 +56,7 @@ export async function runAgentTeamTask(opts) {
|
|
|
56
56
|
promptChars: builtPrompt.length,
|
|
57
57
|
}, 'runAgentTeamTask: dispatching to runAgent');
|
|
58
58
|
const sessionKey = `team-task:${opts.fromSlug}->${opts.profile.slug}`;
|
|
59
|
+
const startedAt = Date.now();
|
|
59
60
|
const result = await runAgent(builtPrompt, {
|
|
60
61
|
sessionKey,
|
|
61
62
|
source: 'team-task',
|
|
@@ -82,14 +83,23 @@ export async function runAgentTeamTask(opts) {
|
|
|
82
83
|
/* non-fatal */
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
86
|
+
// Post-task hooks: memory + skill extraction + reflection. All
|
|
87
|
+
// fire-and-forget. Mirrors the cron wrapper's three-hook pattern.
|
|
88
|
+
// Team tasks often produce repeatable procedures (e.g. "draft a
|
|
89
|
+
// follow-up email after a discovery call") and reflection grades
|
|
90
|
+
// whether the response actually fulfilled the request.
|
|
89
91
|
if (opts.postTaskHooks && result.text?.trim()) {
|
|
92
|
+
const durationMs = Date.now() - startedAt;
|
|
90
93
|
opts.postTaskHooks
|
|
91
94
|
.triggerMemoryExtractionPostExchange(opts.content, result.text, sessionKey, opts.profile)
|
|
92
95
|
.catch(err => logger.debug({ err, fromSlug: opts.fromSlug, toSlug: opts.profile.slug }, 'runAgentTeamTask: memory extraction failed (non-fatal)'));
|
|
96
|
+
opts.postTaskHooks
|
|
97
|
+
.triggerSkillExtractionFromExecution('cron', // 'cron' covers autonomous-task skill source category
|
|
98
|
+
taskName, opts.content, result.text, durationMs, opts.profile.slug)
|
|
99
|
+
.catch(err => logger.debug({ err, fromSlug: opts.fromSlug, toSlug: opts.profile.slug }, 'runAgentTeamTask: skill extraction failed (non-fatal)'));
|
|
100
|
+
opts.postTaskHooks
|
|
101
|
+
.triggerCronReflection(taskName, opts.content, result.text)
|
|
102
|
+
.catch(err => logger.debug({ err, fromSlug: opts.fromSlug, toSlug: opts.profile.slug }, 'runAgentTeamTask: reflection failed (non-fatal)'));
|
|
93
103
|
}
|
|
94
104
|
return {
|
|
95
105
|
...result,
|
package/dist/cli/dashboard.js
CHANGED
|
@@ -281,8 +281,48 @@ async function searchMemory(query, limit = 20, filters = {}) {
|
|
|
281
281
|
WHERE ${where.join(' AND ')}
|
|
282
282
|
ORDER BY ${orderBy}
|
|
283
283
|
LIMIT ?`;
|
|
284
|
-
const
|
|
285
|
-
|
|
284
|
+
const chunkRows = db.prepare(sql).all(...params, limit);
|
|
285
|
+
// Also surface transcripts from chat / cron / team-task. These
|
|
286
|
+
// are written by saveTurn and would otherwise be invisible to the
|
|
287
|
+
// main search panel (only the per-session viewer surfaced them).
|
|
288
|
+
// chunkType filter is chunk-only — if set, skip transcripts.
|
|
289
|
+
let transcriptRows = [];
|
|
290
|
+
if (words.length > 0 && !filters.chunkType && !filters.pinnedOnly) {
|
|
291
|
+
try {
|
|
292
|
+
const ftsQuery = words.map((w) => `"${w.replace(/"/g, '')}"`).join(' OR ');
|
|
293
|
+
const tWhere = ['transcripts_fts MATCH ?'];
|
|
294
|
+
const tParams = [ftsQuery];
|
|
295
|
+
if (filters.sinceDays && filters.sinceDays > 0) {
|
|
296
|
+
tWhere.push("t.created_at >= datetime('now', ?)");
|
|
297
|
+
tParams.push(`-${filters.sinceDays} days`);
|
|
298
|
+
}
|
|
299
|
+
const tSql = `SELECT t.id, t.session_key, t.role, t.content, t.model, t.created_at,
|
|
300
|
+
bm25(transcripts_fts) as score
|
|
301
|
+
FROM transcripts_fts f JOIN transcripts t ON t.id = f.rowid
|
|
302
|
+
WHERE ${tWhere.join(' AND ')}
|
|
303
|
+
ORDER BY bm25(transcripts_fts)
|
|
304
|
+
LIMIT ?`;
|
|
305
|
+
transcriptRows = db.prepare(tSql).all(...tParams, Math.min(limit, 10))
|
|
306
|
+
.map(r => ({
|
|
307
|
+
id: `transcript:${r.id}`,
|
|
308
|
+
source_file: `transcripts/${r.session_key}`,
|
|
309
|
+
section: `${r.role} @ ${r.created_at}`,
|
|
310
|
+
content: r.content,
|
|
311
|
+
chunk_type: 'transcript',
|
|
312
|
+
updated_at: r.created_at,
|
|
313
|
+
salience: 0,
|
|
314
|
+
pinned: 0,
|
|
315
|
+
score: r.score,
|
|
316
|
+
}));
|
|
317
|
+
}
|
|
318
|
+
catch { /* transcripts FTS may be empty/unavailable — non-fatal */ }
|
|
319
|
+
}
|
|
320
|
+
// Merge: transcripts interleaved by score with chunks. FTS bm25
|
|
321
|
+
// is comparable across both since they use the same tokenizer.
|
|
322
|
+
const merged = [...chunkRows, ...transcriptRows]
|
|
323
|
+
.sort((a, b) => Number(a.score ?? 0) - Number(b.score ?? 0))
|
|
324
|
+
.slice(0, limit);
|
|
325
|
+
return { results: merged, dbExists: true };
|
|
286
326
|
}
|
|
287
327
|
catch (err) {
|
|
288
328
|
return { results: [], dbExists: true, error: String(err) };
|