fix: resolve typing hang, intent detector reversed .test() bugs, and 'now' false positive

- Add missing clearInterval(typingInterval) in intent bypass early return path
- Fix intent-detector category detection: pattern.test(regex) → regex.test(trimmed)
- Fix short-answer patterns: same reversed .test() bug
- Prevent 'now' being matched as 'no' by adding \b word boundary to greeting regex
- Also tighten other greeting patterns with $ anchor where appropriate
This commit is contained in:
Kilo
2026-05-06 17:38:24 +00:00
Unverified
parent 994c5481bf
commit 20d5cc08fc
3 changed files with 30 additions and 22 deletions

13
package-lock.json generated
View File

@@ -1,12 +1,13 @@
{ {
"name": "zcode-cli-x", "name": "zcode-cli-x",
"version": "1.0.0", "version": "2.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "zcode-cli-x", "name": "zcode-cli-x",
"version": "1.0.0", "version": "2.0.0",
"license": "MIT",
"dependencies": { "dependencies": {
"@anthropic-ai/sdk": "^0.81.0", "@anthropic-ai/sdk": "^0.81.0",
"@grammyjs/auto-retry": "^2.0.2", "@grammyjs/auto-retry": "^2.0.2",
@@ -31,8 +32,14 @@
"bin": { "bin": {
"zcode": "bin/zcode.js" "zcode": "bin/zcode.js"
}, },
"devDependencies": {},
"engines": { "engines": {
"node": ">=20.0.0" "node": ">=20.0.0",
"npm": ">=9.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/uroma2"
} }
}, },
"node_modules/@anthropic-ai/sdk": { "node_modules/@anthropic-ai/sdk": {

View File

@@ -1256,14 +1256,14 @@ export async function initBot(config, api, tools, skills, agents) {
try { try {
// ── Intent detection: bypass AI for simple messages ── // ── Intent detection: bypass AI for simple messages ──
const intent = detectIntent(text); const intent = detectIntent(text);
if (intent && intent.bypassAI) { if (intent && intent.bypassAI) {
logger.info(`🎯 Intent: ${intent.type} — bypassing AI`); logger.info(`🎯 Intent: ${intent.type} — bypassing AI`);
const reply = intent.response || 'Got it.'; clearInterval(typingInterval);
await queueRequest(key, text, async () => { const reply = intent.response || 'Got it.';
await sendFormatted(ctx, reply); await sendFormatted(ctx, reply);
}); return;
return; }
}
// ── Load conversation history for this chat ── // ── Load conversation history for this chat ──
const chatKey = conversation._key(ctx.chat.id, ctx.message?.message_thread_id); const chatKey = conversation._key(ctx.chat.id, ctx.message?.message_thread_id);

View File

@@ -18,9 +18,9 @@ const GREETINGS = [
/^(hi|hey|hello|howdy|greetings|sup|yo|what'?s up|what'?s up|how are you|how's it going|how do you do)/i, /^(hi|hey|hello|howdy|greetings|sup|yo|what'?s up|what'?s up|how are you|how's it going|how do you do)/i,
/^(good morning|good afternoon|good evening|good night)/i, /^(good morning|good afternoon|good evening|good night)/i,
/^(thanks|thank you|thx|ty|appreciate it)/i, /^(thanks|thank you|thx|ty|appreciate it)/i,
/^(ok|okay|alright|sure|yes|yeah|yep|nope|no)/i, /^(?:ok|okay|alright|sure|yes|yeah|yep|nope|no)\b/i,
/^(continue|go ahead|proceed|do it|carry on|keep going)/i, /^(continue|go ahead|proceed|do it|carry on|keep going)$/i,
/^(done|finished|completed|all good|looks good)/i, /^(done|finished|completed|all good|looks good)$/i,
/^(bye|goodbye|see you|later|take care)/i, /^(bye|goodbye|see you|later|take care)/i,
]; ];
@@ -76,11 +76,12 @@ export function detectIntent(message) {
}; };
let category = 'greeting'; let category = 'greeting';
if (pattern.test(/^(thanks|thank you|thx|ty)/i)) category = 'thanks'; if (/^(thanks|thank you|thx|ty|appreciate it)/i.test(trimmed)) category = 'thanks';
else if (pattern.test(/^(bye|goodbye|see you|later)/i)) category = 'goodbye'; else if (/^(bye|goodbye|see you|later|take care)/i.test(trimmed)) category = 'goodbye';
else if (pattern.test(/^(ok|okay|alright|sure|yes|yeah)/i)) category = 'confirmation'; else if (/^(ok|okay|alright|sure|yes|yeah|yep|nope|no)/i.test(trimmed)) category = 'confirmation';
else if (pattern.test(/^(continue|go ahead|proceed)/i)) category = 'continue'; else if (/^(continue|go ahead|proceed|do it|carry on|keep going)/i.test(trimmed)) category = 'continue';
else if (pattern.test(/^(good morning|good afternoon|good evening)/i)) category = 'greeting'; else if (/^(done|finished|completed|all good|looks good)/i.test(trimmed)) category = 'completion';
else if (/^(good morning|good afternoon|good evening)/i.test(trimmed)) category = 'greeting';
const list = responses[category] || responses['greeting']; const list = responses[category] || responses['greeting'];
return { return {
@@ -106,21 +107,21 @@ export function detectIntent(message) {
if (pattern.test(trimmed)) { if (pattern.test(trimmed)) {
if (type === 'instant') { if (type === 'instant') {
const now = new Date(); const now = new Date();
if (pattern.test(/what time/i)) { if (/what time/i.test(trimmed)) {
return { return {
type: 'instant', type: 'instant',
response: `🕐 ${now.toLocaleTimeString('en-US', { timeZone: 'Asia/Tbilisi' })} (Tbilisi time)`, response: `🕐 ${now.toLocaleTimeString('en-US', { timeZone: 'Asia/Tbilisi' })} (Tbilisi time)`,
bypassAI: true, bypassAI: true,
}; };
} }
if (pattern.test(/what date|what day/i)) { if (/(what date|what day)/i.test(trimmed)) {
return { return {
type: 'instant', type: 'instant',
response: `📅 ${now.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}`, response: `📅 ${now.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}`,
bypassAI: true, bypassAI: true,
}; };
} }
if (pattern.test(/who are you|what are you/i)) { if (/(who are you|what are you)/i.test(trimmed)) {
return { return {
type: 'instant', type: 'instant',
response: '⚡ I\'m zCode CLI X — an agentic coding assistant running on Telegram. I can read/write files, run bash commands, manage git repos, search the web, and more.', response: '⚡ I\'m zCode CLI X — an agentic coding assistant running on Telegram. I can read/write files, run bash commands, manage git repos, search the web, and more.',