Skip to content

Comments

AI-powered duplicate detection for auto-triage#470

Open
jfcsantos wants to merge 10 commits intomainfrom
jsantos/auto-triage-duplicate-cloud
Open

AI-powered duplicate detection for auto-triage#470
jfcsantos wants to merge 10 commits intomainfrom
jsantos/auto-triage-duplicate-cloud

Conversation

@jfcsantos
Copy link
Contributor

Summary

Replaces the simple 0.9 embedding-similarity threshold for duplicate detection with an AI-powered semantic verification step. The Milvus embedding search now acts as a candidate filter (≥ 0.8 similarity), and the Cloud Agent verifies whether any candidate is a true duplicate using LLM reasoning.

Changes

Duplicate detection is now two stages instead of one

  • Previously, the check-duplicates endpoint both found similar issues and decided whether they were duplicates (≥ 0.9 similarity = duplicate). Now it only returns similarity candidates — the decision moves to the worker.
  • The worker sends the candidates to the Cloud Agent, which uses LLM reasoning to determine if any candidate is a true semantic duplicate, with confidence scoring and structured reasoning.
  • If the AI verification fails for any reason, the system falls back to the original threshold-based logic.
  • Duplicate closure comments now include AI reasoning when available.

Cloud Agent supports prompt-only sessions

  • Some workflows (classification, duplicate verification) only need a text prompt — no codebase. Previously, every session required a repo, which meant cloning a repo that was never used.
  • The initiateSessionStream endpoint now allows omitting the repo when the mode is ask. All other modes (code, architect, debug, orchestrator) still require a repo, so existing flows are unaffected.
  • The session service skips branch checkout when no repo was cloned.

UI error sanitization

  • System errors (SQL, connection failures, stack traces) are no longer shown raw in toast messages. A shared friendlyErrorMessage utility filters them into a generic user-facing message.

@jfcsantos
Copy link
Contributor Author

@eshurakov ccing you since I'm modifying some cloud-agent code here.

@kiloconnect
Copy link
Contributor

kiloconnect bot commented Feb 23, 2026

Code Review Summary

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
src/components/auto-triage/AutoTriageTicketsCard.tsx 509 Hardcoded generic error message replaces actual ticket.error_message in admin-facing component, losing debugging info
Other Observations (not in diff)

Issues found in new/unchanged code that are worth noting:

File Line Issue
cloudflare-auto-triage-infra/src/parsers/duplicate-verification-parser.ts 19 parseDuplicateVerification is exported but never imported or used anywhere in the codebase. The actual duplicate verification uses tool-calling in route.ts instead. This entire file appears to be dead code.
cloudflare-auto-triage-infra/src/services/prompt-builder.ts 119 buildDuplicateVerificationPrompt is exported but never imported or used. The route builds its own prompt inline.
cloudflare-auto-triage-infra/src/types.ts 115 DuplicateCandidates type is defined but never used anywhere.
Files Reviewed (10 files)
  • cloud-agent/src/router/schemas.ts - 0 issues (validation correctly relaxed for ask mode)
  • cloud-agent/src/session-service.ts - 0 issues (branch checkout correctly guarded)
  • cloudflare-auto-triage-infra/src/parsers/duplicate-verification-parser.ts - dead code (see observations)
  • cloudflare-auto-triage-infra/src/services/cloud-agent-client.ts - 0 issues
  • cloudflare-auto-triage-infra/src/services/prompt-builder.ts - dead code (see observations)
  • cloudflare-auto-triage-infra/src/triage-orchestrator.ts - 0 new issues
  • cloudflare-auto-triage-infra/src/types.ts - dead code (see observations)
  • src/app/api/internal/triage/check-duplicates/route.ts - 0 issues (AI verification with fallback well-structured)
  • src/components/auto-triage/AutoTriageConfigForm.tsx - 0 new issues
  • src/components/auto-triage/AutoTriageTicketsCard.tsx - 1 issue

Fix these issues in Kilo Cloud

