diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index 3a1ec617..954da1b9 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -49,8 +49,13 @@ type AgentPhase = const TOOL_BUDGETS: Record = { conversational: 1, // Must be at least 1 so the LLM gets called for a text reply - status_check: 5, - diagnose: 8, + // Investigative questions ("is the auth connected?", "what's the test user?") + // routinely need to read several files THEN synthesize an answer. Budgets of + // 5/8 were cutting these off at the cap before the model could answer + // (telemetry showed 100% round_cap on these turns). Raised so a read-only + // investigation can actually finish. + status_check: 12, + diagnose: 15, small_fix: 18, feature_build: 40, deploy: 25, @@ -87,14 +92,36 @@ function classifyTurnIntent(message: string): TurnIntent { ) return "diagnose"; - // Status check + // Status check / investigative questions (read-only). + // These need a real tool budget because answering a question about the + // codebase ("is the auth wired up?", "is there a users table?") legitimately + // requires reading files before responding. if ( - /(status|logs|running|active|what is|show me|check|where|how|what)/.test(m) + /(status|logs|running|active|what is|show me|check|where|how|what|which|whose)/.test( + m, + ) || + // Yes/no investigative question starters: "is/are/does/do/can/has/have/did ..." + /^(is|are|does|do|can|could|has|have|had|did|should|would|will)\b/.test( + m, + ) || + // Investigative vocabulary anywhere in the message + /\b(connected|hooked up|wired( up)?|set ?up|configured|working|exists?|stored|present|enabled)\b/.test( + m, + ) || + // Any message phrased as a question + m.endsWith("?") ) return "status_check"; - // Conversational fallback - if (m.length < 5 || /^(hi|hello|thanks|ok|yes|no)/.test(m)) + // Conversational fallback — ONLY when the entire message is a greeting or a + // bare acknowledgement. Previously `/^(ok|...)/` matched "ok" as a prefix of + // "okay ", misclassifying real work as chat (budget 1) and + // causing round_cap cut-offs. Require the whole message to be the ack. + if ( + /^(hi|hey|hello|yo|thanks|thank you|ok|okay|kk|k|yes|yep|yeah|yup|no|nope|nah|sure|cool|nice|great|awesome|perfect)[\s!.?]*$/.test( + m, + ) + ) return "conversational"; // Default to a generous feature build if we can't tell