clementine-agent 1.1.11 → 1.1.12
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/agent/assistant.js +16 -3
- package/dist/cli/dashboard.js +45 -0
- package/package.json +1 -1
package/dist/agent/assistant.js
CHANGED
|
@@ -1517,18 +1517,31 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
1517
1517
|
const { detectFrustrationSignals, detectRepeatedTopics } = require('./insight-engine.js');
|
|
1518
1518
|
const since24h = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();
|
|
1519
1519
|
const since7d = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString();
|
|
1520
|
-
|
|
1521
|
-
|
|
1520
|
+
let recent = this.getRecentActivity(since24h, 50);
|
|
1521
|
+
let week = this.getRecentActivity(since7d, 200);
|
|
1522
|
+
// Phase 10c: per-agent scope filter. Per-agent bot session keys
|
|
1523
|
+
// embed the agent slug (e.g. dm:ross-the-sdr:userId), so when this
|
|
1524
|
+
// prompt is for a specific agent profile we only consider sessions
|
|
1525
|
+
// that involved THAT agent. Without this filter, Nate's frustration
|
|
1526
|
+
// chatting with Sasha would leak into Ross's prompt — wrong signal.
|
|
1527
|
+
if (profile?.slug) {
|
|
1528
|
+
const slugMarker = `:${profile.slug}:`;
|
|
1529
|
+
recent = recent.filter(e => e.sessionKey.includes(slugMarker));
|
|
1530
|
+
week = week.filter(e => e.sessionKey.includes(slugMarker));
|
|
1531
|
+
}
|
|
1522
1532
|
const frustration = detectFrustrationSignals(recent);
|
|
1523
1533
|
const topics = detectRepeatedTopics(week);
|
|
1524
1534
|
const allSignals = [...frustration, ...topics];
|
|
1525
1535
|
if (allSignals.length > 0) {
|
|
1536
|
+
const scopeNote = profile?.slug
|
|
1537
|
+
? `\n\n*Scope: signals from sessions with you (${profile.slug}).*`
|
|
1538
|
+
: '';
|
|
1526
1539
|
const guidance = frustration.length > 0
|
|
1527
1540
|
? '\n\n**Adjust your approach:** When friction signals are present, lead with a clarifying question instead of assuming. Acknowledge the prior misunderstanding briefly without over-apologizing. Confirm understanding before acting.'
|
|
1528
1541
|
: '\n\n**Use this context naturally:** Recurring topics may indicate an unresolved thread — if relevant, offer to close the loop or summarize current state. Do not force callbacks if not directly applicable.';
|
|
1529
1542
|
volatileParts.push(`## Conversational Context\n\nSignals from recent sessions:\n` +
|
|
1530
1543
|
allSignals.map(s => `- ${s}`).join('\n') +
|
|
1531
|
-
guidance);
|
|
1544
|
+
guidance + scopeNote);
|
|
1532
1545
|
}
|
|
1533
1546
|
}
|
|
1534
1547
|
catch { /* non-fatal — insight-engine optional */ }
|
package/dist/cli/dashboard.js
CHANGED
|
@@ -16981,6 +16981,51 @@ async function refreshToolUsagePanel() {
|
|
|
16981
16981
|
}
|
|
16982
16982
|
html += '</table>';
|
|
16983
16983
|
}
|
|
16984
|
+
|
|
16985
|
+
// Phase 11e: cost-by-source pivot — aggregates the bySource maps from
|
|
16986
|
+
// every family into a single "top jobs by spend" view. Uses only data
|
|
16987
|
+
// already in the response, no extra API call.
|
|
16988
|
+
const sourceTotals = {};
|
|
16989
|
+
for (const f of (data.families || [])) {
|
|
16990
|
+
const callsPerSource = {};
|
|
16991
|
+
for (const s of (f.bySource || [])) callsPerSource[s.source] = s.count;
|
|
16992
|
+
const familyTotalCalls = f.totalCalls || 0;
|
|
16993
|
+
for (const s of (f.bySource || [])) {
|
|
16994
|
+
const share = familyTotalCalls > 0 ? s.count / familyTotalCalls : 0;
|
|
16995
|
+
const cost = (f.estimatedCostUsd || 0) * share;
|
|
16996
|
+
if (!sourceTotals[s.source]) sourceTotals[s.source] = { source: s.source, cost: 0, calls: 0 };
|
|
16997
|
+
sourceTotals[s.source].cost += cost;
|
|
16998
|
+
sourceTotals[s.source].calls += s.count;
|
|
16999
|
+
}
|
|
17000
|
+
}
|
|
17001
|
+
const sourceList = Object.values(sourceTotals)
|
|
17002
|
+
.filter(s => s.source !== 'unknown' || sourceTotals.unknown.cost > 0)
|
|
17003
|
+
.sort((a, b) => b.cost - a.cost);
|
|
17004
|
+
|
|
17005
|
+
if (sourceList.length > 0) {
|
|
17006
|
+
const maxSrcCost = Math.max.apply(null, sourceList.map(s => s.cost).concat([0.0001]));
|
|
17007
|
+
html += '<div style="margin-top:18px"><div style="font-weight:600;font-size:13px;margin-bottom:8px;color:var(--text-secondary)">Top jobs by cost</div>';
|
|
17008
|
+
html += '<table style="width:100%;font-size:13px"><tr>'
|
|
17009
|
+
+ '<th>Job / source</th><th style="text-align:right">Cost</th><th style="text-align:right">Share</th><th style="text-align:right">Calls</th><th>Distribution</th></tr>';
|
|
17010
|
+
const totalSrcCost = sourceList.reduce((sum, s) => sum + s.cost, 0);
|
|
17011
|
+
for (const s of sourceList.slice(0, 10)) {
|
|
17012
|
+
const pct = totalSrcCost > 0 ? ((s.cost / totalSrcCost) * 100).toFixed(1) + '%' : '0.0%';
|
|
17013
|
+
const barW = Math.max(2, Math.round((s.cost / maxSrcCost) * 100));
|
|
17014
|
+
const sourceLabel = s.source === 'unknown'
|
|
17015
|
+
? '<em style="color:var(--text-muted)">unattributed</em>'
|
|
17016
|
+
: '<strong>' + esc(s.source) + '</strong>';
|
|
17017
|
+
html += '<tr>'
|
|
17018
|
+
+ '<td>' + sourceLabel + '</td>'
|
|
17019
|
+
+ '<td style="text-align:right;color:var(--green)">$' + s.cost.toFixed(2) + '</td>'
|
|
17020
|
+
+ '<td style="text-align:right;color:var(--text-muted)">' + pct + '</td>'
|
|
17021
|
+
+ '<td style="text-align:right">' + s.calls.toLocaleString() + '</td>'
|
|
17022
|
+
+ '<td><div style="background:var(--bg-elev);height:8px;border-radius:4px;overflow:hidden;width:100%;max-width:160px">'
|
|
17023
|
+
+ '<div style="background:var(--blue);height:100%;width:' + barW + '%"></div></div></td>'
|
|
17024
|
+
+ '</tr>';
|
|
17025
|
+
}
|
|
17026
|
+
html += '</table></div>';
|
|
17027
|
+
}
|
|
17028
|
+
|
|
16984
17029
|
html += '</div></div>';
|
|
16985
17030
|
host.innerHTML = html;
|
|
16986
17031
|
} catch(e) {
|