clementine-agent 1.0.60 → 1.0.62
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
|
@@ -2571,6 +2571,36 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2571
2571
|
if (!contradictionRetried && attempt < PersonalAssistant.RATE_LIMIT_MAX_RETRIES && responseText.trim()) {
|
|
2572
2572
|
try {
|
|
2573
2573
|
const toolCallRecords = collectToolCalls(collectedSdkMessages);
|
|
2574
|
+
// Diagnostic — emits once per turn so we can see what the
|
|
2575
|
+
// validator is working with even when it doesn't fire. Without
|
|
2576
|
+
// this we're blind to the "regex missed the phrasing" case.
|
|
2577
|
+
if (toolCallRecords.length > 0) {
|
|
2578
|
+
logger.info({
|
|
2579
|
+
sessionKey,
|
|
2580
|
+
sdkMessagesCaptured: collectedSdkMessages.length,
|
|
2581
|
+
toolCallsPaired: toolCallRecords.length,
|
|
2582
|
+
resultClasses: toolCallRecords.map(r => `${r.name}:${r.resultClass}`),
|
|
2583
|
+
firstResultPreview: toolCallRecords[0]?.resultPreview?.slice(0, 300),
|
|
2584
|
+
rawFirstToolResult: (() => {
|
|
2585
|
+
// Dump the raw user-message tool_result block so we can
|
|
2586
|
+
// see is_error + content shape when the classifier picks
|
|
2587
|
+
// a result class that looks wrong (e.g. other_error when
|
|
2588
|
+
// the MCP server actually returned success).
|
|
2589
|
+
for (const msg of collectedSdkMessages) {
|
|
2590
|
+
if (msg.type !== 'user' || !msg.message?.content)
|
|
2591
|
+
continue;
|
|
2592
|
+
const blocks = Array.isArray(msg.message.content) ? msg.message.content : [];
|
|
2593
|
+
for (const b of blocks) {
|
|
2594
|
+
if (b?.type === 'tool_result') {
|
|
2595
|
+
return { is_error: b.is_error, content_shape: Array.isArray(b.content) ? 'array' : typeof b.content, content_head: JSON.stringify(b.content).slice(0, 300) };
|
|
2596
|
+
}
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
return null;
|
|
2600
|
+
})(),
|
|
2601
|
+
replyPreview: responseText.slice(0, 200).replace(/\n/g, ' '),
|
|
2602
|
+
}, 'Contradiction validator pass');
|
|
2603
|
+
}
|
|
2574
2604
|
const finding = detectContradiction(responseText, toolCallRecords);
|
|
2575
2605
|
if (finding) {
|
|
2576
2606
|
contradictionRetried = true;
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
const ARG_ERROR_RE = /\b(invalid|unknown field|required|missing parameter|schema|unrecognized|unexpected property)\b/i;
|
|
16
16
|
const AUTH_ERROR_RE = /\b(unauthori[sz]ed|401|not authenticated|token expired|token has expired|invalid[_ ]?token|access denied)\b/i;
|
|
17
17
|
/** Regex matching reply phrasings that claim a connector-wide failure. */
|
|
18
|
-
export const CONTRADICTION_RE = /(dead\s*end|doesn'?t exist|not in (the |my )?schema|schema[- ]level|aren'?t loading into|(not|isn'?t|aren'?t) (loaded|wired|available|coming through|responding)|connector[^.]{0,40}(dropped|is (a )?dead)|tools? array is empty|MCP server (still connecting|dropped|not responding)|no such tool available|tool doesn'?t exist|both directions are blocked)/i;
|
|
18
|
+
export const CONTRADICTION_RE = /(dead\s*end|doesn'?t exist|not in (the |my )?schema|schema[- ]level|aren'?t loading into|(not|isn'?t|aren'?t|wasn'?t) (loaded|wired|available|connected|coming through|responding|reachable|working)|connector[^.]{0,40}(dropped|is (a )?dead)|tools? array is empty|MCP server (still connecting|dropped|not responding|just isn'?t connected|isn'?t connected)|no such tool available|tool doesn'?t exist|both directions are blocked|(restart|close and reopen|reconnect) Claude Code)/i;
|
|
19
19
|
export function classifyResult(content, isError) {
|
|
20
20
|
if (!isError)
|
|
21
21
|
return 'success';
|