Add timeout protection, low-confidence guard, and hallucination
handling to the AI duplicate verification flow.

- Wrap processStream in Promise.race with a 2-minute timeout to
  prevent the Durable Object from hanging indefinitely on stalled
  SSE streams; clear the timer in a finally block
- Reject duplicate verdicts where AI confidence is below 0.5 to
  avoid false positives from uncertain model responses
- Treat AI-hallucinated issue numbers (not present in the candidate
  set) as non-duplicates instead of propagating an unreliable result
- Remove optional chaining on matchedTicket fields now that the
  hallucination case exits early, making the happy path explicit
- Escape Markdown special characters in AI reasoning before
  embedding it in GitHub comments to prevent formatting corruption
@@ -79,8 +84,30 @@ export class TriageOrchestrator extends DurableObject<Env> {
await this.ctx.storage.setAlarm(Date.now() + alarmTimeout);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[WARNING]: Alarm timeout no longer accounts for the full pipeline duration

The alarm budget comment (lines 80-82) says the 2-minute buffer covers "duplicate check + classification + label/comment API calls". However, the new verifyDuplicatesWithAI() step has its own 2-minute timeout (line 316), which means the worst-case pipeline is now:

  • Embedding HTTP call (~seconds)
  • AI duplicate verification (up to 2 min)
  • Classification (up to 5 min default)
  • Label/comment API calls (~seconds)

Total worst case ≈ 7+ minutes, but the alarm is set to classificationTimeout + 120_000 = 7 minutes exactly, leaving no buffer for the overhead. Consider adding the duplicate verification timeout to the alarm budget:

Suggested change
await this.ctx.storage.setAlarm(Date.now() + alarmTimeout);
await this.ctx.storage.setAlarm(Date.now() + alarmTimeout + 120_000);

Or better, update alarmTimeout on line 83 to include the duplicate verification budget explicitly.

@@ -94,7 +94,8 @@ export function AutoTriageConfigForm({ organizationId }: AutoTriageConfigFormPro
},
onError: error => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[WARNING]: Unused error parameter will cause a lint error

The error parameter was previously used (error.message) but is now unused since the description was replaced with a static string. With @typescript-eslint/no-unused-vars configured as 'error' in eslint.config.mjs, this will fail the build.

This same issue applies to all 4 onError callbacks in this file (lines 95, 110, 127, 142). Either prefix with _ or remove the parameter:

Suggested change
onError: error => {
onError: _error => {

@@ -138,7 +138,8 @@ export function AutoTriageTicketsCard({ organizationId }: AutoTriageTicketsCardP
},
onError: error => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[WARNING]: Unused error parameter will cause a lint error

Same issue as in AutoTriageConfigForm.tsx — the error parameter is no longer used after replacing error.message with a static string. This applies to all 4 onError callbacks in this file (lines 139, 165, 194, 220).

Suggested change
onError: error => {
onError: _error => {

Comment on lines 284 to 293
// No githubRepo — the prompt is pure text, no codebase access needed.
const sessionInput = {
kilocodeOrganizationId: this.state.owner.type === 'org' ? this.state.owner.id : undefined,
prompt,
mode: 'ask' as const,
model: this.state.sessionInput.modelSlug,
createdOnPlatform: 'auto-triage',
};

const cloudAgentClient = new CloudAgentClient(this.env.CLOUD_AGENT_URL, this.state.authToken);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you don't need repo access, it may be faster and easier to just go directly to LLM. Search for sendProxiedChatCompletion

Error: {ticket.error_message}
Error:{' '}
{
'Something went wrong. Please try again or contact support if the problem persists.'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[WARNING]: This admin-facing error display now shows a hardcoded generic message instead of the actual ticket.error_message. While hiding raw errors in toast notifications (user-facing) makes sense, this component appears to be an admin/dashboard view where the real error message is valuable for debugging.

Consider keeping the original ticket.error_message here, or showing both (generic message + details in a collapsible/tooltip).

Suggested change
'Something went wrong. Please try again or contact support if the problem persists.'
ticket.error_message

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants