agentboss 0.1.0 → 0.1.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/bin/aboss.js +288 -288
- package/client/dist/assets/index-DxoLOxZ8.js +141 -0
- package/client/dist/index.html +1 -1
- package/package.json +1 -1
- package/server/analysis/dimensions/judgement.js +111 -107
- package/server/analysis/dimensions/llm-merge.js +59 -57
- package/server/analysis/dimensions/output-quality.js +167 -167
- package/server/analysis/dimensions/problem-definition.js +109 -104
- package/server/analysis/job.js +91 -14
- package/server/analysis/report-builder.js +574 -581
- package/server/analysis/scoring-v2.js +126 -72
- package/server/analysis/thresholds-v2.js +364 -358
- package/server/api/execution.js +94 -0
- package/server/db/schema.js +5 -2
- package/server/etl/opencode.js +5 -1
- package/server/execution/job.js +141 -2
- package/server/llm/advice-prompt.js +74 -11
- package/server/llm/advice.js +50 -1
- package/server/llm/analysis-prompt.js +173 -162
- package/server/llm/cli-runner.js +18 -2
- package/server/llm/judge.js +6 -1
- package/server/llm/mcp-classify.js +147 -0
- package/server/llm/project-advice-prompt.js +106 -6
- package/server/llm/project-advice.js +55 -2
- package/server/llm/session-analyzer.js +10 -1
- package/client/dist/assets/index-DBj1Ujlx.js +0 -137
package/server/analysis/job.js
CHANGED
|
@@ -27,27 +27,77 @@ const { aggregateDailySummary } = require('./daily-aggregator');
|
|
|
27
27
|
/**
|
|
28
28
|
* Build a list of YYYY-MM-DD strings starting from today going back
|
|
29
29
|
* `days` days, ordered most-recent first. Today is included so the
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
30
|
+
* Today is EXCLUDED — sessions on the current calendar day are still
|
|
31
|
+
* actively being held (judge / advice analysing them would race against
|
|
32
|
+
* the user typing more messages, churn the cache, and waste LLM calls).
|
|
33
|
+
* Yesterday + N earlier days only. Callers who really want to (re)
|
|
34
|
+
* analyze today must pass `dates: ['YYYY-MM-DD']` explicitly to
|
|
35
|
+
* runAnalysisJob, or use the per-session reanalyze endpoint
|
|
36
|
+
* (`POST /api/analysis/session/:id`) which bypasses this path.
|
|
33
37
|
*
|
|
34
|
-
*
|
|
38
|
+
* Default `days = 7` therefore produces 7 dates (yesterday through 7
|
|
39
|
+
* days ago), not 8.
|
|
40
|
+
*
|
|
41
|
+
* @param {number} days number of past days to include (yesterday-anchored)
|
|
35
42
|
* @returns {string[]}
|
|
36
43
|
*/
|
|
37
44
|
function buildDateList(days) {
|
|
38
45
|
const dates = [];
|
|
39
46
|
const now = new Date();
|
|
40
|
-
|
|
47
|
+
// Start at i=1 → yesterday; end at i=days inclusive → `days` total dates.
|
|
48
|
+
for (let i = 1; i <= days; i++) {
|
|
41
49
|
const d = new Date(now);
|
|
42
50
|
d.setDate(d.getDate() - i);
|
|
43
|
-
|
|
44
|
-
const mm = String(d.getMonth() + 1).padStart(2, '0');
|
|
45
|
-
const dd = String(d.getDate()).padStart(2, '0');
|
|
46
|
-
dates.push(`${yyyy}-${mm}-${dd}`);
|
|
51
|
+
dates.push(formatDate(d));
|
|
47
52
|
}
|
|
48
53
|
return dates; // already most-recent first
|
|
49
54
|
}
|
|
50
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Local-time YYYY-MM-DD for a Date. Must match buildDateList so the
|
|
58
|
+
* "today" string we compute lines up with the date strings we iterate.
|
|
59
|
+
*/
|
|
60
|
+
function formatDate(d) {
|
|
61
|
+
const yyyy = d.getFullYear();
|
|
62
|
+
const mm = String(d.getMonth() + 1).padStart(2, '0');
|
|
63
|
+
const dd = String(d.getDate()).padStart(2, '0');
|
|
64
|
+
return `${yyyy}-${mm}-${dd}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Pick the id of the "currently active" session for `date` — defined
|
|
69
|
+
* (per user spec) as the today-bucket session with the largest
|
|
70
|
+
* ended_at. Returns null if `date` isn't today or the bucket is empty.
|
|
71
|
+
* We skip this session in the job so we don't analyze a still-growing
|
|
72
|
+
* conversation; the next job pass will pick it up once it settles.
|
|
73
|
+
*
|
|
74
|
+
* Note: the default invocation of runAnalysisJob no longer includes
|
|
75
|
+
* today at all (see buildDateList). This function only fires when a
|
|
76
|
+
* caller explicitly passes `dates` that includes today — in which case
|
|
77
|
+
* we still shield the actively-typed-in session.
|
|
78
|
+
*
|
|
79
|
+
* @param {object} db
|
|
80
|
+
* @param {string} date YYYY-MM-DD
|
|
81
|
+
* @param {object[]} sessions candidate session rows for that date
|
|
82
|
+
* @returns {string|null} session_id to skip, or null
|
|
83
|
+
*/
|
|
84
|
+
function pickCurrentSessionId(db, date, sessions) {
|
|
85
|
+
const today = formatDate(new Date());
|
|
86
|
+
if (date !== today) return null;
|
|
87
|
+
// Compare against ALL today's sessions (not just unanalyzed) so a
|
|
88
|
+
// fully-analyzed but freshly-touched session still counts as "current"
|
|
89
|
+
// and shields a slightly older still-running session from being
|
|
90
|
+
// wrongly considered the active one.
|
|
91
|
+
const allToday = getSessionsByDate(db, today);
|
|
92
|
+
const pool = allToday.length > 0 ? allToday : sessions;
|
|
93
|
+
let best = null;
|
|
94
|
+
for (const s of pool) {
|
|
95
|
+
if (!s.ended_at) continue;
|
|
96
|
+
if (!best || s.ended_at > best.ended_at) best = s;
|
|
97
|
+
}
|
|
98
|
+
return best ? best.id : null;
|
|
99
|
+
}
|
|
100
|
+
|
|
51
101
|
// ---------------------------------------------------------------------------
|
|
52
102
|
// Per-session analyze + persist (shared by the job loop and the
|
|
53
103
|
// per-session reanalyze endpoint)
|
|
@@ -119,7 +169,24 @@ async function analyzeAndStoreSession(db, session, opts = {}) {
|
|
|
119
169
|
|
|
120
170
|
/**
|
|
121
171
|
* Run analysis job: analyze unanalyzed sessions in reverse chronological order.
|
|
122
|
-
*
|
|
172
|
+
*
|
|
173
|
+
* # Today policy
|
|
174
|
+
*
|
|
175
|
+
* Default invocation ({days}) skips TODAY entirely — sessions on the
|
|
176
|
+
* current calendar day are likely still being held, and analysing
|
|
177
|
+
* them now means churning the LLM cache for results that will be stale
|
|
178
|
+
* within minutes. The boot path (bin/aboss.js) uses this default, so
|
|
179
|
+
* "open aboss → background scan" never touches today.
|
|
180
|
+
*
|
|
181
|
+
* Two escape hatches keep today analysable when the user really asks:
|
|
182
|
+
* - `dates: ['YYYY-MM-DD']` explicit list → not filtered. Used by
|
|
183
|
+
* manual triggers that pass a specific date set.
|
|
184
|
+
* - `POST /api/analysis/session/:id` → goes straight through
|
|
185
|
+
* `analyzeAndStoreSession`, doesn't use this job loop, so today's
|
|
186
|
+
* "Re-analyze" button in the UI keeps working.
|
|
187
|
+
*
|
|
188
|
+
* Default: last 7 days (yesterday → 7 days ago). Processes one date at
|
|
189
|
+
* a time, most recent first.
|
|
123
190
|
*
|
|
124
191
|
* @param {object} db - sql.js boss.db instance
|
|
125
192
|
* @param {object} options - {
|
|
@@ -127,6 +194,7 @@ async function analyzeAndStoreSession(db, session, opts = {}) {
|
|
|
127
194
|
* onProgress: fn,
|
|
128
195
|
* forceReanalyze: false,
|
|
129
196
|
* dates: string[] // optional explicit YYYY-MM-DD list; overrides `days`
|
|
197
|
+
* // AND bypasses the "skip today" rule
|
|
130
198
|
* }
|
|
131
199
|
* @returns {Promise<{analyzed: number, errors: number, skipped: number}>}
|
|
132
200
|
*/
|
|
@@ -154,13 +222,15 @@ async function runAnalysisJob(db, options = {}) {
|
|
|
154
222
|
: buildDateList(days);
|
|
155
223
|
|
|
156
224
|
try {
|
|
157
|
-
// Pre-calculate total count for progress reporting
|
|
225
|
+
// Pre-calculate total count for progress reporting. Subtract the
|
|
226
|
+
// "current" (still-running) session if it falls in the candidate set.
|
|
158
227
|
let totalSessions = 0;
|
|
159
228
|
for (const date of dates) {
|
|
160
229
|
const sessions = forceReanalyze
|
|
161
230
|
? getSessionsByDate(db, date)
|
|
162
231
|
: getUnanalyzedSessions(db, date);
|
|
163
|
-
|
|
232
|
+
const skipId = pickCurrentSessionId(db, date, sessions);
|
|
233
|
+
totalSessions += sessions.filter((s) => s.id !== skipId).length;
|
|
164
234
|
}
|
|
165
235
|
|
|
166
236
|
updateAnalysisState(db, {
|
|
@@ -181,10 +251,17 @@ async function runAnalysisJob(db, options = {}) {
|
|
|
181
251
|
last_analyzed_at: null,
|
|
182
252
|
});
|
|
183
253
|
|
|
184
|
-
// 2a. Get unanalyzed sessions for this date
|
|
185
|
-
|
|
254
|
+
// 2a. Get unanalyzed sessions for this date, minus the currently-
|
|
255
|
+
// active session (today's session with the largest ended_at). We
|
|
256
|
+
// skip it so the job doesn't score a conversation that's still
|
|
257
|
+
// being written to — the next pass will catch it.
|
|
258
|
+
const rawSessions = forceReanalyze
|
|
186
259
|
? getSessionsByDate(db, date)
|
|
187
260
|
: getUnanalyzedSessions(db, date);
|
|
261
|
+
const skipId = pickCurrentSessionId(db, date, rawSessions);
|
|
262
|
+
const sessions = skipId
|
|
263
|
+
? rawSessions.filter((s) => s.id !== skipId)
|
|
264
|
+
: rawSessions;
|
|
188
265
|
|
|
189
266
|
if (sessions.length === 0) {
|
|
190
267
|
result.skipped++;
|