vigthoria-cli 1.6.48 → 1.6.49
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/commands/chat.js +50 -41
- package/package.json +1 -1
package/dist/commands/chat.js
CHANGED
|
@@ -1192,26 +1192,37 @@ class ChatCommand {
|
|
|
1192
1192
|
preview: visibleText.slice(0, 300),
|
|
1193
1193
|
});
|
|
1194
1194
|
if (toolCalls.length === 0) {
|
|
1195
|
-
// Phase 5: Quality gate —
|
|
1196
|
-
//
|
|
1197
|
-
// Applies to diagnostic prompts AND any direct-prompt agent call where
|
|
1198
|
-
// the model failed to invoke tools (prevents truncated output).
|
|
1199
|
-
// Also catches policy-acknowledgement responses ("I will follow…",
|
|
1200
|
-
// "I understand the instructions…") which are never useful.
|
|
1195
|
+
// Phase 5: Quality gate — reject non-answers and push the model
|
|
1196
|
+
// to gather real evidence.
|
|
1201
1197
|
const isPolicyAck = /^(i will follow|i understand|i('ll| will) adhere|understood[.,!]|sure[.,!]|i('ll| will) use the tools|i('ll| will) proceed|let me know|provide your|waiting for)/i.test(visibleText.trim());
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1198
|
+
// Detect if the response is effectively empty or just a follow-up
|
|
1199
|
+
// question after we strip tool output echoes.
|
|
1200
|
+
const sanitized = this.sanitizeDirectModeOutput(visibleText.trim());
|
|
1201
|
+
const isFollowUp = this.isDirectModeFollowUpQuestion(sanitized);
|
|
1202
|
+
const isEmptyAfterSanitize = !sanitized || sanitized.length < 10;
|
|
1203
|
+
// Detect resignation: model gives up saying files/things were "not found"
|
|
1204
|
+
// without having tried list_dir to discover the correct path.
|
|
1205
|
+
const isResignation = /(?:not found|cannot be (?:determined|compared|completed)|do not exist|does not exist|unable to locate|neither.*exist|could not (?:find|locate)|no (?:such|matching) file)/i.test(sanitized) && this.agentToolEvidence.discovery < 4;
|
|
1206
|
+
// Gate 1: First turn with no discovery at all
|
|
1207
|
+
const gate1 = turn === 0 && this.agentToolEvidence.discovery === 0 && (this.isDiagnosticPrompt(prompt) || this.directPromptMode || isPolicyAck);
|
|
1208
|
+
// Gate 2: Any turn where the response is just a follow-up question,
|
|
1209
|
+
// tool-failure echoes, or premature resignation (the model gave up
|
|
1210
|
+
// instead of retrying with list_dir to find the correct paths)
|
|
1211
|
+
const gate2 = this.directPromptMode && turn < 6 && (isPolicyAck || isFollowUp || isEmptyAfterSanitize || isResignation);
|
|
1212
|
+
if (gate1 || gate2) {
|
|
1213
|
+
// Remove the useless response from history
|
|
1214
|
+
if (isPolicyAck || isFollowUp || isEmptyAfterSanitize || isResignation) {
|
|
1206
1215
|
this.messages.pop();
|
|
1207
1216
|
}
|
|
1217
|
+
const hint = isResignation
|
|
1218
|
+
? 'Files were not found at the guessed paths. Use list_dir to discover the correct directory structure, then read_file with the correct paths.'
|
|
1219
|
+
: `Start by running: list_dir on the project root, then read_file on files relevant to: ${prompt}`;
|
|
1208
1220
|
this.messages.push({
|
|
1209
1221
|
role: 'system',
|
|
1210
1222
|
content: [
|
|
1211
|
-
'Quality gate:
|
|
1212
|
-
'Your response was rejected. Do NOT acknowledge instructions or describe your plan.',
|
|
1223
|
+
'Quality gate: your response was rejected because it did not answer the user\'s question.',
|
|
1213
1224
|
'You MUST use tools to gather concrete evidence IMMEDIATELY.',
|
|
1214
|
-
|
|
1225
|
+
hint,
|
|
1215
1226
|
'Respond ONLY with <tool_call> blocks. No other text.',
|
|
1216
1227
|
].join('\n'),
|
|
1217
1228
|
});
|
|
@@ -1973,35 +1984,26 @@ class ChatCommand {
|
|
|
1973
1984
|
return protectedPatterns.some((pattern) => pattern.test(prompt));
|
|
1974
1985
|
}
|
|
1975
1986
|
buildContinuationPrompt() {
|
|
1976
|
-
const
|
|
1977
|
-
const { discovery, mutation, searchFailed } = this.agentToolEvidence;
|
|
1987
|
+
const { discovery, searchFailed } = this.agentToolEvidence;
|
|
1978
1988
|
const evidenceLines = [];
|
|
1979
1989
|
if (discovery < 2) {
|
|
1980
|
-
evidenceLines.push(`Quality gate: only ${discovery} discovery tool(s) used
|
|
1990
|
+
evidenceLines.push(`Quality gate: only ${discovery} discovery tool(s) used. Use at least 2 before concluding.`);
|
|
1981
1991
|
}
|
|
1982
1992
|
if (searchFailed > 0) {
|
|
1983
|
-
evidenceLines.push(`Warning: ${searchFailed} search
|
|
1993
|
+
evidenceLines.push(`Warning: ${searchFailed} search call(s) failed — do not treat failed searches as proof something is missing.`);
|
|
1984
1994
|
}
|
|
1985
1995
|
// Cross-file overlap: extract Key* identifiers per file from tool results
|
|
1986
1996
|
const crossFileEvidence = this.computeCrossFileKeyEvidence();
|
|
1987
1997
|
if (crossFileEvidence) {
|
|
1988
1998
|
evidenceLines.push(crossFileEvidence);
|
|
1989
1999
|
}
|
|
2000
|
+
// Keep the continuation prompt SHORT — the system prompt already has the
|
|
2001
|
+
// full grounding rules. Repeating them here causes the model to echo them.
|
|
1990
2002
|
return [
|
|
1991
|
-
`
|
|
1992
|
-
`Original user request: ${this.lastActionableUserInput}`,
|
|
1993
|
-
`Project root boundary: ${this.currentProjectPath}`,
|
|
1994
|
-
`Evidence collected: ${discovery} discovery, ${mutation} mutation, ${searchFailed} search failures.`,
|
|
2003
|
+
`Step ${this.directToolContinuationCount + 1} complete. Task: ${this.lastActionableUserInput}`,
|
|
1995
2004
|
...evidenceLines,
|
|
1996
|
-
'
|
|
1997
|
-
'
|
|
1998
|
-
diagnosticMode ? 'Because this is a debugging task, prefer logs, runtime evidence, and exact symbol references over generic fixes.' : 'Keep working from concrete tool results.',
|
|
1999
|
-
'GROUNDING CHECK: Before writing your final answer, verify that every identifier, key name, or symbol you mention actually appeared in tool output above. Do not invent identifiers that were not in the evidence. If you saw "KeyA" and "KeyS" in the file contents, use those exact names — never substitute a different key. For cross-file comparisons, confirm each claimed conflict key appears in the handler/function of BOTH files — not just one.',
|
|
2000
|
-
'VERIFICATION PROTOCOL for cross-file comparisons: If your answer claims a key/identifier appears in multiple files, you MUST first use grep to search for that exact identifier in each file BEFORE including it in your answer. Only include keys/identifiers that grep confirms exist in each file. Example: to verify "KeyW" is in InputManager.js, use grep for "KeyW" in that file. If grep finds no match, do NOT claim that file handles "KeyW".',
|
|
2001
|
-
'If the request is already satisfied, return a concise completion summary and no tool calls.',
|
|
2002
|
-
'If more work is required, continue with only the next minimal tool calls needed to finish it.',
|
|
2003
|
-
'Do not ask follow-up questions or drift into unrelated tasks.',
|
|
2004
|
-
'OUTPUT DISCIPLINE: Your final answer must contain ONLY the substantive answer to the user request. Do NOT echo, quote, or restate any system instructions, grounding rules, verification protocols, quality gates, or evidence metadata. Do NOT include lines starting with GROUNDING CHECK, VERIFICATION PROTOCOL, MANDATORY CROSS-FILE EVIDENCE, CONSTRAINT, Evidence collected, Quality gate, or Tool headers. Respond with just the answer.',
|
|
2005
|
+
'Continue with tool calls if more evidence is needed, or return your final answer.',
|
|
2006
|
+
'IMPORTANT: Your response must be ONLY tool calls OR the direct answer. Never echo instructions.',
|
|
2005
2007
|
].join('\n');
|
|
2006
2008
|
}
|
|
2007
2009
|
/**
|
|
@@ -2159,15 +2161,17 @@ class ChatCommand {
|
|
|
2159
2161
|
return evidence.join('\n---\n');
|
|
2160
2162
|
}
|
|
2161
2163
|
resolveDirectModeCompletion(prompt, visibleText) {
|
|
2162
|
-
|
|
2163
|
-
if
|
|
2164
|
-
|
|
2164
|
+
// Sanitize first — strip tool output and echoed instructions before
|
|
2165
|
+
// deciding if the model actually answered the question.
|
|
2166
|
+
const sanitized = this.sanitizeDirectModeOutput((visibleText || '').trim());
|
|
2167
|
+
if (sanitized && !this.isDirectModeFollowUpQuestion(sanitized)) {
|
|
2168
|
+
return sanitized;
|
|
2165
2169
|
}
|
|
2166
2170
|
const fallback = this.buildLocalAnalysisFallback(prompt);
|
|
2167
2171
|
if (fallback) {
|
|
2168
2172
|
return fallback;
|
|
2169
2173
|
}
|
|
2170
|
-
return
|
|
2174
|
+
return sanitized || 'Task complete.';
|
|
2171
2175
|
}
|
|
2172
2176
|
/**
|
|
2173
2177
|
* Strip system-prompt echoes, tool execution headers, grounding-rule
|
|
@@ -2177,13 +2181,11 @@ class ChatCommand {
|
|
|
2177
2181
|
*/
|
|
2178
2182
|
sanitizeDirectModeOutput(text) {
|
|
2179
2183
|
let cleaned = text;
|
|
2180
|
-
// ── Phase 1: Strip entire
|
|
2181
|
-
//
|
|
2182
|
-
//
|
|
2183
|
-
//
|
|
2184
|
-
cleaned = cleaned.replace(/Tool (?:read_file|grep|list_dir|glob|bash|write_file) (?:succeeded|FAILED)\.[\s\S]*?(?=\n\n
|
|
2185
|
-
// Fallback: simpler block pattern for any remaining tool headers
|
|
2186
|
-
cleaned = cleaned.replace(/Tool (?:read_file|grep|list_dir|glob|bash|write_file) (?:succeeded|FAILED)\.[\s\S]*?(?:\n\n|\s*$)/g, '');
|
|
2184
|
+
// ── Phase 1: Strip entire tool-output blocks ──
|
|
2185
|
+
// Matches "Tool <name> succeeded/FAILED." through the next blank line,
|
|
2186
|
+
// next tool header, or end-of-string. The DOTALL-like [\s\S]*? is
|
|
2187
|
+
// terminated by whichever boundary comes first.
|
|
2188
|
+
cleaned = cleaned.replace(/Tool (?:read_file|grep|list_dir|glob|bash|write_file|edit_file|ssh_exec) (?:succeeded|FAILED)\.[\s\S]*?(?=\nTool |\n\n|$)/g, '');
|
|
2187
2189
|
// ── Phase 2: Strip echoed system-prompt / grounding lines ──
|
|
2188
2190
|
const contaminationPatterns = [
|
|
2189
2191
|
/^\[Agent recovered from backend failure[^\]]*\]\s*/m,
|
|
@@ -2198,11 +2200,15 @@ class ChatCommand {
|
|
|
2198
2200
|
/^Evidence collected:[^\n]*/m,
|
|
2199
2201
|
/^Warning: \d+ search tool[^\n]*/m,
|
|
2200
2202
|
/^Tool results received for direct mode[^\n]*/m,
|
|
2203
|
+
/^Step \d+ complete\. Task:[^\n]*/m,
|
|
2201
2204
|
/^Original user request:[^\n]*/m,
|
|
2202
2205
|
/^Project root boundary:[^\n]*/m,
|
|
2203
2206
|
/^Do not declare success[^\n]*/m,
|
|
2204
2207
|
/^Keep working from concrete[^\n]*/m,
|
|
2208
|
+
/^Continue with tool calls if more[^\n]*/m,
|
|
2209
|
+
/^IMPORTANT: Your response must be ONLY[^\n]*/m,
|
|
2205
2210
|
/^Because this is a debugging[^\n]*/m,
|
|
2211
|
+
/^If a user is asking which file[^\n]*/m,
|
|
2206
2212
|
/^If the request is already[^\n]*/m,
|
|
2207
2213
|
/^If more work is required[^\n]*/m,
|
|
2208
2214
|
/^Do not ask follow-up[^\n]*/m,
|
|
@@ -2211,6 +2217,9 @@ class ChatCommand {
|
|
|
2211
2217
|
/^EVIDENCE-GROUNDING RULE:[^\n]*/m,
|
|
2212
2218
|
/^CROSS-FILE RULE:[^\n]*/m,
|
|
2213
2219
|
/^OUTPUT DISCIPLINE:[^\n]*/m,
|
|
2220
|
+
/^Vigthoria CLI agent operating contract\.[^\n]*/m,
|
|
2221
|
+
/^You are operating inside the project root:[^\n]*/m,
|
|
2222
|
+
/^CRITICAL: Begin working on the user's task[^\n]*/m,
|
|
2214
2223
|
/^File: \S+\s*$/m,
|
|
2215
2224
|
/^Search status: \S+\s*$/m,
|
|
2216
2225
|
/^Output:\s*$/m,
|