From f587ef679ca802370091d3d1eb41dc6f1b915fa6 Mon Sep 17 00:00:00 2001 From: roblourens Date: Wed, 12 Aug 2026 18:26:39 -0700 Subject: [PATCH] Improve Agent Host E2E test coverage (#330550) Improve Agent Host E2E coverage (Written by Copilot) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../agentHost/test/node/e2e/KNOWN_ISSUES.md | 17 + ...-a-fenced-multiline-markdown-response.yaml | 21 + ...-a-fenced-multiline-markdown-response.yaml | 21 + ...-a-fenced-multiline-markdown-response.yaml | 21 + .../test/node/e2e/coverage/summary.json | 2468 ++++++++++------- .../node/e2e/suites/agentHostE2ESuites.ts | 2 + .../test/node/e2e/suites/changesetSuite.ts | 130 +- .../node/e2e/suites/clientFilesystemSuite.ts | 37 + .../test/node/e2e/suites/coreSuite.ts | 24 + .../test/node/e2e/suites/e2eTestContext.ts | 2 + .../node/e2e/suites/protocolContractsSuite.ts | 243 +- 11 files changed, 1968 insertions(+), 1018 deletions(-) create mode 100644 src/vs/platform/agentHost/test/node/e2e/captures/claude-preserves-a-fenced-multiline-markdown-response.yaml create mode 100644 src/vs/platform/agentHost/test/node/e2e/captures/codex-preserves-a-fenced-multiline-markdown-response.yaml create mode 100644 src/vs/platform/agentHost/test/node/e2e/captures/copilotcli-preserves-a-fenced-multiline-markdown-response.yaml diff --git a/src/vs/platform/agentHost/test/node/e2e/KNOWN_ISSUES.md b/src/vs/platform/agentHost/test/node/e2e/KNOWN_ISSUES.md index bf1fbbd9f50..1404464ca7e 100644 --- a/src/vs/platform/agentHost/test/node/e2e/KNOWN_ISSUES.md +++ b/src/vs/platform/agentHost/test/node/e2e/KNOWN_ISSUES.md @@ -16,6 +16,23 @@ When a valid E2E scenario exposes a gap: Capability skips are tracked separately from suspected bugs. A provider that does not advertise a capability is expected to skip positive-path tests for that capability. +### Duplicate session creation is accepted + +A client can retry session creation with a URI that already identifies a live session. The host accepts the duplicate request instead of reporting that the resource already exists, so clients cannot distinguish an idempotent retry from an accidental collision and a provider may be asked to create conflicting backing state. + +- Test: `creating a duplicate session resource is rejected`. +- Scope: conformance reference provider on all platforms. +- Expected: the second AHP `createSession` request fails with `SessionAlreadyExists`. +- Observed: the second request resolves successfully. +- Gate: the scenario requires `AGENT_HOST_RUN_KNOWN_ISSUES=1`. +- Reproduce: + + ```bash + AGENT_HOST_RUN_KNOWN_ISSUES=1 ./scripts/test-integration.sh --run \ + src/vs/platform/agentHost/test/node/e2e/conformance/agentHostConformance.integrationTest.ts \ + --grep "creating a duplicate session resource is rejected" + ``` + ### Deleting a worktree session can race background Git work A user can configure ignored files to be copied into an isolated worktree, complete an agent turn, and then delete the session. Session deletion can fail because background changeset or Git-state work is still using the worktree while Git removes it, leaving the session's worktree behind. diff --git a/src/vs/platform/agentHost/test/node/e2e/captures/claude-preserves-a-fenced-multiline-markdown-response.yaml b/src/vs/platform/agentHost/test/node/e2e/captures/claude-preserves-a-fenced-multiline-markdown-response.yaml new file mode 100644 index 00000000000..186cbd6268b --- /dev/null +++ b/src/vs/platform/agentHost/test/node/e2e/captures/claude-preserves-a-fenced-multiline-markdown-response.yaml @@ -0,0 +1,21 @@ +version: 1 +dialect: anthropic +exchanges: + - request: + model: claude-opus-5 + system: ${system} + messages: + - role: user + content: |- + Reply with exactly this Markdown code block and nothing else: + ```text + ALPHA + BETA + ``` + response: + content: |- + ```text + ALPHA + BETA + ``` + stopReason: end_turn diff --git a/src/vs/platform/agentHost/test/node/e2e/captures/codex-preserves-a-fenced-multiline-markdown-response.yaml b/src/vs/platform/agentHost/test/node/e2e/captures/codex-preserves-a-fenced-multiline-markdown-response.yaml new file mode 100644 index 00000000000..d7491ec679e --- /dev/null +++ b/src/vs/platform/agentHost/test/node/e2e/captures/codex-preserves-a-fenced-multiline-markdown-response.yaml @@ -0,0 +1,21 @@ +version: 1 +dialect: responses +exchanges: + - request: + model: gpt-5.3-codex + system: ${system} + messages: + - role: user + content: |- + Reply with exactly this Markdown code block and nothing else: + ```text + ALPHA + BETA + ``` + response: + content: |- + ```text + ALPHA + BETA + ``` + stopReason: end_turn diff --git a/src/vs/platform/agentHost/test/node/e2e/captures/copilotcli-preserves-a-fenced-multiline-markdown-response.yaml b/src/vs/platform/agentHost/test/node/e2e/captures/copilotcli-preserves-a-fenced-multiline-markdown-response.yaml new file mode 100644 index 00000000000..fd6399a3120 --- /dev/null +++ b/src/vs/platform/agentHost/test/node/e2e/captures/copilotcli-preserves-a-fenced-multiline-markdown-response.yaml @@ -0,0 +1,21 @@ +version: 1 +dialect: anthropic +exchanges: + - request: + model: claude-sonnet-5 + system: ${system} + messages: + - role: user + content: |- + Reply with exactly this Markdown code block and nothing else: + ```text + ALPHA + BETA + ``` + response: + content: |- + ```text + ALPHA + BETA + ``` + stopReason: end_turn diff --git a/src/vs/platform/agentHost/test/node/e2e/coverage/summary.json b/src/vs/platform/agentHost/test/node/e2e/coverage/summary.json index f9a7e055a5c..a60d0e8548c 100644 --- a/src/vs/platform/agentHost/test/node/e2e/coverage/summary.json +++ b/src/vs/platform/agentHost/test/node/e2e/coverage/summary.json @@ -15,27 +15,49 @@ }, "total": { "statements": { - "covered": 77668, - "total": 102175, - "percentage": 76.01 + "covered": 83077, + "total": 109466, + "percentage": 75.89 }, "branches": { - "covered": 8663, - "total": 12958, - "percentage": 66.85 + "covered": 9300, + "total": 13964, + "percentage": 66.59 }, "functions": { - "covered": 2777, - "total": 3896, - "percentage": 71.27 + "covered": 3027, + "total": 4252, + "percentage": 71.19 }, "lines": { - "covered": 77668, - "total": 102175, - "percentage": 76.01 + "covered": 83077, + "total": 109466, + "percentage": 75.89 } }, "files": { + "src/vs/platform/agentHost/common/agent.ts": { + "statements": { + "covered": 1112, + "total": 1120, + "percentage": 99.28 + }, + "branches": { + "covered": 26, + "total": 33, + "percentage": 78.78 + }, + "functions": { + "covered": 9, + "total": 10, + "percentage": 90 + }, + "lines": { + "covered": 1112, + "total": 1120, + "percentage": 99.28 + } + }, "src/vs/platform/agentHost/common/agentClientUri.ts": { "statements": { "covered": 88, @@ -82,9 +104,9 @@ }, "src/vs/platform/agentHost/common/agentHostByokLm.ts": { "statements": { - "covered": 211, - "total": 216, - "percentage": 97.68 + "covered": 214, + "total": 221, + "percentage": 96.83 }, "branches": { "covered": 0, @@ -93,19 +115,19 @@ }, "functions": { "covered": 0, - "total": 1, + "total": 2, "percentage": 0 }, "lines": { - "covered": 211, - "total": 216, - "percentage": 97.68 + "covered": 214, + "total": 221, + "percentage": 96.83 } }, "src/vs/platform/agentHost/common/agentHostChangesetOperationService.ts": { "statements": { - "covered": 130, - "total": 130, + "covered": 132, + "total": 132, "percentage": 100 }, "branches": { @@ -119,15 +141,15 @@ "percentage": 100 }, "lines": { - "covered": 130, - "total": 130, + "covered": 132, + "total": 132, "percentage": 100 } }, "src/vs/platform/agentHost/common/agentHostChangesetService.ts": { "statements": { - "covered": 293, - "total": 293, + "covered": 305, + "total": 305, "percentage": 100 }, "branches": { @@ -141,8 +163,8 @@ "percentage": 100 }, "lines": { - "covered": 293, - "total": 293, + "covered": 305, + "total": 305, "percentage": 100 } }, @@ -170,8 +192,8 @@ }, "src/vs/platform/agentHost/common/agentHostCheckpointService.ts": { "statements": { - "covered": 134, - "total": 134, + "covered": 153, + "total": 153, "percentage": 100 }, "branches": { @@ -181,12 +203,12 @@ }, "functions": { "covered": 1, - "total": 6, - "percentage": 16.66 + "total": 9, + "percentage": 11.11 }, "lines": { - "covered": 134, - "total": 134, + "covered": 153, + "total": 153, "percentage": 100 } }, @@ -219,9 +241,9 @@ "percentage": 94.44 }, "branches": { - "covered": 2, + "covered": 3, "total": 5, - "percentage": 40 + "percentage": 60 }, "functions": { "covered": 1, @@ -234,6 +256,28 @@ "percentage": 94.44 } }, + "src/vs/platform/agentHost/common/agentHostConfigurationSync.ts": { + "statements": { + "covered": 72, + "total": 143, + "percentage": 50.34 + }, + "branches": { + "covered": 0, + "total": 0, + "percentage": 100 + }, + "functions": { + "covered": 0, + "total": 8, + "percentage": 0 + }, + "lines": { + "covered": 72, + "total": 143, + "percentage": 50.34 + } + }, "src/vs/platform/agentHost/common/agentHostConversationContext.ts": { "statements": { "covered": 82, @@ -258,9 +302,9 @@ }, "src/vs/platform/agentHost/common/agentHostCustomizationConfig.ts": { "statements": { - "covered": 142, - "total": 156, - "percentage": 91.02 + "covered": 128, + "total": 142, + "percentage": 90.14 }, "branches": { "covered": 1, @@ -273,9 +317,9 @@ "percentage": 0 }, "lines": { - "covered": 142, - "total": 156, - "percentage": 91.02 + "covered": 128, + "total": 142, + "percentage": 90.14 } }, "src/vs/platform/agentHost/common/agentHostFileSystemProvider.ts": { @@ -285,9 +329,9 @@ "percentage": 54.39 }, "branches": { - "covered": 22, - "total": 34, - "percentage": 64.7 + "covered": 23, + "total": 35, + "percentage": 65.71 }, "functions": { "covered": 10, @@ -324,30 +368,30 @@ }, "src/vs/platform/agentHost/common/agentHostGitService.ts": { "statements": { - "covered": 426, - "total": 440, - "percentage": 96.81 + "covered": 445, + "total": 468, + "percentage": 95.08 }, "branches": { - "covered": 14, - "total": 18, - "percentage": 77.77 + "covered": 17, + "total": 21, + "percentage": 80.95 }, "functions": { "covered": 5, - "total": 6, - "percentage": 83.33 + "total": 7, + "percentage": 71.42 }, "lines": { - "covered": 426, - "total": 440, - "percentage": 96.81 + "covered": 445, + "total": 468, + "percentage": 95.08 } }, "src/vs/platform/agentHost/common/agentHostGitStateService.ts": { "statements": { - "covered": 58, - "total": 58, + "covered": 63, + "total": 63, "percentage": 100 }, "branches": { @@ -361,11 +405,33 @@ "percentage": 100 }, "lines": { - "covered": 58, - "total": 58, + "covered": 63, + "total": 63, "percentage": 100 } }, + "src/vs/platform/agentHost/common/agentHostManagedSettings.ts": { + "statements": { + "covered": 44, + "total": 80, + "percentage": 55 + }, + "branches": { + "covered": 2, + "total": 2, + "percentage": 100 + }, + "functions": { + "covered": 1, + "total": 5, + "percentage": 20 + }, + "lines": { + "covered": 44, + "total": 80, + "percentage": 55 + } + }, "src/vs/platform/agentHost/common/agentHostReviewService.ts": { "statements": { "covered": 89, @@ -390,9 +456,9 @@ }, "src/vs/platform/agentHost/common/agentHostSchema.ts": { "statements": { - "covered": 676, - "total": 772, - "percentage": 87.56 + "covered": 679, + "total": 775, + "percentage": 87.61 }, "branches": { "covered": 48, @@ -405,9 +471,9 @@ "percentage": 68.18 }, "lines": { - "covered": 676, - "total": 772, - "percentage": 87.56 + "covered": 679, + "total": 775, + "percentage": 87.61 } }, "src/vs/platform/agentHost/common/agentHostSlashCommand.ts": { @@ -500,23 +566,23 @@ }, "src/vs/platform/agentHost/common/agentHostWorkingDirectories.ts": { "statements": { - "covered": 20, - "total": 20, + "covered": 34, + "total": 34, "percentage": 100 }, "branches": { - "covered": 1, - "total": 2, - "percentage": 50 + "covered": 4, + "total": 5, + "percentage": 80 }, "functions": { - "covered": 1, - "total": 1, + "covered": 2, + "total": 2, "percentage": 100 }, "lines": { - "covered": 20, - "total": 20, + "covered": 34, + "total": 34, "percentage": 100 } }, @@ -566,24 +632,24 @@ }, "src/vs/platform/agentHost/common/agentModelSource.ts": { "statements": { - "covered": 22, - "total": 31, - "percentage": 70.96 + "covered": 41, + "total": 57, + "percentage": 71.92 }, "branches": { - "covered": 0, - "total": 0, + "covered": 1, + "total": 1, "percentage": 100 }, "functions": { - "covered": 0, - "total": 2, - "percentage": 0 + "covered": 1, + "total": 4, + "percentage": 25 }, "lines": { - "covered": 22, - "total": 31, - "percentage": 70.96 + "covered": 41, + "total": 57, + "percentage": 71.92 } }, "src/vs/platform/agentHost/common/agentPluginManager.ts": { @@ -610,24 +676,24 @@ }, "src/vs/platform/agentHost/common/agentService.ts": { "statements": { - "covered": 2227, - "total": 2402, - "percentage": 92.71 + "covered": 1010, + "total": 1175, + "percentage": 85.95 }, "branches": { - "covered": 24, - "total": 31, - "percentage": 77.41 + "covered": 9, + "total": 12, + "percentage": 75 }, "functions": { - "covered": 6, - "total": 15, - "percentage": 40 + "covered": 1, + "total": 8, + "percentage": 12.5 }, "lines": { - "covered": 2227, - "total": 2402, - "percentage": 92.71 + "covered": 1010, + "total": 1175, + "percentage": 85.95 } }, "src/vs/platform/agentHost/common/agentTelemetryCorrelation.ts": { @@ -659,9 +725,9 @@ "percentage": 80.07 }, "branches": { - "covered": 25, - "total": 35, - "percentage": 71.42 + "covered": 28, + "total": 38, + "percentage": 73.68 }, "functions": { "covered": 11, @@ -698,14 +764,14 @@ }, "src/vs/platform/agentHost/common/changesetUri.ts": { "statements": { - "covered": 318, + "covered": 320, "total": 370, - "percentage": 85.94 + "percentage": 86.48 }, "branches": { - "covered": 43, - "total": 57, - "percentage": 75.43 + "covered": 49, + "total": 61, + "percentage": 80.32 }, "functions": { "covered": 19, @@ -713,16 +779,16 @@ "percentage": 76 }, "lines": { - "covered": 318, + "covered": 320, "total": 370, - "percentage": 85.94 + "percentage": 86.48 } }, "src/vs/platform/agentHost/common/claudeModelConfig.ts": { "statements": { - "covered": 125, - "total": 128, - "percentage": 97.65 + "covered": 123, + "total": 126, + "percentage": 97.61 }, "branches": { "covered": 5, @@ -735,9 +801,31 @@ "percentage": 75 }, "lines": { - "covered": 125, - "total": 128, - "percentage": 97.65 + "covered": 123, + "total": 126, + "percentage": 97.61 + } + }, + "src/vs/platform/agentHost/common/claudeProviders.ts": { + "statements": { + "covered": 35, + "total": 35, + "percentage": 100 + }, + "branches": { + "covered": 0, + "total": 0, + "percentage": 100 + }, + "functions": { + "covered": 0, + "total": 0, + "percentage": 100 + }, + "lines": { + "covered": 35, + "total": 35, + "percentage": 100 } }, "src/vs/platform/agentHost/common/claudeSessionConfigKeys.ts": { @@ -813,9 +901,9 @@ "percentage": 88.09 }, "branches": { - "covered": 19, - "total": 28, - "percentage": 67.85 + "covered": 20, + "total": 29, + "percentage": 68.96 }, "functions": { "covered": 4, @@ -830,8 +918,8 @@ }, "src/vs/platform/agentHost/common/copilotCliConfig.ts": { "statements": { - "covered": 155, - "total": 155, + "covered": 159, + "total": 159, "percentage": 100 }, "branches": { @@ -845,8 +933,8 @@ "percentage": 100 }, "lines": { - "covered": 155, - "total": 155, + "covered": 159, + "total": 159, "percentage": 100 } }, @@ -918,9 +1006,9 @@ }, "src/vs/platform/agentHost/common/fileEditAttribution.ts": { "statements": { - "covered": 148, - "total": 245, - "percentage": 60.4 + "covered": 157, + "total": 271, + "percentage": 57.93 }, "branches": { "covered": 1, @@ -929,13 +1017,13 @@ }, "functions": { "covered": 1, - "total": 14, - "percentage": 7.14 + "total": 15, + "percentage": 6.66 }, "lines": { - "covered": 148, - "total": 245, - "percentage": 60.4 + "covered": 157, + "total": 271, + "percentage": 57.93 } }, "src/vs/platform/agentHost/common/githubEndpoints.ts": { @@ -982,6 +1070,28 @@ "percentage": 74.32 } }, + "src/vs/platform/agentHost/common/githubPullRequestReferences.ts": { + "statements": { + "covered": 38, + "total": 64, + "percentage": 59.37 + }, + "branches": { + "covered": 2, + "total": 5, + "percentage": 40 + }, + "functions": { + "covered": 2, + "total": 4, + "percentage": 50 + }, + "lines": { + "covered": 38, + "total": 64, + "percentage": 59.37 + } + }, "src/vs/platform/agentHost/common/meta/agentCompletionAttachmentMeta.ts": { "statements": { "covered": 146, @@ -1028,14 +1138,14 @@ }, "src/vs/platform/agentHost/common/meta/agentErrorMeta.ts": { "statements": { - "covered": 22, + "covered": 25, "total": 27, - "percentage": 81.48 + "percentage": 92.59 }, "branches": { - "covered": 1, - "total": 14, - "percentage": 7.14 + "covered": 11, + "total": 15, + "percentage": 73.33 }, "functions": { "covered": 1, @@ -1043,16 +1153,16 @@ "percentage": 100 }, "lines": { - "covered": 22, + "covered": 25, "total": 27, - "percentage": 81.48 + "percentage": 92.59 } }, "src/vs/platform/agentHost/common/meta/agentFeedbackAnnotations.ts": { "statements": { - "covered": 127, - "total": 135, - "percentage": 94.07 + "covered": 125, + "total": 133, + "percentage": 93.98 }, "branches": { "covered": 8, @@ -1065,9 +1175,9 @@ "percentage": 60 }, "lines": { - "covered": 127, - "total": 135, - "percentage": 94.07 + "covered": 125, + "total": 133, + "percentage": 93.98 } }, "src/vs/platform/agentHost/common/meta/agentFeedbackAttachments.ts": { @@ -1121,9 +1231,9 @@ "percentage": 84.81 }, "branches": { - "covered": 37, - "total": 46, - "percentage": 80.43 + "covered": 36, + "total": 45, + "percentage": 80 }, "functions": { "covered": 5, @@ -1231,9 +1341,9 @@ "percentage": 88.09 }, "branches": { - "covered": 18, - "total": 23, - "percentage": 78.26 + "covered": 19, + "total": 24, + "percentage": 79.16 }, "functions": { "covered": 11, @@ -1248,14 +1358,14 @@ }, "src/vs/platform/agentHost/common/reasoningEffort.ts": { "statements": { - "covered": 85, - "total": 89, - "percentage": 95.5 + "covered": 87, + "total": 91, + "percentage": 95.6 }, "branches": { "covered": 20, - "total": 27, - "percentage": 74.07 + "total": 29, + "percentage": 68.96 }, "functions": { "covered": 3, @@ -1263,9 +1373,9 @@ "percentage": 100 }, "lines": { - "covered": 85, - "total": 89, - "percentage": 95.5 + "covered": 87, + "total": 91, + "percentage": 95.6 } }, "src/vs/platform/agentHost/common/resourceReadLogging.ts": { @@ -1358,8 +1468,8 @@ }, "src/vs/platform/agentHost/common/sessionDataService.ts": { "statements": { - "covered": 464, - "total": 464, + "covered": 466, + "total": 466, "percentage": 100 }, "branches": { @@ -1373,8 +1483,8 @@ "percentage": 100 }, "lines": { - "covered": 464, - "total": 464, + "covered": 466, + "total": 466, "percentage": 100 } }, @@ -1512,14 +1622,14 @@ }, "src/vs/platform/agentHost/common/state/protocol/channels-changeset/reducer.ts": { "statements": { - "covered": 90, + "covered": 92, "total": 121, - "percentage": 74.38 + "percentage": 76.03 }, "branches": { - "covered": 13, - "total": 24, - "percentage": 54.16 + "covered": 16, + "total": 26, + "percentage": 61.53 }, "functions": { "covered": 1, @@ -1527,9 +1637,9 @@ "percentage": 100 }, "lines": { - "covered": 90, + "covered": 92, "total": 121, - "percentage": 74.38 + "percentage": 76.03 } }, "src/vs/platform/agentHost/common/state/protocol/channels-chat/reducer.ts": { @@ -1539,9 +1649,9 @@ "percentage": 79.21 }, "branches": { - "covered": 160, - "total": 227, - "percentage": 70.48 + "covered": 164, + "total": 230, + "percentage": 71.3 }, "functions": { "covered": 15, @@ -2018,24 +2128,24 @@ }, "src/vs/platform/agentHost/common/state/sessionState.ts": { "statements": { - "covered": 1316, - "total": 1680, - "percentage": 78.33 + "covered": 1370, + "total": 1829, + "percentage": 74.9 }, "branches": { - "covered": 145, - "total": 212, - "percentage": 68.39 + "covered": 147, + "total": 215, + "percentage": 68.37 }, "functions": { - "covered": 54, - "total": 74, - "percentage": 72.97 + "covered": 55, + "total": 83, + "percentage": 66.26 }, "lines": { - "covered": 1316, - "total": 1680, - "percentage": 78.33 + "covered": 1370, + "total": 1829, + "percentage": 74.9 } }, "src/vs/platform/agentHost/common/state/sessionWorkingDirectories.ts": { @@ -2106,36 +2216,80 @@ }, "src/vs/platform/agentHost/node/activeClientState.ts": { "statements": { - "covered": 164, + "covered": 160, "total": 195, - "percentage": 84.1 + "percentage": 82.05 + }, + "branches": { + "covered": 13, + "total": 20, + "percentage": 65 + }, + "functions": { + "covered": 7, + "total": 16, + "percentage": 43.75 + }, + "lines": { + "covered": 160, + "total": 195, + "percentage": 82.05 + } + }, + "src/vs/platform/agentHost/node/agentChatBackings.ts": { + "statements": { + "covered": 7, + "total": 7, + "percentage": 100 + }, + "branches": { + "covered": 0, + "total": 0, + "percentage": 100 + }, + "functions": { + "covered": 0, + "total": 0, + "percentage": 100 + }, + "lines": { + "covered": 7, + "total": 7, + "percentage": 100 + } + }, + "src/vs/platform/agentHost/node/agentChatContext.ts": { + "statements": { + "covered": 73, + "total": 77, + "percentage": 94.8 }, "branches": { "covered": 15, - "total": 23, - "percentage": 65.21 + "total": 18, + "percentage": 83.33 }, "functions": { - "covered": 8, - "total": 16, - "percentage": 50 + "covered": 4, + "total": 4, + "percentage": 100 }, "lines": { - "covered": 164, - "total": 195, - "percentage": 84.1 + "covered": 73, + "total": 77, + "percentage": 94.8 } }, "src/vs/platform/agentHost/node/agentConfigurationService.ts": { "statements": { - "covered": 387, - "total": 417, - "percentage": 92.8 + "covered": 389, + "total": 422, + "percentage": 92.18 }, "branches": { - "covered": 40, - "total": 54, - "percentage": 74.07 + "covered": 42, + "total": 57, + "percentage": 73.68 }, "functions": { "covered": 16, @@ -2143,21 +2297,21 @@ "percentage": 94.11 }, "lines": { - "covered": 387, - "total": 417, - "percentage": 92.8 + "covered": 389, + "total": 422, + "percentage": 92.18 } }, "src/vs/platform/agentHost/node/agentHostAuthenticationService.ts": { "statements": { - "covered": 100, - "total": 148, - "percentage": 67.56 + "covered": 102, + "total": 153, + "percentage": 66.66 }, "branches": { "covered": 18, - "total": 29, - "percentage": 62.06 + "total": 30, + "percentage": 60 }, "functions": { "covered": 6, @@ -2165,9 +2319,9 @@ "percentage": 85.71 }, "lines": { - "covered": 100, - "total": 148, - "percentage": 67.56 + "covered": 102, + "total": 153, + "percentage": 66.66 } }, "src/vs/platform/agentHost/node/agentHostBangCommand.ts": { @@ -2216,9 +2370,9 @@ }, "src/vs/platform/agentHost/node/agentHostChangesetCoordinator.ts": { "statements": { - "covered": 318, - "total": 333, - "percentage": 95.49 + "covered": 343, + "total": 367, + "percentage": 93.46 }, "branches": { "covered": 52, @@ -2227,79 +2381,79 @@ }, "functions": { "covered": 15, - "total": 15, - "percentage": 100 + "total": 16, + "percentage": 93.75 }, "lines": { - "covered": 318, - "total": 333, - "percentage": 95.49 + "covered": 343, + "total": 367, + "percentage": 93.46 } }, "src/vs/platform/agentHost/node/agentHostChangesetFileMonitorCoordinator.ts": { "statements": { - "covered": 326, - "total": 368, - "percentage": 88.58 + "covered": 381, + "total": 441, + "percentage": 86.39 }, "branches": { - "covered": 69, - "total": 84, - "percentage": 82.14 + "covered": 67, + "total": 89, + "percentage": 75.28 }, "functions": { - "covered": 27, - "total": 27, - "percentage": 100 + "covered": 29, + "total": 30, + "percentage": 96.66 }, "lines": { - "covered": 326, - "total": 368, - "percentage": 88.58 + "covered": 381, + "total": 441, + "percentage": 86.39 } }, "src/vs/platform/agentHost/node/agentHostChangesetOperationService.ts": { "statements": { - "covered": 200, - "total": 234, - "percentage": 85.47 + "covered": 252, + "total": 296, + "percentage": 85.13 }, "branches": { - "covered": 42, - "total": 54, - "percentage": 77.77 + "covered": 51, + "total": 66, + "percentage": 77.27 }, "functions": { - "covered": 9, - "total": 12, - "percentage": 75 + "covered": 12, + "total": 13, + "percentage": 92.3 }, "lines": { - "covered": 200, - "total": 234, - "percentage": 85.47 + "covered": 252, + "total": 296, + "percentage": 85.13 } }, "src/vs/platform/agentHost/node/agentHostChangesetService.ts": { "statements": { - "covered": 900, - "total": 1122, - "percentage": 80.21 + "covered": 1226, + "total": 1645, + "percentage": 74.52 }, "branches": { - "covered": 173, - "total": 226, - "percentage": 76.54 + "covered": 184, + "total": 258, + "percentage": 71.31 }, "functions": { - "covered": 46, - "total": 52, - "percentage": 88.46 + "covered": 56, + "total": 70, + "percentage": 80 }, "lines": { - "covered": 900, - "total": 1122, - "percentage": 80.21 + "covered": 1226, + "total": 1645, + "percentage": 74.52 } }, "src/vs/platform/agentHost/node/agentHostChangesetStateCache.ts": { @@ -2346,6 +2500,28 @@ "percentage": 95.45 } }, + "src/vs/platform/agentHost/node/agentHostChangesetTelemetry.ts": { + "statements": { + "covered": 148, + "total": 162, + "percentage": 91.35 + }, + "branches": { + "covered": 10, + "total": 10, + "percentage": 100 + }, + "functions": { + "covered": 2, + "total": 3, + "percentage": 66.66 + }, + "lines": { + "covered": 148, + "total": 162, + "percentage": 91.35 + } + }, "src/vs/platform/agentHost/node/agentHostChatCompletionProvider.ts": { "statements": { "covered": 133, @@ -2370,24 +2546,24 @@ }, "src/vs/platform/agentHost/node/agentHostCheckpointService.ts": { "statements": { - "covered": 263, - "total": 352, - "percentage": 74.71 + "covered": 360, + "total": 508, + "percentage": 70.86 }, "branches": { - "covered": 61, - "total": 81, - "percentage": 75.3 + "covered": 80, + "total": 110, + "percentage": 72.72 }, "functions": { - "covered": 12, - "total": 14, - "percentage": 85.71 + "covered": 17, + "total": 21, + "percentage": 80.95 }, "lines": { - "covered": 263, - "total": 352, - "percentage": 74.71 + "covered": 360, + "total": 508, + "percentage": 70.86 } }, "src/vs/platform/agentHost/node/agentHostClientConnectionTelemetry.ts": { @@ -2414,46 +2590,46 @@ }, "src/vs/platform/agentHost/node/agentHostCommitOperationHandler.ts": { "statements": { - "covered": 52, + "covered": 163, "total": 216, - "percentage": 24.07 + "percentage": 75.46 }, "branches": { - "covered": 1, - "total": 1, - "percentage": 100 + "covered": 18, + "total": 39, + "percentage": 46.15 }, "functions": { - "covered": 1, + "covered": 8, "total": 9, - "percentage": 11.11 + "percentage": 88.88 }, "lines": { - "covered": 52, + "covered": 163, "total": 216, - "percentage": 24.07 + "percentage": 75.46 } }, "src/vs/platform/agentHost/node/agentHostCommitOperationProvider.ts": { "statements": { - "covered": 55, + "covered": 58, "total": 58, - "percentage": 94.82 + "percentage": 100 }, "branches": { - "covered": 10, - "total": 11, - "percentage": 90.9 + "covered": 13, + "total": 14, + "percentage": 92.85 }, "functions": { - "covered": 4, + "covered": 6, "total": 6, - "percentage": 66.66 + "percentage": 100 }, "lines": { - "covered": 55, + "covered": 58, "total": 58, - "percentage": 94.82 + "percentage": 100 } }, "src/vs/platform/agentHost/node/agentHostCompletions.ts": { @@ -2478,6 +2654,28 @@ "percentage": 96.99 } }, + "src/vs/platform/agentHost/node/agentHostDatabase.ts": { + "statements": { + "covered": 267, + "total": 304, + "percentage": 87.82 + }, + "branches": { + "covered": 42, + "total": 56, + "percentage": 75 + }, + "functions": { + "covered": 23, + "total": 28, + "percentage": 82.14 + }, + "lines": { + "covered": 267, + "total": 304, + "percentage": 87.82 + } + }, "src/vs/platform/agentHost/node/agentHostDiscardChangesOperationHandler.ts": { "statements": { "covered": 68, @@ -2568,14 +2766,14 @@ }, "src/vs/platform/agentHost/node/agentHostFileMonitorService.ts": { "statements": { - "covered": 167, + "covered": 165, "total": 185, - "percentage": 90.27 + "percentage": 89.18 }, "branches": { - "covered": 25, - "total": 35, - "percentage": 71.42 + "covered": 22, + "total": 34, + "percentage": 64.7 }, "functions": { "covered": 14, @@ -2583,31 +2781,31 @@ "percentage": 100 }, "lines": { - "covered": 167, + "covered": 165, "total": 185, - "percentage": 90.27 + "percentage": 89.18 } }, "src/vs/platform/agentHost/node/agentHostGitHubEndpointService.ts": { "statements": { - "covered": 119, + "covered": 121, "total": 127, - "percentage": 93.7 + "percentage": 95.27 }, "branches": { + "covered": 8, + "total": 9, + "percentage": 88.88 + }, + "functions": { "covered": 7, "total": 8, "percentage": 87.5 }, - "functions": { - "covered": 6, - "total": 8, - "percentage": 75 - }, "lines": { - "covered": 119, + "covered": 121, "total": 127, - "percentage": 93.7 + "percentage": 95.27 } }, "src/vs/platform/agentHost/node/agentHostGitHubTelemetryRouter.ts": { @@ -2634,46 +2832,46 @@ }, "src/vs/platform/agentHost/node/agentHostGitService.ts": { "statements": { - "covered": 1057, - "total": 1443, - "percentage": 73.25 + "covered": 1117, + "total": 1692, + "percentage": 66.01 }, "branches": { - "covered": 216, - "total": 303, - "percentage": 71.28 + "covered": 226, + "total": 323, + "percentage": 69.96 }, "functions": { - "covered": 49, - "total": 70, - "percentage": 70 + "covered": 55, + "total": 79, + "percentage": 69.62 }, "lines": { - "covered": 1057, - "total": 1443, - "percentage": 73.25 + "covered": 1117, + "total": 1692, + "percentage": 66.01 } }, "src/vs/platform/agentHost/node/agentHostGitStateService.ts": { "statements": { - "covered": 176, - "total": 285, - "percentage": 61.75 + "covered": 233, + "total": 424, + "percentage": 54.95 }, "branches": { - "covered": 32, - "total": 54, - "percentage": 59.25 + "covered": 68, + "total": 92, + "percentage": 73.91 }, "functions": { - "covered": 8, - "total": 9, - "percentage": 88.88 + "covered": 9, + "total": 14, + "percentage": 64.28 }, "lines": { - "covered": 176, - "total": 285, - "percentage": 61.75 + "covered": 233, + "total": 424, + "percentage": 54.95 } }, "src/vs/platform/agentHost/node/agentHostHeadlessTerminal.ts": { @@ -2742,6 +2940,72 @@ "percentage": 80.74 } }, + "src/vs/platform/agentHost/node/agentHostManagedSettingsService.ts": { + "statements": { + "covered": 42, + "total": 76, + "percentage": 55.26 + }, + "branches": { + "covered": 3, + "total": 4, + "percentage": 75 + }, + "functions": { + "covered": 3, + "total": 5, + "percentage": 60 + }, + "lines": { + "covered": 42, + "total": 76, + "percentage": 55.26 + } + }, + "src/vs/platform/agentHost/node/agentHostMergeOperationHandler.ts": { + "statements": { + "covered": 36, + "total": 151, + "percentage": 23.84 + }, + "branches": { + "covered": 1, + "total": 1, + "percentage": 100 + }, + "functions": { + "covered": 1, + "total": 4, + "percentage": 25 + }, + "lines": { + "covered": 36, + "total": 151, + "percentage": 23.84 + } + }, + "src/vs/platform/agentHost/node/agentHostMergeOperationProvider.ts": { + "statements": { + "covered": 81, + "total": 100, + "percentage": 81 + }, + "branches": { + "covered": 25, + "total": 33, + "percentage": 75.75 + }, + "functions": { + "covered": 5, + "total": 6, + "percentage": 83.33 + }, + "lines": { + "covered": 81, + "total": 100, + "percentage": 81 + } + }, "src/vs/platform/agentHost/node/agentHostMicrosoftTelemetry.ts": { "statements": { "covered": 47, @@ -2764,6 +3028,50 @@ "percentage": 51.08 } }, + "src/vs/platform/agentHost/node/agentHostMultiRootDiff.ts": { + "statements": { + "covered": 101, + "total": 128, + "percentage": 78.9 + }, + "branches": { + "covered": 2, + "total": 4, + "percentage": 50 + }, + "functions": { + "covered": 1, + "total": 3, + "percentage": 33.33 + }, + "lines": { + "covered": 101, + "total": 128, + "percentage": 78.9 + } + }, + "src/vs/platform/agentHost/node/agentHostPromptCache.ts": { + "statements": { + "covered": 58, + "total": 60, + "percentage": 96.66 + }, + "branches": { + "covered": 10, + "total": 15, + "percentage": 66.66 + }, + "functions": { + "covered": 3, + "total": 3, + "percentage": 100 + }, + "lines": { + "covered": 58, + "total": 60, + "percentage": 96.66 + } + }, "src/vs/platform/agentHost/node/agentHostProxyResolver.ts": { "statements": { "covered": 123, @@ -2771,14 +3079,14 @@ "percentage": 73.65 }, "branches": { - "covered": 18, - "total": 24, + "covered": 15, + "total": 20, "percentage": 75 }, "functions": { - "covered": 16, + "covered": 13, "total": 28, - "percentage": 57.14 + "percentage": 46.42 }, "lines": { "covered": 123, @@ -2789,8 +3097,8 @@ "src/vs/platform/agentHost/node/agentHostPullRequestOperationHandler.ts": { "statements": { "covered": 127, - "total": 505, - "percentage": 25.14 + "total": 497, + "percentage": 25.55 }, "branches": { "covered": 1, @@ -2799,20 +3107,20 @@ }, "functions": { "covered": 1, - "total": 16, - "percentage": 6.25 + "total": 15, + "percentage": 6.66 }, "lines": { "covered": 127, - "total": 505, - "percentage": 25.14 + "total": 497, + "percentage": 25.55 } }, "src/vs/platform/agentHost/node/agentHostPullRequestOperationProvider.ts": { "statements": { - "covered": 65, - "total": 116, - "percentage": 56.03 + "covered": 66, + "total": 117, + "percentage": 56.41 }, "branches": { "covered": 14, @@ -2821,13 +3129,13 @@ }, "functions": { "covered": 4, - "total": 7, - "percentage": 57.14 + "total": 8, + "percentage": 50 }, "lines": { - "covered": 65, - "total": 116, - "percentage": 56.03 + "covered": 66, + "total": 117, + "percentage": 56.41 } }, "src/vs/platform/agentHost/node/agentHostRenameCommand.ts": { @@ -2898,14 +3206,14 @@ }, "src/vs/platform/agentHost/node/agentHostRestrictedTelemetry.ts": { "statements": { - "covered": 168, - "total": 299, - "percentage": 56.18 + "covered": 170, + "total": 308, + "percentage": 55.19 }, "branches": { "covered": 2, - "total": 5, - "percentage": 40 + "total": 7, + "percentage": 28.57 }, "functions": { "covered": 1, @@ -2913,38 +3221,38 @@ "percentage": 7.14 }, "lines": { - "covered": 168, - "total": 299, - "percentage": 56.18 + "covered": 170, + "total": 308, + "percentage": 55.19 } }, "src/vs/platform/agentHost/node/agentHostReviewService.ts": { "statements": { - "covered": 138, + "covered": 209, "total": 264, - "percentage": 52.27 + "percentage": 79.16 }, "branches": { - "covered": 20, - "total": 26, - "percentage": 76.92 + "covered": 35, + "total": 52, + "percentage": 67.3 }, "functions": { - "covered": 7, + "covered": 9, "total": 13, - "percentage": 53.84 + "percentage": 69.23 }, "lines": { - "covered": 138, + "covered": 209, "total": 264, - "percentage": 52.27 + "percentage": 79.16 } }, "src/vs/platform/agentHost/node/agentHostServerMain.ts": { "statements": { - "covered": 446, - "total": 495, - "percentage": 90.1 + "covered": 453, + "total": 503, + "percentage": 90.05 }, "branches": { "covered": 23, @@ -2957,21 +3265,43 @@ "percentage": 85.71 }, "lines": { - "covered": 446, - "total": 495, - "percentage": 90.1 + "covered": 453, + "total": 503, + "percentage": 90.05 + } + }, + "src/vs/platform/agentHost/node/agentHostSessionRepositories.ts": { + "statements": { + "covered": 87, + "total": 95, + "percentage": 91.57 + }, + "branches": { + "covered": 10, + "total": 12, + "percentage": 83.33 + }, + "functions": { + "covered": 1, + "total": 1, + "percentage": 100 + }, + "lines": { + "covered": 87, + "total": 95, + "percentage": 91.57 } }, "src/vs/platform/agentHost/node/agentHostSessionTitleController.ts": { "statements": { - "covered": 512, - "total": 663, - "percentage": 77.22 + "covered": 549, + "total": 694, + "percentage": 79.1 }, "branches": { - "covered": 102, - "total": 128, - "percentage": 79.68 + "covered": 100, + "total": 129, + "percentage": 77.51 }, "functions": { "covered": 25, @@ -2979,9 +3309,31 @@ "percentage": 73.52 }, "lines": { - "covered": 512, - "total": 663, - "percentage": 77.22 + "covered": 549, + "total": 694, + "percentage": 79.1 + } + }, + "src/vs/platform/agentHost/node/agentHostSessionTitleSignal.ts": { + "statements": { + "covered": 58, + "total": 60, + "percentage": 96.66 + }, + "branches": { + "covered": 2, + "total": 3, + "percentage": 66.66 + }, + "functions": { + "covered": 1, + "total": 1, + "percentage": 100 + }, + "lines": { + "covered": 58, + "total": 60, + "percentage": 96.66 } }, "src/vs/platform/agentHost/node/agentHostShellUtils.ts": { @@ -3008,9 +3360,9 @@ }, "src/vs/platform/agentHost/node/agentHostSkillCompletionProvider.ts": { "statements": { - "covered": 59, - "total": 122, - "percentage": 48.36 + "covered": 67, + "total": 129, + "percentage": 51.93 }, "branches": { "covered": 5, @@ -3019,13 +3371,13 @@ }, "functions": { "covered": 2, - "total": 5, - "percentage": 40 + "total": 6, + "percentage": 33.33 }, "lines": { - "covered": 59, - "total": 122, - "percentage": 48.36 + "covered": 67, + "total": 129, + "percentage": 51.93 } }, "src/vs/platform/agentHost/node/agentHostSlashCompletion.ts": { @@ -3052,24 +3404,24 @@ }, "src/vs/platform/agentHost/node/agentHostStateManager.ts": { "statements": { - "covered": 1555, - "total": 1698, - "percentage": 91.57 + "covered": 1638, + "total": 1762, + "percentage": 92.96 }, "branches": { - "covered": 254, - "total": 299, - "percentage": 84.94 + "covered": 264, + "total": 313, + "percentage": 84.34 }, "functions": { - "covered": 65, - "total": 72, - "percentage": 90.27 + "covered": 72, + "total": 77, + "percentage": 93.5 }, "lines": { - "covered": 1555, - "total": 1698, - "percentage": 91.57 + "covered": 1638, + "total": 1762, + "percentage": 92.96 } }, "src/vs/platform/agentHost/node/agentHostSyncOperationHandler.ts": { @@ -3118,24 +3470,24 @@ }, "src/vs/platform/agentHost/node/agentHostTelemetryReporter.ts": { "statements": { - "covered": 872, - "total": 979, - "percentage": 89.07 + "covered": 1068, + "total": 1218, + "percentage": 87.68 }, "branches": { - "covered": 46, - "total": 69, - "percentage": 66.66 + "covered": 51, + "total": 73, + "percentage": 69.86 }, "functions": { "covered": 15, - "total": 19, - "percentage": 78.94 + "total": 22, + "percentage": 68.18 }, "lines": { - "covered": 872, - "total": 979, - "percentage": 89.07 + "covered": 1068, + "total": 1218, + "percentage": 87.68 } }, "src/vs/platform/agentHost/node/agentHostTelemetryService.ts": { @@ -3162,14 +3514,14 @@ }, "src/vs/platform/agentHost/node/agentHostTerminalManager.ts": { "statements": { - "covered": 877, + "covered": 882, "total": 971, - "percentage": 90.31 + "percentage": 90.83 }, "branches": { - "covered": 116, - "total": 145, - "percentage": 80 + "covered": 120, + "total": 149, + "percentage": 80.53 }, "functions": { "covered": 35, @@ -3177,21 +3529,21 @@ "percentage": 85.36 }, "lines": { - "covered": 877, + "covered": 882, "total": 971, - "percentage": 90.31 + "percentage": 90.83 } }, "src/vs/platform/agentHost/node/agentHostToolCallTracker.ts": { "statements": { - "covered": 253, - "total": 293, - "percentage": 86.34 + "covered": 259, + "total": 299, + "percentage": 86.62 }, "branches": { - "covered": 55, - "total": 62, - "percentage": 88.7 + "covered": 54, + "total": 61, + "percentage": 88.52 }, "functions": { "covered": 15, @@ -3199,31 +3551,31 @@ "percentage": 100 }, "lines": { - "covered": 253, - "total": 293, - "percentage": 86.34 + "covered": 259, + "total": 299, + "percentage": 86.62 } }, "src/vs/platform/agentHost/node/agentHostTurnTracker.ts": { "statements": { - "covered": 115, - "total": 115, - "percentage": 100 + "covered": 385, + "total": 484, + "percentage": 79.54 }, "branches": { - "covered": 16, - "total": 17, - "percentage": 94.11 + "covered": 42, + "total": 52, + "percentage": 80.76 }, "functions": { - "covered": 7, - "total": 7, - "percentage": 100 + "covered": 18, + "total": 22, + "percentage": 81.81 }, "lines": { - "covered": 115, - "total": 115, - "percentage": 100 + "covered": 385, + "total": 484, + "percentage": 79.54 } }, "src/vs/platform/agentHost/node/agentHostUpgradeChannel.ts": { @@ -3294,24 +3646,24 @@ }, "src/vs/platform/agentHost/node/agentPeerChats.ts": { "statements": { - "covered": 223, - "total": 354, - "percentage": 62.99 + "covered": 186, + "total": 359, + "percentage": 51.81 }, "branches": { - "covered": 35, - "total": 64, - "percentage": 54.68 + "covered": 14, + "total": 46, + "percentage": 30.43 }, "functions": { - "covered": 18, + "covered": 6, "total": 24, - "percentage": 75 + "percentage": 25 }, "lines": { - "covered": 223, - "total": 354, - "percentage": 62.99 + "covered": 186, + "total": 359, + "percentage": 51.81 } }, "src/vs/platform/agentHost/node/agentPluginManager.ts": { @@ -3321,9 +3673,9 @@ "percentage": 85.61 }, "branches": { - "covered": 31, - "total": 44, - "percentage": 70.45 + "covered": 32, + "total": 45, + "percentage": 71.11 }, "functions": { "covered": 16, @@ -3338,9 +3690,9 @@ }, "src/vs/platform/agentHost/node/agentSdkDownloader.ts": { "statements": { - "covered": 292, - "total": 626, - "percentage": 46.64 + "covered": 305, + "total": 650, + "percentage": 46.92 }, "branches": { "covered": 7, @@ -3349,57 +3701,79 @@ }, "functions": { "covered": 4, - "total": 14, - "percentage": 28.57 + "total": 15, + "percentage": 26.66 }, "lines": { - "covered": 292, - "total": 626, - "percentage": 46.64 + "covered": 305, + "total": 650, + "percentage": 46.92 } }, "src/vs/platform/agentHost/node/agentService.ts": { "statements": { - "covered": 3530, - "total": 4447, - "percentage": 79.37 + "covered": 4285, + "total": 5457, + "percentage": 78.52 }, "branches": { - "covered": 639, - "total": 909, - "percentage": 70.29 + "covered": 729, + "total": 1087, + "percentage": 67.06 }, "functions": { - "covered": 143, - "total": 164, - "percentage": 87.19 + "covered": 174, + "total": 206, + "percentage": 84.46 }, "lines": { - "covered": 3530, - "total": 4447, - "percentage": 79.37 + "covered": 4285, + "total": 5457, + "percentage": 78.52 + } + }, + "src/vs/platform/agentHost/node/agentSessionRegistry.ts": { + "statements": { + "covered": 132, + "total": 138, + "percentage": 95.65 + }, + "branches": { + "covered": 10, + "total": 10, + "percentage": 100 + }, + "functions": { + "covered": 9, + "total": 12, + "percentage": 75 + }, + "lines": { + "covered": 132, + "total": 138, + "percentage": 95.65 } }, "src/vs/platform/agentHost/node/agentSideEffects.ts": { "statements": { - "covered": 1772, - "total": 2026, - "percentage": 87.46 + "covered": 1898, + "total": 2164, + "percentage": 87.7 }, "branches": { - "covered": 336, - "total": 423, - "percentage": 79.43 + "covered": 369, + "total": 468, + "percentage": 78.84 }, "functions": { - "covered": 57, - "total": 59, - "percentage": 96.61 + "covered": 62, + "total": 64, + "percentage": 96.87 }, "lines": { - "covered": 1772, - "total": 2026, - "percentage": 87.46 + "covered": 1898, + "total": 2164, + "percentage": 87.7 } }, "src/vs/platform/agentHost/node/appNodeModules.ts": { @@ -3448,8 +3822,8 @@ }, "src/vs/platform/agentHost/node/claude/anthropicBetas.ts": { "statements": { - "covered": 46, - "total": 46, + "covered": 40, + "total": 40, "percentage": 100 }, "branches": { @@ -3463,8 +3837,8 @@ "percentage": 100 }, "lines": { - "covered": 46, - "total": 46, + "covered": 40, + "total": 40, "percentage": 100 } }, @@ -3492,80 +3866,80 @@ }, "src/vs/platform/agentHost/node/claude/claudeAgent.ts": { "statements": { - "covered": 1904, - "total": 2474, - "percentage": 76.96 + "covered": 2076, + "total": 2558, + "percentage": 81.15 }, "branches": { - "covered": 183, - "total": 309, - "percentage": 59.22 + "covered": 200, + "total": 302, + "percentage": 66.22 }, "functions": { - "covered": 74, - "total": 96, - "percentage": 77.08 + "covered": 89, + "total": 113, + "percentage": 78.76 }, "lines": { - "covered": 1904, - "total": 2474, - "percentage": 76.96 + "covered": 2076, + "total": 2558, + "percentage": 81.15 } }, "src/vs/platform/agentHost/node/claude/claudeAgentSdkService.ts": { "statements": { - "covered": 270, + "covered": 267, "total": 312, - "percentage": 86.53 + "percentage": 85.57 }, "branches": { - "covered": 14, - "total": 19, - "percentage": 73.68 + "covered": 13, + "total": 18, + "percentage": 72.22 }, "functions": { - "covered": 12, + "covered": 11, "total": 15, - "percentage": 80 + "percentage": 73.33 }, "lines": { - "covered": 270, + "covered": 267, "total": 312, - "percentage": 86.53 + "percentage": 85.57 } }, "src/vs/platform/agentHost/node/claude/claudeAgentSession.ts": { "statements": { - "covered": 1023, - "total": 1219, - "percentage": 83.92 + "covered": 1094, + "total": 1348, + "percentage": 81.15 }, "branches": { - "covered": 63, - "total": 97, - "percentage": 64.94 + "covered": 62, + "total": 95, + "percentage": 65.26 }, "functions": { - "covered": 30, - "total": 53, - "percentage": 56.6 + "covered": 33, + "total": 56, + "percentage": 58.92 }, "lines": { - "covered": 1023, - "total": 1219, - "percentage": 83.92 + "covered": 1094, + "total": 1348, + "percentage": 81.15 } }, "src/vs/platform/agentHost/node/claude/claudeCanUseTool.ts": { "statements": { - "covered": 236, - "total": 278, - "percentage": 84.89 + "covered": 257, + "total": 301, + "percentage": 85.38 }, "branches": { - "covered": 19, - "total": 27, - "percentage": 70.37 + "covered": 22, + "total": 31, + "percentage": 70.96 }, "functions": { "covered": 5, @@ -3573,9 +3947,9 @@ "percentage": 71.42 }, "lines": { - "covered": 236, - "total": 278, - "percentage": 84.89 + "covered": 257, + "total": 301, + "percentage": 85.38 } }, "src/vs/platform/agentHost/node/claude/claudeElicitation.ts": { @@ -3712,14 +4086,14 @@ }, "src/vs/platform/agentHost/node/claude/claudeModelId.ts": { "statements": { - "covered": 173, - "total": 203, - "percentage": 85.22 + "covered": 166, + "total": 198, + "percentage": 83.83 }, "branches": { - "covered": 41, - "total": 51, - "percentage": 80.39 + "covered": 38, + "total": 49, + "percentage": 77.55 }, "functions": { "covered": 11, @@ -3727,9 +4101,31 @@ "percentage": 84.61 }, "lines": { - "covered": 173, - "total": 203, - "percentage": 85.22 + "covered": 166, + "total": 198, + "percentage": 83.83 + } + }, + "src/vs/platform/agentHost/node/claude/claudeModelSelection.ts": { + "statements": { + "covered": 160, + "total": 178, + "percentage": 89.88 + }, + "branches": { + "covered": 12, + "total": 14, + "percentage": 85.71 + }, + "functions": { + "covered": 6, + "total": 7, + "percentage": 85.71 + }, + "lines": { + "covered": 160, + "total": 178, + "percentage": 89.88 } }, "src/vs/platform/agentHost/node/claude/claudePromptQueue.ts": { @@ -3822,14 +4218,14 @@ }, "src/vs/platform/agentHost/node/claude/claudeReplayMapper.ts": { "statements": { - "covered": 520, + "covered": 504, "total": 652, - "percentage": 79.75 + "percentage": 77.3 }, "branches": { - "covered": 63, - "total": 120, - "percentage": 52.5 + "covered": 61, + "total": 116, + "percentage": 52.58 }, "functions": { "covered": 18, @@ -3837,16 +4233,16 @@ "percentage": 78.26 }, "lines": { - "covered": 520, + "covered": 504, "total": 652, - "percentage": 79.75 + "percentage": 77.3 } }, "src/vs/platform/agentHost/node/claude/claudeSdkMessageRouter.ts": { "statements": { - "covered": 85, - "total": 89, - "percentage": 95.5 + "covered": 89, + "total": 93, + "percentage": 95.69 }, "branches": { "covered": 10, @@ -3859,9 +4255,9 @@ "percentage": 66.66 }, "lines": { - "covered": 85, - "total": 89, - "percentage": 95.5 + "covered": 89, + "total": 93, + "percentage": 95.69 } }, "src/vs/platform/agentHost/node/claude/claudeSdkOptions.ts": { @@ -3871,9 +4267,9 @@ "percentage": 82.03 }, "branches": { - "covered": 14, - "total": 40, - "percentage": 35 + "covered": 13, + "total": 39, + "percentage": 33.33 }, "functions": { "covered": 4, @@ -3888,58 +4284,58 @@ }, "src/vs/platform/agentHost/node/claude/claudeSdkPipeline.ts": { "statements": { - "covered": 532, - "total": 710, - "percentage": 74.92 + "covered": 552, + "total": 733, + "percentage": 75.3 }, "branches": { - "covered": 39, + "covered": 40, "total": 63, - "percentage": 61.9 + "percentage": 63.49 }, "functions": { "covered": 20, - "total": 30, - "percentage": 66.66 + "total": 31, + "percentage": 64.51 }, "lines": { - "covered": 532, - "total": 710, - "percentage": 74.92 + "covered": 552, + "total": 733, + "percentage": 75.3 } }, "src/vs/platform/agentHost/node/claude/claudeServerToolMcpServer.ts": { "statements": { - "covered": 71, - "total": 71, + "covered": 77, + "total": 77, "percentage": 100 }, "branches": { - "covered": 7, - "total": 9, - "percentage": 77.77 + "covered": 10, + "total": 12, + "percentage": 83.33 }, "functions": { - "covered": 2, - "total": 2, + "covered": 3, + "total": 3, "percentage": 100 }, "lines": { - "covered": 71, - "total": 71, + "covered": 77, + "total": 77, "percentage": 100 } }, "src/vs/platform/agentHost/node/claude/claudeSessionMetadataStore.ts": { "statements": { - "covered": 202, - "total": 240, - "percentage": 84.16 + "covered": 201, + "total": 237, + "percentage": 84.81 }, "branches": { - "covered": 24, - "total": 37, - "percentage": 64.86 + "covered": 17, + "total": 35, + "percentage": 48.57 }, "functions": { "covered": 8, @@ -3947,9 +4343,9 @@ "percentage": 100 }, "lines": { - "covered": 202, - "total": 240, - "percentage": 84.16 + "covered": 201, + "total": 237, + "percentage": 84.81 } }, "src/vs/platform/agentHost/node/claude/claudeSessionPermissionMode.ts": { @@ -3981,9 +4377,9 @@ "percentage": 93.72 }, "branches": { - "covered": 41, - "total": 50, - "percentage": 82 + "covered": 42, + "total": 51, + "percentage": 82.35 }, "functions": { "covered": 17, @@ -3998,24 +4394,24 @@ }, "src/vs/platform/agentHost/node/claude/claudeSubagentResolver.ts": { "statements": { - "covered": 223, - "total": 355, - "percentage": 62.81 + "covered": 236, + "total": 439, + "percentage": 53.75 }, "branches": { - "covered": 12, + "covered": 13, "total": 20, - "percentage": 60 + "percentage": 65 }, "functions": { - "covered": 10, - "total": 17, - "percentage": 58.82 + "covered": 11, + "total": 21, + "percentage": 52.38 }, "lines": { - "covered": 223, - "total": 355, - "percentage": 62.81 + "covered": 236, + "total": 439, + "percentage": 53.75 } }, "src/vs/platform/agentHost/node/claude/claudeSubagentSignals.ts": { @@ -4086,14 +4482,14 @@ }, "src/vs/platform/agentHost/node/claude/claudeToolDisplay.ts": { "statements": { - "covered": 494, - "total": 651, - "percentage": 75.88 + "covered": 469, + "total": 590, + "percentage": 79.49 }, "branches": { - "covered": 81, - "total": 149, - "percentage": 54.36 + "covered": 73, + "total": 131, + "percentage": 55.72 }, "functions": { "covered": 15, @@ -4101,31 +4497,31 @@ "percentage": 88.23 }, "lines": { - "covered": 494, - "total": 651, - "percentage": 75.88 + "covered": 469, + "total": 590, + "percentage": 79.49 } }, "src/vs/platform/agentHost/node/claude/claudeTransportMode.ts": { "statements": { - "covered": 109, - "total": 140, - "percentage": 77.85 + "covered": 135, + "total": 150, + "percentage": 90 }, "branches": { - "covered": 1, - "total": 3, - "percentage": 33.33 + "covered": 9, + "total": 16, + "percentage": 56.25 }, "functions": { - "covered": 1, - "total": 4, - "percentage": 25 + "covered": 5, + "total": 5, + "percentage": 100 }, "lines": { - "covered": 109, - "total": 140, - "percentage": 77.85 + "covered": 135, + "total": 150, + "percentage": 90 } }, "src/vs/platform/agentHost/node/claude/clientTools/claudeClientToolMcpServer.ts": { @@ -4311,9 +4707,9 @@ "percentage": 76.95 }, "branches": { - "covered": 45, - "total": 70, - "percentage": 64.28 + "covered": 44, + "total": 69, + "percentage": 63.76 }, "functions": { "covered": 12, @@ -4460,24 +4856,24 @@ }, "src/vs/platform/agentHost/node/codex/codexAgent.ts": { "statements": { - "covered": 3166, - "total": 4838, - "percentage": 65.44 + "covered": 3879, + "total": 5890, + "percentage": 65.85 }, "branches": { - "covered": 350, - "total": 589, - "percentage": 59.42 + "covered": 364, + "total": 690, + "percentage": 52.75 }, "functions": { - "covered": 128, - "total": 179, - "percentage": 71.5 + "covered": 153, + "total": 210, + "percentage": 72.85 }, "lines": { - "covered": 3166, - "total": 4838, - "percentage": 65.44 + "covered": 3879, + "total": 5890, + "percentage": 65.85 } }, "src/vs/platform/agentHost/node/codex/codexAppServerClient.ts": { @@ -4504,9 +4900,9 @@ }, "src/vs/platform/agentHost/node/codex/codexClientCustomizations.ts": { "statements": { - "covered": 258, + "covered": 260, "total": 316, - "percentage": 81.64 + "percentage": 82.27 }, "branches": { "covered": 27, @@ -4514,14 +4910,14 @@ "percentage": 52.94 }, "functions": { - "covered": 15, + "covered": 16, "total": 19, - "percentage": 78.94 + "percentage": 84.21 }, "lines": { - "covered": 258, + "covered": 260, "total": 316, - "percentage": 81.64 + "percentage": 82.27 } }, "src/vs/platform/agentHost/node/codex/codexCustomizations.ts": { @@ -4531,9 +4927,9 @@ "percentage": 82.15 }, "branches": { - "covered": 15, - "total": 29, - "percentage": 51.72 + "covered": 17, + "total": 30, + "percentage": 56.66 }, "functions": { "covered": 7, @@ -4614,14 +5010,14 @@ }, "src/vs/platform/agentHost/node/codex/codexLaunchConfig.ts": { "statements": { - "covered": 84, - "total": 120, - "percentage": 70 + "covered": 96, + "total": 130, + "percentage": 73.84 }, "branches": { - "covered": 4, - "total": 16, - "percentage": 25 + "covered": 5, + "total": 18, + "percentage": 27.77 }, "functions": { "covered": 3, @@ -4629,31 +5025,53 @@ "percentage": 50 }, "lines": { - "covered": 84, - "total": 120, - "percentage": 70 + "covered": 96, + "total": 130, + "percentage": 73.84 + } + }, + "src/vs/platform/agentHost/node/codex/codexLocalAuth.ts": { + "statements": { + "covered": 25, + "total": 70, + "percentage": 35.71 + }, + "branches": { + "covered": 0, + "total": 0, + "percentage": 100 + }, + "functions": { + "covered": 0, + "total": 6, + "percentage": 0 + }, + "lines": { + "covered": 25, + "total": 70, + "percentage": 35.71 } }, "src/vs/platform/agentHost/node/codex/codexMapAppServerEvents.ts": { "statements": { - "covered": 622, - "total": 1179, - "percentage": 52.75 + "covered": 634, + "total": 1250, + "percentage": 50.72 }, "branches": { - "covered": 59, - "total": 112, - "percentage": 52.67 + "covered": 63, + "total": 118, + "percentage": 53.38 }, "functions": { "covered": 19, - "total": 38, - "percentage": 50 + "total": 42, + "percentage": 45.23 }, "lines": { - "covered": 622, - "total": 1179, - "percentage": 52.75 + "covered": 634, + "total": 1250, + "percentage": 50.72 } }, "src/vs/platform/agentHost/node/codex/codexMcpServers.ts": { @@ -4724,58 +5142,58 @@ }, "src/vs/platform/agentHost/node/codex/codexProxyService.ts": { "statements": { - "covered": 384, + "covered": 390, "total": 484, - "percentage": 79.33 + "percentage": 80.57 }, "branches": { - "covered": 32, - "total": 77, - "percentage": 41.55 + "covered": 33, + "total": 79, + "percentage": 41.77 }, "functions": { - "covered": 10, + "covered": 11, "total": 14, - "percentage": 71.42 + "percentage": 78.57 }, "lines": { - "covered": 384, + "covered": 390, "total": 484, - "percentage": 79.33 + "percentage": 80.57 } }, "src/vs/platform/agentHost/node/codex/codexReplayMapper.ts": { "statements": { - "covered": 142, - "total": 264, - "percentage": 53.78 + "covered": 149, + "total": 293, + "percentage": 50.85 }, "branches": { "covered": 6, - "total": 17, - "percentage": 35.29 + "total": 19, + "percentage": 31.57 }, "functions": { "covered": 4, - "total": 9, - "percentage": 44.44 + "total": 10, + "percentage": 40 }, "lines": { - "covered": 142, - "total": 264, - "percentage": 53.78 + "covered": 149, + "total": 293, + "percentage": 50.85 } }, "src/vs/platform/agentHost/node/codex/codexSessionConfigKeys.ts": { "statements": { - "covered": 172, - "total": 196, - "percentage": 87.75 + "covered": 174, + "total": 198, + "percentage": 87.87 }, "branches": { "covered": 23, - "total": 43, - "percentage": 53.48 + "total": 45, + "percentage": 51.11 }, "functions": { "covered": 11, @@ -4783,21 +5201,21 @@ "percentage": 100 }, "lines": { - "covered": 172, - "total": 196, - "percentage": 87.75 + "covered": 174, + "total": 198, + "percentage": 87.87 } }, "src/vs/platform/agentHost/node/codex/codexSessionMetadataStore.ts": { "statements": { - "covered": 156, - "total": 181, - "percentage": 86.18 + "covered": 207, + "total": 232, + "percentage": 89.22 }, "branches": { - "covered": 14, - "total": 30, - "percentage": 46.66 + "covered": 16, + "total": 36, + "percentage": 44.44 }, "functions": { "covered": 6, @@ -4805,21 +5223,21 @@ "percentage": 100 }, "lines": { - "covered": 156, - "total": 181, - "percentage": 86.18 + "covered": 207, + "total": 232, + "percentage": 89.22 } }, "src/vs/platform/agentHost/node/codex/codexShellCommand.ts": { "statements": { - "covered": 38, + "covered": 36, "total": 42, - "percentage": 90.47 + "percentage": 85.71 }, "branches": { - "covered": 7, - "total": 9, - "percentage": 77.77 + "covered": 2, + "total": 6, + "percentage": 33.33 }, "functions": { "covered": 2, @@ -4827,9 +5245,9 @@ "percentage": 100 }, "lines": { - "covered": 38, + "covered": 36, "total": 42, - "percentage": 90.47 + "percentage": 85.71 } }, "src/vs/platform/agentHost/node/codex/codexThreadList.ts": { @@ -5010,68 +5428,68 @@ }, "src/vs/platform/agentHost/node/copilot/copilotAgent.ts": { "statements": { - "covered": 4032, - "total": 5228, - "percentage": 77.12 + "covered": 4060, + "total": 5376, + "percentage": 75.52 }, "branches": { - "covered": 569, - "total": 905, - "percentage": 62.87 + "covered": 648, + "total": 1003, + "percentage": 64.6 }, "functions": { - "covered": 203, - "total": 244, - "percentage": 83.19 + "covered": 227, + "total": 277, + "percentage": 81.94 }, "lines": { - "covered": 4032, - "total": 5228, - "percentage": 77.12 + "covered": 4060, + "total": 5376, + "percentage": 75.52 } }, "src/vs/platform/agentHost/node/copilot/copilotAgentSession.ts": { "statements": { - "covered": 4101, - "total": 5517, - "percentage": 74.33 + "covered": 4116, + "total": 5500, + "percentage": 74.83 }, "branches": { - "covered": 712, - "total": 1054, - "percentage": 67.55 + "covered": 736, + "total": 1064, + "percentage": 69.17 }, "functions": { - "covered": 163, - "total": 200, - "percentage": 81.5 + "covered": 167, + "total": 206, + "percentage": 81.06 }, "lines": { - "covered": 4101, - "total": 5517, - "percentage": 74.33 + "covered": 4116, + "total": 5500, + "percentage": 74.83 } }, "src/vs/platform/agentHost/node/copilot/copilotAttachmentUtils.ts": { "statements": { - "covered": 18, - "total": 28, - "percentage": 64.28 + "covered": 22, + "total": 32, + "percentage": 68.75 }, "branches": { - "covered": 3, - "total": 3, + "covered": 4, + "total": 4, "percentage": 100 }, "functions": { - "covered": 1, - "total": 2, - "percentage": 50 + "covered": 2, + "total": 3, + "percentage": 66.66 }, "lines": { - "covered": 18, - "total": 28, - "percentage": 64.28 + "covered": 22, + "total": 32, + "percentage": 68.75 } }, "src/vs/platform/agentHost/node/copilot/copilotCliEnvironment.ts": { @@ -5098,35 +5516,35 @@ }, "src/vs/platform/agentHost/node/copilot/copilotFailureTelemetry.ts": { "statements": { - "covered": 218, - "total": 299, - "percentage": 72.9 + "covered": 292, + "total": 402, + "percentage": 72.63 }, "branches": { - "covered": 3, - "total": 9, - "percentage": 33.33 + "covered": 6, + "total": 23, + "percentage": 26.08 }, "functions": { - "covered": 2, - "total": 7, - "percentage": 28.57 + "covered": 5, + "total": 11, + "percentage": 45.45 }, "lines": { - "covered": 218, - "total": 299, - "percentage": 72.9 + "covered": 292, + "total": 402, + "percentage": 72.63 } }, "src/vs/platform/agentHost/node/copilot/copilotGitHubTelemetryForwarder.ts": { "statements": { - "covered": 152, - "total": 154, - "percentage": 98.7 + "covered": 218, + "total": 224, + "percentage": 97.32 }, "branches": { - "covered": 3, - "total": 6, + "covered": 5, + "total": 10, "percentage": 50 }, "functions": { @@ -5135,9 +5553,9 @@ "percentage": 100 }, "lines": { - "covered": 152, - "total": 154, - "percentage": 98.7 + "covered": 218, + "total": 224, + "percentage": 97.32 } }, "src/vs/platform/agentHost/node/copilot/copilotGitProject.ts": { @@ -5164,24 +5582,24 @@ }, "src/vs/platform/agentHost/node/copilot/copilotNonPtyShellTerminals.ts": { "statements": { - "covered": 190, + "covered": 199, "total": 264, - "percentage": 71.96 + "percentage": 75.37 }, "branches": { - "covered": 19, - "total": 31, - "percentage": 61.29 + "covered": 26, + "total": 38, + "percentage": 68.42 }, "functions": { - "covered": 9, + "covered": 10, "total": 12, - "percentage": 75 + "percentage": 83.33 }, "lines": { - "covered": 190, + "covered": 199, "total": 264, - "percentage": 71.96 + "percentage": 75.37 } }, "src/vs/platform/agentHost/node/copilot/copilotPluginConverters.ts": { @@ -5206,11 +5624,33 @@ "percentage": 70.15 } }, + "src/vs/platform/agentHost/node/copilot/copilotSdkChatError.ts": { + "statements": { + "covered": 58, + "total": 64, + "percentage": 90.62 + }, + "branches": { + "covered": 3, + "total": 16, + "percentage": 18.75 + }, + "functions": { + "covered": 3, + "total": 3, + "percentage": 100 + }, + "lines": { + "covered": 58, + "total": 64, + "percentage": 90.62 + } + }, "src/vs/platform/agentHost/node/copilot/copilotSessionLauncher.ts": { "statements": { - "covered": 559, - "total": 682, - "percentage": 81.96 + "covered": 565, + "total": 688, + "percentage": 82.12 }, "branches": { "covered": 63, @@ -5223,9 +5663,9 @@ "percentage": 80.64 }, "lines": { - "covered": 559, - "total": 682, - "percentage": 81.96 + "covered": 565, + "total": 688, + "percentage": 82.12 } }, "src/vs/platform/agentHost/node/copilot/copilotSessionWrapper.ts": { @@ -5252,31 +5692,31 @@ }, "src/vs/platform/agentHost/node/copilot/copilotShellTools.ts": { "statements": { - "covered": 513, + "covered": 522, "total": 811, - "percentage": 63.25 + "percentage": 64.36 }, "branches": { - "covered": 27, - "total": 48, - "percentage": 56.25 + "covered": 30, + "total": 50, + "percentage": 60 }, "functions": { - "covered": 17, + "covered": 18, "total": 31, - "percentage": 54.83 + "percentage": 58.06 }, "lines": { - "covered": 513, + "covered": 522, "total": 811, - "percentage": 63.25 + "percentage": 64.36 } }, "src/vs/platform/agentHost/node/copilot/copilotSlashCommandCompletionProvider.ts": { "statements": { - "covered": 84, - "total": 230, - "percentage": 36.52 + "covered": 99, + "total": 269, + "percentage": 36.8 }, "branches": { "covered": 2, @@ -5285,13 +5725,13 @@ }, "functions": { "covered": 2, - "total": 6, - "percentage": 33.33 + "total": 8, + "percentage": 25 }, "lines": { - "covered": 84, - "total": 230, - "percentage": 36.52 + "covered": 99, + "total": 269, + "percentage": 36.8 } }, "src/vs/platform/agentHost/node/copilot/copilotSlashCommandProvider.ts": { @@ -5362,68 +5802,68 @@ }, "src/vs/platform/agentHost/node/copilot/copilotTokenFields.ts": { "statements": { - "covered": 9, + "covered": 20, "total": 26, - "percentage": 34.61 + "percentage": 76.92 }, "branches": { - "covered": 0, - "total": 0, - "percentage": 100 + "covered": 1, + "total": 4, + "percentage": 25 }, "functions": { - "covered": 0, + "covered": 1, "total": 2, - "percentage": 0 + "percentage": 50 }, "lines": { - "covered": 9, + "covered": 20, "total": 26, - "percentage": 34.61 + "percentage": 76.92 } }, "src/vs/platform/agentHost/node/copilot/copilotToolDisplay.ts": { "statements": { - "covered": 997, - "total": 1275, - "percentage": 78.19 + "covered": 969, + "total": 1206, + "percentage": 80.34 }, "branches": { - "covered": 174, - "total": 302, - "percentage": 57.61 + "covered": 164, + "total": 276, + "percentage": 59.42 }, "functions": { - "covered": 26, - "total": 34, - "percentage": 76.47 + "covered": 27, + "total": 35, + "percentage": 77.14 }, "lines": { - "covered": 997, - "total": 1275, - "percentage": 78.19 + "covered": 969, + "total": 1206, + "percentage": 80.34 } }, "src/vs/platform/agentHost/node/copilot/mapSessionEvents.ts": { "statements": { - "covered": 606, - "total": 875, - "percentage": 69.25 + "covered": 662, + "total": 944, + "percentage": 70.12 }, "branches": { - "covered": 78, - "total": 154, - "percentage": 50.64 + "covered": 87, + "total": 170, + "percentage": 51.17 }, "functions": { - "covered": 20, - "total": 21, - "percentage": 95.23 + "covered": 21, + "total": 22, + "percentage": 95.45 }, "lines": { - "covered": 606, - "total": 875, - "percentage": 69.25 + "covered": 662, + "total": 944, + "percentage": 70.12 } }, "src/vs/platform/agentHost/node/copilot/modelIdentifiers.ts": { @@ -5516,9 +5956,9 @@ }, "src/vs/platform/agentHost/node/copilot/prompts/promptRegistry.ts": { "statements": { - "covered": 222, + "covered": 221, "total": 241, - "percentage": 92.11 + "percentage": 91.7 }, "branches": { "covered": 16, @@ -5531,9 +5971,9 @@ "percentage": 100 }, "lines": { - "covered": 222, + "covered": 221, "total": 241, - "percentage": 92.11 + "percentage": 91.7 } }, "src/vs/platform/agentHost/node/copilot/prompts/systemMessage.ts": { @@ -5560,36 +6000,36 @@ }, "src/vs/platform/agentHost/node/copilot/prompts/toolInstructions.ts": { "statements": { - "covered": 104, - "total": 137, - "percentage": 75.91 + "covered": 119, + "total": 138, + "percentage": 86.23 }, "branches": { - "covered": 6, - "total": 10, - "percentage": 60 + "covered": 8, + "total": 19, + "percentage": 42.1 }, "functions": { - "covered": 4, - "total": 6, - "percentage": 66.66 + "covered": 6, + "total": 7, + "percentage": 85.71 }, "lines": { - "covered": 104, - "total": 137, - "percentage": 75.91 + "covered": 119, + "total": 138, + "percentage": 86.23 } }, "src/vs/platform/agentHost/node/copilot/sandboxConfigForSdk.ts": { "statements": { - "covered": 97, - "total": 129, - "percentage": 75.19 + "covered": 78, + "total": 117, + "percentage": 66.66 }, "branches": { "covered": 1, - "total": 22, - "percentage": 4.54 + "total": 23, + "percentage": 4.34 }, "functions": { "covered": 1, @@ -5597,9 +6037,9 @@ "percentage": 100 }, "lines": { - "covered": 97, - "total": 129, - "percentage": 75.19 + "covered": 78, + "total": 117, + "percentage": 66.66 } }, "src/vs/platform/agentHost/node/copilot/sessionCustomizationDiscovery.ts": { @@ -5692,9 +6132,9 @@ }, "src/vs/platform/agentHost/node/gitDiffContent.ts": { "statements": { - "covered": 69, - "total": 75, - "percentage": 92 + "covered": 78, + "total": 84, + "percentage": 92.85 }, "branches": { "covered": 7, @@ -5707,9 +6147,9 @@ "percentage": 100 }, "lines": { - "covered": 69, - "total": 75, - "percentage": 92 + "covered": 78, + "total": 84, + "percentage": 92.85 } }, "src/vs/platform/agentHost/node/localCommands/bangLocalCommand.ts": { @@ -5785,9 +6225,9 @@ "percentage": 100 }, "branches": { - "covered": 16, - "total": 17, - "percentage": 94.11 + "covered": 18, + "total": 19, + "percentage": 94.73 }, "functions": { "covered": 5, @@ -5802,9 +6242,9 @@ }, "src/vs/platform/agentHost/node/networkDiagnosticsService.ts": { "statements": { - "covered": 180, - "total": 194, - "percentage": 92.78 + "covered": 181, + "total": 195, + "percentage": 92.82 }, "branches": { "covered": 22, @@ -5817,9 +6257,9 @@ "percentage": 100 }, "lines": { - "covered": 180, - "total": 194, - "percentage": 92.78 + "covered": 181, + "total": 195, + "percentage": 92.82 } }, "src/vs/platform/agentHost/node/osc633Parser.ts": { @@ -5829,9 +6269,9 @@ "percentage": 79.88 }, "branches": { - "covered": 39, - "total": 48, - "percentage": 81.25 + "covered": 41, + "total": 49, + "percentage": 83.67 }, "functions": { "covered": 9, @@ -5868,24 +6308,24 @@ }, "src/vs/platform/agentHost/node/protocolServerHandler.ts": { "statements": { - "covered": 1528, - "total": 1783, - "percentage": 85.69 + "covered": 1590, + "total": 1813, + "percentage": 87.69 }, "branches": { - "covered": 265, - "total": 348, - "percentage": 76.14 + "covered": 300, + "total": 375, + "percentage": 80 }, "functions": { - "covered": 72, - "total": 84, - "percentage": 85.71 + "covered": 75, + "total": 85, + "percentage": 88.23 }, "lines": { - "covered": 1528, - "total": 1783, - "percentage": 85.69 + "covered": 1590, + "total": 1813, + "percentage": 87.69 } }, "src/vs/platform/agentHost/node/serverUrls.ts": { @@ -5912,14 +6352,14 @@ }, "src/vs/platform/agentHost/node/sessionDataService.ts": { "statements": { - "covered": 157, + "covered": 155, "total": 198, - "percentage": 79.29 + "percentage": 78.28 }, "branches": { - "covered": 21, + "covered": 20, "total": 24, - "percentage": 87.5 + "percentage": 83.33 }, "functions": { "covered": 12, @@ -5927,53 +6367,53 @@ "percentage": 85.71 }, "lines": { - "covered": 157, + "covered": 155, "total": 198, - "percentage": 79.29 + "percentage": 78.28 } }, "src/vs/platform/agentHost/node/sessionDatabase.ts": { "statements": { - "covered": 738, - "total": 869, - "percentage": 84.92 + "covered": 742, + "total": 872, + "percentage": 85.09 }, "branches": { - "covered": 111, - "total": 136, - "percentage": 81.61 + "covered": 107, + "total": 134, + "percentage": 79.85 }, "functions": { - "covered": 38, + "covered": 39, "total": 53, - "percentage": 71.69 + "percentage": 73.58 }, "lines": { - "covered": 738, - "total": 869, - "percentage": 84.92 + "covered": 742, + "total": 872, + "percentage": 85.09 } }, "src/vs/platform/agentHost/node/sessionDiffAggregator.ts": { "statements": { - "covered": 247, - "total": 460, - "percentage": 53.69 + "covered": 277, + "total": 507, + "percentage": 54.63 }, "branches": { - "covered": 19, - "total": 35, - "percentage": 54.28 + "covered": 24, + "total": 43, + "percentage": 55.81 }, "functions": { "covered": 4, - "total": 5, - "percentage": 80 + "total": 6, + "percentage": 66.66 }, "lines": { - "covered": 247, - "total": 460, - "percentage": 53.69 + "covered": 277, + "total": 507, + "percentage": 54.63 } }, "src/vs/platform/agentHost/node/sessionPermissions.ts": { @@ -5983,9 +6423,9 @@ "percentage": 77.23 }, "branches": { - "covered": 84, - "total": 125, - "percentage": 67.2 + "covered": 86, + "total": 127, + "percentage": 67.71 }, "functions": { "covered": 23, @@ -6023,8 +6463,8 @@ "src/vs/platform/agentHost/node/shared/agentEditAttributionService.ts": { "statements": { "covered": 274, - "total": 1408, - "percentage": 19.46 + "total": 1414, + "percentage": 19.37 }, "branches": { "covered": 10, @@ -6038,37 +6478,37 @@ }, "lines": { "covered": 274, - "total": 1408, - "percentage": 19.46 + "total": 1414, + "percentage": 19.37 } }, "src/vs/platform/agentHost/node/shared/agentFeedbackServerTools.ts": { "statements": { - "covered": 577, - "total": 611, - "percentage": 94.43 + "covered": 561, + "total": 608, + "percentage": 92.26 }, "branches": { - "covered": 61, - "total": 94, - "percentage": 64.89 + "covered": 59, + "total": 91, + "percentage": 64.83 }, "functions": { - "covered": 22, - "total": 22, - "percentage": 100 + "covered": 24, + "total": 25, + "percentage": 96 }, "lines": { - "covered": 577, - "total": 611, - "percentage": 94.43 + "covered": 561, + "total": 608, + "percentage": 92.26 } }, "src/vs/platform/agentHost/node/shared/agentHostOctoKitService.ts": { "statements": { - "covered": 154, - "total": 370, - "percentage": 41.62 + "covered": 185, + "total": 445, + "percentage": 41.57 }, "branches": { "covered": 1, @@ -6077,35 +6517,35 @@ }, "functions": { "covered": 1, - "total": 9, - "percentage": 11.11 + "total": 13, + "percentage": 7.69 }, "lines": { - "covered": 154, - "total": 370, - "percentage": 41.62 + "covered": 185, + "total": 445, + "percentage": 41.57 } }, "src/vs/platform/agentHost/node/shared/agentServerToolHost.ts": { "statements": { - "covered": 140, - "total": 144, - "percentage": 97.22 + "covered": 153, + "total": 158, + "percentage": 96.83 }, "branches": { - "covered": 8, - "total": 11, - "percentage": 72.72 + "covered": 11, + "total": 15, + "percentage": 73.33 }, "functions": { - "covered": 4, - "total": 4, + "covered": 5, + "total": 5, "percentage": 100 }, "lines": { - "covered": 140, - "total": 144, - "percentage": 97.22 + "covered": 153, + "total": 158, + "percentage": 96.83 } }, "src/vs/platform/agentHost/node/shared/arcToolEdit.ts": { @@ -6132,24 +6572,24 @@ }, "src/vs/platform/agentHost/node/shared/copilotApiService.ts": { "statements": { - "covered": 1031, - "total": 1282, - "percentage": 80.42 + "covered": 1100, + "total": 1276, + "percentage": 86.2 }, "branches": { - "covered": 44, - "total": 89, - "percentage": 49.43 + "covered": 57, + "total": 102, + "percentage": 55.88 }, "functions": { - "covered": 23, - "total": 30, - "percentage": 76.66 + "covered": 25, + "total": 28, + "percentage": 89.28 }, "lines": { - "covered": 1031, - "total": 1282, - "percentage": 80.42 + "covered": 1100, + "total": 1276, + "percentage": 86.2 } }, "src/vs/platform/agentHost/node/shared/editArcReporter.ts": { @@ -6242,14 +6682,14 @@ }, "src/vs/platform/agentHost/node/shared/fileEditTracker.ts": { "statements": { - "covered": 232, - "total": 246, - "percentage": 94.3 + "covered": 236, + "total": 250, + "percentage": 94.4 }, "branches": { - "covered": 33, - "total": 39, - "percentage": 84.61 + "covered": 36, + "total": 42, + "percentage": 85.71 }, "functions": { "covered": 7, @@ -6257,31 +6697,9 @@ "percentage": 100 }, "lines": { - "covered": 232, - "total": 246, - "percentage": 94.3 - } - }, - "src/vs/platform/agentHost/node/shared/forwardedChatError.ts": { - "statements": { - "covered": 185, - "total": 313, - "percentage": 59.1 - }, - "branches": { - "covered": 2, - "total": 12, - "percentage": 16.66 - }, - "functions": { - "covered": 2, - "total": 12, - "percentage": 16.66 - }, - "lines": { - "covered": 185, - "total": 313, - "percentage": 59.1 + "covered": 236, + "total": 250, + "percentage": 94.4 } }, "src/vs/platform/agentHost/node/shared/loopbackProxyServer.ts": { @@ -6314,8 +6732,8 @@ }, "branches": { "covered": 65, - "total": 79, - "percentage": 82.27 + "total": 78, + "percentage": 83.33 }, "functions": { "covered": 21, @@ -6350,6 +6768,28 @@ "percentage": 87.09 } }, + "src/vs/platform/agentHost/node/shared/proxyChatError.ts": { + "statements": { + "covered": 162, + "total": 232, + "percentage": 69.82 + }, + "branches": { + "covered": 5, + "total": 23, + "percentage": 21.73 + }, + "functions": { + "covered": 5, + "total": 9, + "percentage": 55.55 + }, + "lines": { + "covered": 162, + "total": 232, + "percentage": 69.82 + } + }, "src/vs/platform/agentHost/node/shared/serverToolGroups.ts": { "statements": { "covered": 70, @@ -6374,24 +6814,24 @@ }, "src/vs/platform/agentHost/node/shared/sessionServerTools.ts": { "statements": { - "covered": 991, - "total": 1094, - "percentage": 90.58 + "covered": 982, + "total": 1085, + "percentage": 90.5 }, "branches": { - "covered": 165, - "total": 245, - "percentage": 67.34 + "covered": 147, + "total": 237, + "percentage": 62.02 }, "functions": { - "covered": 48, - "total": 50, - "percentage": 96 + "covered": 47, + "total": 49, + "percentage": 95.91 }, "lines": { - "covered": 991, - "total": 1094, - "percentage": 90.58 + "covered": 982, + "total": 1085, + "percentage": 90.5 } }, "src/vs/platform/agentHost/node/shared/shellCommandExecution.ts": { @@ -6401,9 +6841,9 @@ "percentage": 61.82 }, "branches": { - "covered": 11, + "covered": 13, "total": 24, - "percentage": 45.83 + "percentage": 54.16 }, "functions": { "covered": 8, @@ -6418,31 +6858,31 @@ }, "src/vs/platform/agentHost/node/shared/worktreeIsolation.ts": { "statements": { - "covered": 820, - "total": 1067, - "percentage": 76.85 + "covered": 819, + "total": 1106, + "percentage": 74.05 }, "branches": { - "covered": 101, - "total": 150, - "percentage": 67.33 + "covered": 87, + "total": 148, + "percentage": 58.78 }, "functions": { - "covered": 36, + "covered": 37, "total": 48, - "percentage": 75 + "percentage": 77.08 }, "lines": { - "covered": 820, - "total": 1067, - "percentage": 76.85 + "covered": 819, + "total": 1106, + "percentage": 74.05 } }, "src/vs/platform/agentHost/node/webSocketTransport.ts": { "statements": { - "covered": 218, - "total": 254, - "percentage": 85.82 + "covered": 215, + "total": 258, + "percentage": 83.33 }, "branches": { "covered": 15, @@ -6455,9 +6895,9 @@ "percentage": 77.77 }, "lines": { - "covered": 218, - "total": 254, - "percentage": 85.82 + "covered": 215, + "total": 258, + "percentage": 83.33 } }, "src/vs/platform/agentHost/node/workspacelessScratchDir.ts": { diff --git a/src/vs/platform/agentHost/test/node/e2e/suites/agentHostE2ESuites.ts b/src/vs/platform/agentHost/test/node/e2e/suites/agentHostE2ESuites.ts index 9093b44bb9d..be154ed9eb4 100644 --- a/src/vs/platform/agentHost/test/node/e2e/suites/agentHostE2ESuites.ts +++ b/src/vs/platform/agentHost/test/node/e2e/suites/agentHostE2ESuites.ts @@ -30,6 +30,7 @@ const isLinux = process.platform === 'linux'; const RECORD = process.env['AGENT_HOST_REPLAY_RECORD'] === '1' || process.env['AGENT_HOST_UPDATE_SNAPSHOTS'] === '1'; const RUN_RECORD_ONLY_TESTS = process.env['AGENT_HOST_REPLAY_RECORD'] === '1'; const RUN_KNOWN_ISSUE_TESTS = RECORD && process.env['AGENT_HOST_RUN_KNOWN_ISSUES'] === '1'; +const RUN_HOST_ONLY_KNOWN_ISSUE_TESTS = process.env['AGENT_HOST_RUN_KNOWN_ISSUES'] === '1'; const isWindows = process.platform === 'win32'; interface IDefineOptions { @@ -57,6 +58,7 @@ function defineSuite(config: IAgentHostE2EProviderConfig, options: IDefineOption isWindows, runRecordOnlyTests: RUN_RECORD_ONLY_TESTS, runKnownIssueTests: RUN_KNOWN_ISSUE_TESTS, + runHostOnlyKnownIssueTests: RUN_HOST_ONLY_KNOWN_ISSUE_TESTS, registerNoModelTrafficTest: title => noModelTrafficTestTitles.add(title), get observedModelRequestBodies() { return lease?.observedModelRequestBodies ?? []; }, restartServer: async () => { diff --git a/src/vs/platform/agentHost/test/node/e2e/suites/changesetSuite.ts b/src/vs/platform/agentHost/test/node/e2e/suites/changesetSuite.ts index eadba68e8d2..e727cec895d 100644 --- a/src/vs/platform/agentHost/test/node/e2e/suites/changesetSuite.ts +++ b/src/vs/platform/agentHost/test/node/e2e/suites/changesetSuite.ts @@ -141,6 +141,19 @@ export function defineChangesetTests(context: IAgentHostE2ETestContext): void { return `!node -e "require('fs').writeFileSync(process.argv[1],process.argv[2])" ${file} ${contents}`; } + function writeFileBase64Command(file: string, contents: string): string { + const encodedFile = Buffer.from(file).toString('base64'); + const encodedContents = Buffer.from(contents).toString('base64'); + return `!node -e "const fs=require('fs');fs.writeFileSync(Buffer.from(process.argv[1],'base64').toString(),Buffer.from(process.argv[2],'base64'))" ${encodedFile} ${encodedContents}`; + } + + function writeFileTwiceBase64Command(file: string, first: string, second: string): string { + const encodedFile = Buffer.from(file).toString('base64'); + const encodedFirst = Buffer.from(first).toString('base64'); + const encodedSecond = Buffer.from(second).toString('base64'); + return `!node -e "const fs=require('fs');const file=Buffer.from(process.argv[1],'base64').toString();fs.writeFileSync(file,Buffer.from(process.argv[2],'base64'));fs.writeFileSync(file,Buffer.from(process.argv[3],'base64'))" ${encodedFile} ${encodedFirst} ${encodedSecond}`; + } + function deleteFileCommand(file: string): string { return `!node -e "require('fs').unlinkSync(process.argv[1])" ${file}`; } @@ -153,6 +166,10 @@ export function defineChangesetTests(context: IAgentHostE2ETestContext): void { return file.edit.after?.uri ?? file.edit.before?.uri ?? ''; } + function fileHasBasename(file: IObservedChangesetFile, basename: string): boolean { + return URI.parse(fileUri(file)).path.endsWith(`/${basename}`); + } + /** * Waits for a `changeset/contentChanged` on `channel` that reports * `basename`. Matched by basename because git resolves symlinks when @@ -165,10 +182,10 @@ export function defineChangesetTests(context: IAgentHostE2ETestContext): void { return false; } const action = getActionEnvelope(n).action as IContentChangedAction; - return action.files.some(file => fileUri(file).endsWith(`/${basename}`)); + return action.files.some(file => fileHasBasename(file, basename)); }, timeout); const action = getActionEnvelope(notification).action as IContentChangedAction; - return action.files.find(file => fileUri(file).endsWith(`/${basename}`))!; + return action.files.find(file => fileHasBasename(file, basename))!; } async function waitForTurnComplete(sessionUri: string, turnId: string): Promise { @@ -201,7 +218,7 @@ export function defineChangesetTests(context: IAgentHostE2ETestContext): void { const state = await changesetState(channel); const files: IObservedChangesetFile[] = []; for (const basename of basenames) { - const file = state.files.find(file => fileUri(file).endsWith(`/${basename}`)); + const file = state.files.find(file => fileHasBasename(file, basename)); if (file) { files.push(file); } @@ -489,6 +506,113 @@ export function defineChangesetTests(context: IAgentHostE2ETestContext): void { ]); }); + conformanceTest(context, 'ignored files do not appear in a branch changeset', async function () { + const workspace = createGitWorkspace('ahp-changeset-ignored-'); + writeFileSync(join(workspace, '.gitignore'), 'ignored.log\n'); + execSync('git add .gitignore', { cwd: workspace }); + execSync('git commit -q -m "ignore generated log"', { cwd: workspace }); + const sessionUri = await createSessionIn(workspace, 'changeset-ignored'); + const branchUri = buildBranchChangesetUri(sessionUri); + await context.client.call('subscribe', { channel: branchUri }); + await changesetState(branchUri); + context.client.clearReceived(); + const changed = context.client.waitForNotification(n => + isActionNotification(n, 'changeset/contentChanged') && getActionEnvelope(n).channel === branchUri, + 60_000, + ); + + await runBangTurn(sessionUri, 'turn-changeset-ignored', writeFileCommand('ignored.log', 'ignored'), 1); + await changed; + const state = await changesetState(branchUri); + + assert.deepStrictEqual(state.files, []); + }); + + conformanceTest(context, 'a file created and deleted in one turn leaves no branch change', async function () { + const workspace = createGitWorkspace('ahp-changeset-create-delete-'); + const sessionUri = await createSessionIn(workspace, 'changeset-create-delete'); + const branchUri = buildBranchChangesetUri(sessionUri); + await context.client.call('subscribe', { channel: branchUri }); + await changesetState(branchUri); + context.client.clearReceived(); + const changed = context.client.waitForNotification(n => + isActionNotification(n, 'changeset/contentChanged') && getActionEnvelope(n).channel === branchUri, + 60_000, + ); + + await runBangTurn(sessionUri, 'turn-changeset-create-delete', '!node -e "const fs=require(\'fs\');fs.writeFileSync(\'temporary.txt\',\'temporary\');fs.unlinkSync(\'temporary.txt\')"', 1); + await changed; + const state = await changesetState(branchUri); + + assert.deepStrictEqual(state.files, []); + }); + + conformanceTest(context, 'an edit restored in the same turn leaves no branch change', async function () { + const workspace = createGitWorkspace('ahp-changeset-edit-restore-'); + const sessionUri = await createSessionIn(workspace, 'changeset-edit-restore'); + const branchUri = buildBranchChangesetUri(sessionUri); + await context.client.call('subscribe', { channel: branchUri }); + await changesetState(branchUri); + context.client.clearReceived(); + const changed = context.client.waitForNotification(n => + isActionNotification(n, 'changeset/contentChanged') && getActionEnvelope(n).channel === branchUri, + 60_000, + ); + + await runBangTurn(sessionUri, 'turn-changeset-edit-restore', writeFileTwiceBase64Command('seed.txt', 'changed', 'seed\n'), 1); + await changed; + const state = await changesetState(branchUri); + + assert.deepStrictEqual(state.files, []); + }); + + conformanceTest(context, 'an added multiline file reports every added line', async function () { + const workspace = createGitWorkspace('ahp-changeset-multiline-add-'); + const sessionUri = await createSessionIn(workspace, 'changeset-multiline-add'); + const branchUri = buildBranchChangesetUri(sessionUri); + await context.client.call('subscribe', { channel: branchUri }); + + await runBangTurn(sessionUri, 'turn-changeset-multiline-add', writeFileBase64Command('lines.txt', 'one\ntwo\nthree\n'), 1); + const [file] = await waitForChangesetFiles(branchUri, ['lines.txt']); + + assert.deepStrictEqual(file.edit.diff, { added: 3, removed: 0 }); + }); + + conformanceTest(context, 'deleting a multiline tracked file reports every removed line', async function () { + const workspace = createGitWorkspace('ahp-changeset-multiline-delete-'); + writeFileSync(join(workspace, 'lines.txt'), 'one\ntwo\nthree\n'); + execSync('git add lines.txt', { cwd: workspace }); + execSync('git commit -q -m "add multiline file"', { cwd: workspace }); + const sessionUri = await createSessionIn(workspace, 'changeset-multiline-delete'); + const branchUri = buildBranchChangesetUri(sessionUri); + await context.client.call('subscribe', { channel: branchUri }); + + await runBangTurn(sessionUri, 'turn-changeset-multiline-delete', deleteFileCommand('lines.txt'), 1); + const [file] = await waitForChangesetFiles(branchUri, ['lines.txt']); + + assert.deepStrictEqual(file.edit.diff, { added: 0, removed: 3 }); + }); + + conformanceTest(context, 'a changed filename containing spaces remains addressable', async function () { + const workspace = createGitWorkspace('ahp-changeset-spaced-file-'); + const sessionUri = await createSessionIn(workspace, 'changeset-spaced-file'); + const branchUri = buildBranchChangesetUri(sessionUri); + await context.client.call('subscribe', { channel: branchUri }); + + await runBangTurn(sessionUri, 'turn-changeset-spaced-file', writeFileBase64Command('spaced file.txt', 'content\n'), 1); + const [file] = await waitForChangesetFiles(branchUri, ['spaced file.txt']); + + assert.deepStrictEqual({ + id: URI.parse(file.id).path.endsWith('/spaced file.txt'), + after: file.edit.after?.uri.endsWith('/spaced%20file.txt') || file.edit.after?.uri.endsWith('/spaced file.txt'), + exists: existsSync(join(workspace, 'spaced file.txt')), + }, { + id: true, + after: true, + exists: true, + }); + }); + conformanceTest(context, 'an empty repository reports an untracked file as added', async function () { const workspace = mkdtempSync(join(tmpdir(), 'ahp-changeset-empty-repo-')); tempDirs.push(workspace); diff --git a/src/vs/platform/agentHost/test/node/e2e/suites/clientFilesystemSuite.ts b/src/vs/platform/agentHost/test/node/e2e/suites/clientFilesystemSuite.ts index 4674a7ab4e8..f59c076dee8 100644 --- a/src/vs/platform/agentHost/test/node/e2e/suites/clientFilesystemSuite.ts +++ b/src/vs/platform/agentHost/test/node/e2e/suites/clientFilesystemSuite.ts @@ -145,6 +145,43 @@ export function defineClientFilesystemTests(context: IAgentHostE2ETestContext): ]); }); + conformanceTest(context, 'resourceList returns an empty collection for an empty directory', async function () { + await initializeClient('resource-list-empty'); + const root = createWorkspace('ahp-resource-list-empty-'); + + const result = await context.client.call('resourceList', { + channel: ROOT_STATE_URI, + uri: URI.file(root).toString(), + }); + + assert.deepStrictEqual(result.entries, []); + }); + + conformanceTest(context, 'resourceWrite truncates an existing file by default', async function () { + await initializeClient('resource-write-default-truncate'); + const root = createWorkspace('ahp-resource-write-default-truncate-'); + const file = fileUri(root, 'replace.txt'); + writeFileSync(join(root, 'replace.txt'), 'LONGER_ORIGINAL'); + + await writeText(file, 'short'); + + assert.strictEqual(readFileSync(join(root, 'replace.txt'), 'utf8'), 'short'); + }); + + conformanceTest(context, 'resourceDelete removes an empty directory without recursive mode', async function () { + await initializeClient('resource-delete-empty-directory'); + const root = createWorkspace('ahp-resource-delete-empty-directory-'); + const directory = join(root, 'empty'); + mkdirSync(directory); + + await context.client.call('resourceDelete', { + channel: ROOT_STATE_URI, + uri: URI.file(directory).toString(), + }); + + assert.strictEqual(existsSync(directory), false); + }); + conformanceTest(context, 'resourceCopy, resourceMove, and resourceDelete mutate the tree', async function () { await initializeClient('resource-mutate'); const root = createWorkspace('ahp-resource-mutate-'); diff --git a/src/vs/platform/agentHost/test/node/e2e/suites/coreSuite.ts b/src/vs/platform/agentHost/test/node/e2e/suites/coreSuite.ts index a16839fc18e..5c16728f3cd 100644 --- a/src/vs/platform/agentHost/test/node/e2e/suites/coreSuite.ts +++ b/src/vs/platform/agentHost/test/node/e2e/suites/coreSuite.ts @@ -141,6 +141,30 @@ export function defineCoreTests(context: IAgentHostE2ETestContext): void { assert.ok(responseParts.length > 0, 'should have received at least one response part'); }); + test('preserves a fenced multiline markdown response', async function () { + this.timeout(120_000); + const workspaceDir = mkdtempSync(join(tmpdir(), 'ahp-markdown-response-')); + tempDirs.push(workspaceDir); + const sessionUri = await createRealSession( + context.client, + config, + `markdown-response-${config.provider}`, + createdSessions, + URI.file(workspaceDir), + ); + const expected = '```text\nALPHA\nBETA\n```'; + + const result = await driveTurnToCompletion( + context.client, + sessionUri, + 'turn-markdown-response', + `Reply with exactly this Markdown code block and nothing else:\n${expected}`, + 1, + ); + + assert.strictEqual(result.responseText, expected); + }); + test('listModels returns well-shaped model entries after authenticate', async function () { this.timeout(60_000); diff --git a/src/vs/platform/agentHost/test/node/e2e/suites/e2eTestContext.ts b/src/vs/platform/agentHost/test/node/e2e/suites/e2eTestContext.ts index ef4a9b852c3..d790ae99da1 100644 --- a/src/vs/platform/agentHost/test/node/e2e/suites/e2eTestContext.ts +++ b/src/vs/platform/agentHost/test/node/e2e/suites/e2eTestContext.ts @@ -43,6 +43,8 @@ export interface IAgentHostE2ETestContext { readonly runRecordOnlyTests: boolean; /** Whether explicitly requested known-issue reproductions should run against live recording. */ readonly runKnownIssueTests: boolean; + /** Whether explicitly requested model-free known-issue reproductions should run in strict replay. */ + readonly runHostOnlyKnownIssueTests: boolean; readonly registerNoModelTrafficTest: (title: string) => void; readonly observedModelRequestBodies: readonly string[]; /** diff --git a/src/vs/platform/agentHost/test/node/e2e/suites/protocolContractsSuite.ts b/src/vs/platform/agentHost/test/node/e2e/suites/protocolContractsSuite.ts index 15212007d1d..226e185858d 100644 --- a/src/vs/platform/agentHost/test/node/e2e/suites/protocolContractsSuite.ts +++ b/src/vs/platform/agentHost/test/node/e2e/suites/protocolContractsSuite.ts @@ -16,6 +16,7 @@ import { mkdtempSync } from 'fs'; import { tmpdir } from 'os'; import { join } from '../../../../../../base/common/path.js'; import { URI } from '../../../../../../base/common/uri.js'; +import { generateUuid } from '../../../../../../base/common/uuid.js'; import { ReconnectResultType, type FetchTurnsResult, type InitializeResult, type ListSessionsResult, type ReconnectResult, type SubscribeResult } from '../../../../common/state/protocol/commands.js'; import type { SessionSummaryChangedParams } from '../../../../common/state/protocol/channels-root/notifications.js'; import type { OtlpExportLogsParams } from '../../../../common/state/protocol/channels-otlp/notifications.js'; @@ -23,7 +24,7 @@ import type { IAgentHostManagedSettingsDiagnostics, IAgentHostNetworkDiagnostics import { ActionType, type StateAction } from '../../../../common/state/sessionActions.js'; import { TerminalClaimKind } from '../../../../common/state/protocol/state.js'; import { buildChatUri, buildDefaultChatUri, MessageKind, ROOT_STATE_URI, SessionStatus, type ChatState, type SessionState, type Turn } from '../../../../common/state/sessionState.js'; -import { createRealSession, dispatchTurn } from '../harness/agentHostE2ETestHarness.js'; +import { createRealSession, dispatchTurn, resolveGitHubToken } from '../harness/agentHostE2ETestHarness.js'; import { PROTOCOL_VERSION } from '../../../../common/state/protocol/version/registry.js'; import { AhpErrorCodes, JsonRpcErrorCodes } from '../../../../common/state/sessionProtocol.js'; import { getActionEnvelope, isActionNotification, type TestProtocolClient } from '../../serverIntegrationTestHelpers.js'; @@ -209,6 +210,41 @@ export function defineProtocolContractTests(context: IAgentHostE2ETestContext): } }); + conformanceTest(context, 'initialize reports the negotiated protocol and sequence', async function () { + const client = await context.connectClient(); + try { + const initialized = await client.call('initialize', { + channel: ROOT_STATE_URI, + protocolVersions: [PROTOCOL_VERSION], + clientId: `server-identity-${config.provider}`, + clientInfo: { name: 'agent-host-e2e', version: '1.0.0' }, + }); + + assert.deepStrictEqual({ + protocolVersion: initialized.protocolVersion, + serverSeqIsNonNegative: initialized.serverSeq >= 0, + }, { + protocolVersion: PROTOCOL_VERSION, + serverSeqIsNonNegative: true, + }); + } finally { + client.close(); + } + }); + + conformanceTest(context, 'initialize cannot be repeated after the handshake', async function () { + const client = await initializeAdditionalClient('repeat-initialize'); + try { + await assert.rejects(client.call('initialize', { + channel: ROOT_STATE_URI, + protocolVersions: [PROTOCOL_VERSION], + clientId: `repeat-initialize-again-${config.provider}`, + }), { code: JsonRpcErrorCodes.MethodNotFound }); + } finally { + client.close(); + } + }); + conformanceTest(context, 'listSessions includes provider-backed session metadata', async function () { const { sessionUri, workspace } = await createSession('list-session-metadata'); const chatUri = buildDefaultChatUri(sessionUri); @@ -668,6 +704,211 @@ export function defineProtocolContractTests(context: IAgentHostE2ETestContext): } }); + conformanceTest(context, 'resource requests before initialize are rejected', async function () { + const client = await context.connectClient(); + try { + await assert.rejects(client.call('resourceResolve', { + channel: ROOT_STATE_URI, + uri: URI.file(tmpdir()).toString(), + }), { code: JsonRpcErrorCodes.MethodNotFound }); + } finally { + client.close(); + } + }); + + conformanceTest(context, 'unknown requests after initialize are rejected', async function () { + const client = await initializeAdditionalClient('unknown-request'); + try { + await assert.rejects(client.call('agentHostE2E/unknownRequest', { + channel: ROOT_STATE_URI, + }), { code: JsonRpcErrorCodes.MethodNotFound }); + } finally { + client.close(); + } + }); + + conformanceTest(context, 'reconnect rejects an unknown client', async function () { + const client = await context.connectClient(); + try { + await assert.rejects(client.call('reconnect', { + channel: ROOT_STATE_URI, + clientId: `unknown-reconnect-${config.provider}`, + lastSeenServerSeq: 0, + subscriptions: [], + }), { code: AhpErrorCodes.NotFound }); + } finally { + client.close(); + } + }); + + conformanceTest(context, 'creating a session with an unknown provider is rejected', async function () { + const client = await initializeAdditionalClient('unknown-provider'); + try { + await assert.rejects(client.call('createSession', { + channel: 'missing-provider:/session', + provider: 'missing-provider', + }), { code: AhpErrorCodes.ProviderNotFound }); + } finally { + client.close(); + } + }); + + conformanceTest(context, 'creating a duplicate session resource is rejected', async function () { + const { sessionUri, workspace } = await createSession('duplicate-session'); + + await assert.rejects(context.client.call('createSession', { + channel: sessionUri, + provider: config.provider, + workingDirectories: [URI.file(workspace).toString()], + config: { isolation: 'folder' }, + }), { code: AhpErrorCodes.SessionAlreadyExists }); + }, context.runHostOnlyKnownIssueTests); + + conformanceTest(context, 'a session cannot fork onto its own resource', async function () { + const { sessionUri } = await createSession('self-fork'); + + await assert.rejects(context.client.call('createSession', { + channel: sessionUri, + provider: config.provider, + fork: { session: sessionUri, turnId: 'irrelevant' }, + }), { code: AhpErrorCodes.SessionAlreadyExists }); + }); + + conformanceTest(context, 'forking from a missing session is rejected', async function () { + const target = URI.from({ scheme: config.scheme, path: `/${generateUuid()}` }).toString(); + const missingSource = URI.from({ scheme: config.scheme, path: `/${generateUuid()}` }).toString(); + await context.client.call('initialize', { + channel: ROOT_STATE_URI, + protocolVersions: [PROTOCOL_VERSION], + clientId: `missing-fork-source-${config.provider}`, + }); + + await assert.rejects(context.client.call('createSession', { + channel: target, + provider: config.provider, + fork: { session: missingSource, turnId: 'missing-turn' }, + }), { code: AhpErrorCodes.SessionNotFound }); + }); + + conformanceTest(context, 'createSession rejects an active client owned by another connection', async function () { + const client = await context.connectClient(); + try { + await client.call('initialize', { + channel: ROOT_STATE_URI, + protocolVersions: [PROTOCOL_VERSION], + clientId: `active-client-owner-${config.provider}`, + }); + await assert.rejects(client.call('createSession', { + channel: URI.from({ scheme: config.scheme, path: `/${generateUuid()}` }).toString(), + provider: config.provider, + activeClient: { clientId: 'different-client', displayName: 'Different Client', tools: [] }, + }), { code: JsonRpcErrorCodes.InvalidParams }); + } finally { + client.close(); + } + }); + + conformanceTest(context, 'createSession seeds a matching active client into session state', async function () { + const workspace = mkdtempSync(join(tmpdir(), 'ahp-active-client-create-')); + tempDirs.push(workspace); + const clientId = `active-client-create-${config.provider}`; + const client = await context.connectClient(); + const sessionUri = URI.from({ scheme: config.scheme, path: `/${generateUuid()}` }).toString(); + let created = false; + try { + await client.call('initialize', { + channel: ROOT_STATE_URI, + protocolVersions: [PROTOCOL_VERSION], + clientId, + }); + await client.call('authenticate', { + channel: ROOT_STATE_URI, + resource: 'https://api.github.com', + token: config.githubToken ?? resolveGitHubToken(), + }); + await client.call('createSession', { + channel: sessionUri, + provider: config.provider, + workingDirectories: [URI.file(workspace).toString()], + config: { isolation: 'folder' }, + activeClient: { clientId, displayName: 'Creating Client', tools: [] }, + }); + created = true; + + const subscribed = await client.call('subscribe', { channel: sessionUri }); + const state = subscribed.snapshot!.state as SessionState; + assert.deepStrictEqual(state.activeClients, [{ + clientId, + displayName: 'Creating Client', + tools: [], + }]); + } finally { + if (created) { + await client.call('disposeSession', { channel: sessionUri }); + } + client.close(); + } + }); + + conformanceTest(context, 'creating a chat for a missing session is rejected', async function () { + const client = await initializeAdditionalClient('missing-chat-session'); + const sessionUri = URI.from({ scheme: config.scheme, path: '/missing-chat-session' }).toString(); + try { + await assert.rejects(client.call('createChat', { + channel: sessionUri, + chat: buildChatUri(sessionUri, 'peer'), + }), { code: AhpErrorCodes.SessionNotFound }); + } finally { + client.close(); + } + }); + + conformanceTest(context, 'subscribing twice does not duplicate action delivery', async function () { + const { sessionUri } = await createSession('duplicate-subscription'); + const chatUri = buildDefaultChatUri(sessionUri); + await context.client.call('subscribe', { channel: chatUri }); + await context.client.call('subscribe', { channel: chatUri }); + context.client.clearReceived(); + + const clientSeq = nextClientSeq(); + const action = { type: ActionType.ChatDraftChanged, draft: { text: 'single delivery', origin: { kind: MessageKind.User } } } as const; + context.client.dispatch({ channel: chatUri, clientSeq, action }); + await context.client.waitForNotification(n => + isActionNotification(n, action.type) + && getActionEnvelope(n).channel === chatUri + && getActionEnvelope(n).origin?.clientSeq === clientSeq, + ); + await context.client.call('ping', { channel: ROOT_STATE_URI }); + const deliveries = context.client.receivedNotifications(n => + isActionNotification(n, action.type) + && getActionEnvelope(n).channel === chatUri + && getActionEnvelope(n).origin?.clientSeq === clientSeq, + ); + + assert.strictEqual(deliveries.length, 1); + }); + + conformanceTest(context, 'resubscribing receives state changed while unsubscribed', async function () { + const { sessionUri } = await createSession('resubscribe-snapshot'); + const chatUri = buildDefaultChatUri(sessionUri); + context.client.notify('unsubscribe', { channel: chatUri }); + const clientSeq = nextClientSeq(); + context.client.dispatch({ + channel: chatUri, + clientSeq, + action: { + type: ActionType.ChatDraftChanged, + draft: { text: 'changed while unsubscribed', origin: { kind: MessageKind.User } }, + }, + }); + await context.client.call('ping', { channel: ROOT_STATE_URI }); + + const subscribed = await context.client.call('subscribe', { channel: chatUri }); + const state = subscribed.snapshot!.state as ChatState; + + assert.strictEqual(state.draft?.text, 'changed while unsubscribed'); + }); + // The protocol declares working-directory mutation on both the session and // chat channels, but the host rejects all four: applying one would change // the synchronized directory set without reconfiguring the agent's actual