From f63abd67a705e4dae1ab308efe5b2d72052d9e30 Mon Sep 17 00:00:00 2001 From: Tajudeen Date: Thu, 23 Jul 2026 16:09:56 +0100 Subject: [PATCH] Wire classifyCompletionState into synthesis tool paths and add Phase 2 CDP probe script. Intent and how-many search synthesis branches now use the shared completion classifier instead of inline interrupt/completion checks, keeping agent-loop exit semantics consistent with the main tool path. Co-authored-by: Cursor --- package.json | 1 + .../cortexide/browser/chatThreadService.ts | 39 ++++++++++++++----- test/cortexide-smoke/README.md | 8 +++- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 658c79a0d8a..c27868e9455 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "test-phase0-qa": "npm run test-node -- --runGlob \"**/cortexide/test/common/{providerSettingsValidation,onboardingHelpers,attachFileToChat,chatThreadStorageReviver,providerToolFormat,phase0ClaimVerification,modelCapabilities,menubarStackingFix,designSystem,atReferenceTokens,resolveAtReferences,prepareChatAttachments}.test.js\"", "test-phase1-safety-cdp": "node test/cortexide-smoke/phase1-safety-verify.mjs", "test-phase2-qa": "npm run test-node -- --runGlob \"**/cortexide/test/common/{agentLoopDecisions,toolPermissions,toolSynthesisDecision,toolCallRecognition}.test.js\"", + "test-phase2-cap-cdp": "node test/cortexide-smoke/phase2-cap-escalation-probe.mjs", "test-cortexide-qa": "npm run test-phase0-qa && npm run test-phase2-qa", "test-extension": "vscode-test", "test-build-scripts": "cd build && npm run test", diff --git a/src/vs/workbench/contrib/cortexide/browser/chatThreadService.ts b/src/vs/workbench/contrib/cortexide/browser/chatThreadService.ts index c086c8f1288..7dfaab55f93 100644 --- a/src/vs/workbench/contrib/cortexide/browser/chatThreadService.ts +++ b/src/vs/workbench/contrib/cortexide/browser/chatThreadService.ts @@ -4608,17 +4608,28 @@ Output ONLY the JSON, no other text. Start with { and end with }.` isCapableLocalModelFlag, // a capable local model (>=7B, coder or general) is allowed the web tools at the chokepoint too ) - if (interrupted) { + const intentSynthOutcome = classifyCompletionState({ + toolCall: { name: toolName }, + completionSignaled: hwCompletion, + interrupted, + awaitingUserApproval, + fileReadLimitExceeded: false, + readFileLimitReached: false, + synthFired: false, + synthCompletionSignaled: false, + synthInterrupted: false, + }) + if (intentSynthOutcome.action === 'terminate_interrupted') { this._setStreamState(threadId, undefined) return } - if (hwCompletion) { + if (intentSynthOutcome.action === 'terminate_completion') { this._setStreamState(threadId, { isRunning: undefined }) return } - if (awaitingUserApproval) { + if (intentSynthOutcome.action === 'await_user') { isRunningWhenEnd = 'awaiting_user' - } else { + } else if (intentSynthOutcome.action === 'continue') { shouldSendAnotherMessage = true } @@ -4693,12 +4704,22 @@ Output ONLY the JSON, no other text. Start with { and end with }.` isCapableLocalModelFlag, // a capable local model (>=7B, coder or general) is allowed the web tools at the chokepoint too ) - if (interrupted) { + const howManySynthOutcome = classifyCompletionState({ + toolCall: { name: toolName }, + completionSignaled: synthCompletion, + interrupted, + awaitingUserApproval, + fileReadLimitExceeded: false, + readFileLimitReached: false, + synthFired: false, + synthCompletionSignaled: false, + synthInterrupted: false, + }) + if (howManySynthOutcome.action === 'terminate_interrupted') { this._setStreamState(threadId, undefined) return } - - if (synthCompletion) { + if (howManySynthOutcome.action === 'terminate_completion') { this._setStreamState(threadId, { isRunning: undefined }) return } @@ -4706,9 +4727,9 @@ Output ONLY the JSON, no other text. Start with { and end with }.` (toolsExecutedInRequest as string[]).push(toolName) hasSynthesizedToolsInThisRequest = true - if (awaitingUserApproval) { + if (howManySynthOutcome.action === 'await_user') { isRunningWhenEnd = 'awaiting_user' - } else { + } else if (howManySynthOutcome.action === 'continue') { shouldSendAnotherMessage = true } diff --git a/test/cortexide-smoke/README.md b/test/cortexide-smoke/README.md index cb748bfbf2c..0f95a3b0b17 100644 --- a/test/cortexide-smoke/README.md +++ b/test/cortexide-smoke/README.md @@ -15,7 +15,9 @@ Chrome DevTools Protocol (CDP). Used to confirm the editor actually boots and it - `phase1-safety-verify.mjs` — CDP regression for Phase 1 safety: loads real transpiled `toolPermissions` / `commandRisk` in the live renderer, exercises gather/agent/untrusted decisions, and confirms `cortexide.*` safety settings registered at startup. -- `run-phase0-qa.sh` — runs `npm run test-phase0-qa` (unit) and optionally `--cdp` live verify +- `phase2-cap-escalation-probe.mjs` — optional CDP probe for Phase 2 agent-loop cap/escalation + markers (needs Ollama + a small local model; slow — manual only). +- `run-phase0-qa.sh` — runs `npm run test-cortexide-qa` (unit) and optionally `--cdp` live verify (Phase 0 UI + Phase 1 safety). ## Usage @@ -47,6 +49,10 @@ test/cortexide-smoke/run-phase0-qa.sh --cdp # Phase 1 safety only (app must already be running on the CDP port): npm run test-phase1-safety-cdp # or: node test/cortexide-smoke/phase1-safety-verify.mjs --port 9222 + +# Phase 2 cap/escalation probe (optional — needs Ollama + small model, slow): +npm run test-phase2-cap-cdp +# or: CX_WS=/tmp/cx-p2-cap-ws node test/cortexide-smoke/phase2-cap-escalation-probe.mjs --port 9222 ``` CI: `.github/workflows/phase0-qa.yml` runs unit tests on every PR/push to `main`.