clementine-agent 1.16.0 → 1.17.0
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
CHANGED
|
@@ -4769,13 +4769,28 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
4769
4769
|
// Periodic progress beacon — sends a status update every 5 minutes
|
|
4770
4770
|
// so the user knows the task is still alive during long phases.
|
|
4771
4771
|
// Capped at 3 messages per phase to prevent notification spam.
|
|
4772
|
+
// Also refreshes status.json so dashboard polls see liveness even
|
|
4773
|
+
// when the SDK stream hasn't emitted a result yet.
|
|
4772
4774
|
const BEACON_INTERVAL_MS = 5 * 60 * 1000;
|
|
4773
4775
|
const MAX_BEACONS_PER_PHASE = 3;
|
|
4774
4776
|
let beaconCount = 0;
|
|
4775
4777
|
const beaconTimer = setInterval(() => {
|
|
4778
|
+
const mins = Math.round((Date.now() - phaseStart) / 60_000);
|
|
4779
|
+
try {
|
|
4780
|
+
writeStatus({
|
|
4781
|
+
jobName,
|
|
4782
|
+
status: 'running',
|
|
4783
|
+
phase,
|
|
4784
|
+
startedAt,
|
|
4785
|
+
maxHours: effectiveMaxHours,
|
|
4786
|
+
phaseStartedAt: new Date(phaseStart).toISOString(),
|
|
4787
|
+
phaseElapsedMin: mins,
|
|
4788
|
+
toolCallsThisPhase: phaseToolCount,
|
|
4789
|
+
});
|
|
4790
|
+
}
|
|
4791
|
+
catch { /* non-fatal */ }
|
|
4776
4792
|
if (this.onPhaseProgress && beaconCount < MAX_BEACONS_PER_PHASE) {
|
|
4777
4793
|
beaconCount++;
|
|
4778
|
-
const mins = Math.round((Date.now() - phaseStart) / 60_000);
|
|
4779
4794
|
try {
|
|
4780
4795
|
// Conversational beacon — no technical jargon
|
|
4781
4796
|
const msg = mins < 3
|
|
@@ -4826,6 +4841,22 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
4826
4841
|
// Capture terminal reason for execution advisor
|
|
4827
4842
|
this._lastTerminalReason = result.terminal_reason ?? undefined;
|
|
4828
4843
|
this.logQueryResult(result, 'unleashed', `unleashed:${jobName}`, jobName);
|
|
4844
|
+
// Refresh status.json the moment the SDK reports result —
|
|
4845
|
+
// even if the underlying stream stalls afterward, the dashboard
|
|
4846
|
+
// sees liveness instead of a frozen "phase 0 / running" row.
|
|
4847
|
+
try {
|
|
4848
|
+
writeStatus({
|
|
4849
|
+
jobName,
|
|
4850
|
+
status: 'running',
|
|
4851
|
+
phase,
|
|
4852
|
+
startedAt,
|
|
4853
|
+
maxHours: effectiveMaxHours,
|
|
4854
|
+
lastResultAt: new Date().toISOString(),
|
|
4855
|
+
lastResultIsError: !!result.is_error,
|
|
4856
|
+
toolCallsThisPhase: phaseToolCount,
|
|
4857
|
+
});
|
|
4858
|
+
}
|
|
4859
|
+
catch { /* non-fatal */ }
|
|
4829
4860
|
// Detect dollar-budget exceeded (strict marker — see cron
|
|
4830
4861
|
// handler above for the reasoning).
|
|
4831
4862
|
if (result.is_error && 'result' in result) {
|
|
@@ -50,6 +50,21 @@ const CHAIN_MARKERS = [
|
|
|
50
50
|
/\bonce\s+(that|you)\b.*,/i,
|
|
51
51
|
/\bnext\b.*,/i,
|
|
52
52
|
];
|
|
53
|
+
/**
|
|
54
|
+
* Patterns that look like a pasted error message or stack trace.
|
|
55
|
+
* Error pastes are long and entity-heavy (file paths, quoted strings,
|
|
56
|
+
* "Error:" prefixes), which previously tripped the deepWorthy gate
|
|
57
|
+
* even when the user was just asking "what's wrong with this?". We
|
|
58
|
+
* still allow the plan-first directive to fire; we just don't auto-spawn
|
|
59
|
+
* an expensive multi-phase background task on a debug request.
|
|
60
|
+
*/
|
|
61
|
+
const ERROR_PASTE_MARKERS = [
|
|
62
|
+
/\b(Error|Exception|Traceback|Stack ?trace):\s/i,
|
|
63
|
+
/^\s*at\s+[\w.$<>]+\s*\(/m, // JS/TS stack frame: "at foo.bar (file:line)"
|
|
64
|
+
/\bfailed:\s*Error\b/i,
|
|
65
|
+
/Reached maximum number of turns/i,
|
|
66
|
+
/\bENOENT\b|\bECONNREFUSED\b|\bETIMEDOUT\b/,
|
|
67
|
+
];
|
|
53
68
|
/**
|
|
54
69
|
* Phrasings that explicitly ask for plan-first behavior. Triggers
|
|
55
70
|
* regardless of other heuristics.
|
|
@@ -148,7 +163,14 @@ export function classifyComplexity(text) {
|
|
|
148
163
|
isLong,
|
|
149
164
|
entities >= 3,
|
|
150
165
|
].filter(Boolean).length;
|
|
151
|
-
|
|
166
|
+
// Suppress deepWorthy on pasted error messages. They're long and
|
|
167
|
+
// entity-heavy (file paths, quoted strings) but the user is asking
|
|
168
|
+
// "what's wrong here?", not requesting sustained autonomous work.
|
|
169
|
+
// The plan-first path still fires when complex=true.
|
|
170
|
+
const looksLikeErrorPaste = ERROR_PASTE_MARKERS.some((re) => re.test(trimmed));
|
|
171
|
+
if (looksLikeErrorPaste)
|
|
172
|
+
signals.push('error-paste');
|
|
173
|
+
const deepWorthy = strongCount >= 2 && !looksLikeErrorPaste;
|
|
152
174
|
if (complex) {
|
|
153
175
|
return {
|
|
154
176
|
complex: true,
|