diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index c9d7f5d98b..1476155587 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,11 +3,11 @@ "isRoot": true, "tools": { "nbgv": { - "version": "3.10.85", + "version": "3.10.91", "commands": [ "nbgv" ], "rollForward": false } } -} +} \ No newline at end of file diff --git a/eng/skill-validator/src/Evaluate/AgentRunner.cs b/eng/skill-validator/src/Evaluate/AgentRunner.cs index 4d17da2fce..e14a30d9eb 100644 --- a/eng/skill-validator/src/Evaluate/AgentRunner.cs +++ b/eng/skill-validator/src/Evaluate/AgentRunner.cs @@ -3,7 +3,7 @@ using System.Text.Json; using System.Text.Json.Nodes; using SkillValidator.Shared; -using GitHub.Copilot.SDK; +using GitHub.Copilot; namespace SkillValidator.Evaluate; @@ -68,14 +68,14 @@ public static async Task GetPluginClient( var options = new CopilotClientOptions { - LogLevel = verbose ? "info" : "none", + LogLevel = verbose ? CopilotLogLevel.Info : CopilotLogLevel.None, SessionFs = new SessionFsConfig { - InitialCwd = Environment.CurrentDirectory, + InitialWorkingDirectory = Environment.CurrentDirectory, SessionStatePath = "session-state", Conventions = OperatingSystem.IsWindows() - ? GitHub.Copilot.SDK.Rpc.SessionFsSetProviderConventions.Windows - : GitHub.Copilot.SDK.Rpc.SessionFsSetProviderConventions.Posix, + ? GitHub.Copilot.Rpc.SessionFsSetProviderConventions.Windows + : GitHub.Copilot.Rpc.SessionFsSetProviderConventions.Posix, }, }; @@ -443,22 +443,21 @@ internal static async Task BuildSessionConfig( Streaming = true, WorkingDirectory = workDir, SkillDirectories = [..skillDirs, ..noiseDirs], - ConfigDir = configDir, + ConfigDirectory = configDir, McpServers = sdkMcp, CustomAgents = customAgents, InfiniteSessions = new InfiniteSessionConfig { Enabled = false }, - // SDK 0.3.0 requires a SessionFsProvider (abstract base class). + // The SDK requires a SessionFsProvider (abstract base class). // Without this, events.jsonl files are never written and // session replay data is lost. - CreateSessionFsHandler = _ => new LocalSessionFsHandler(configDir), + CreateSessionFsProvider = _ => new LocalSessionFsHandler(configDir), OnPermissionRequest = (request, _) => { - // SDK 0.2.0: PermissionRequest only has Kind, no path data. - // Permission sandboxing is handled via Hooks.OnPreToolUse instead. - return Task.FromResult(new PermissionRequestResult - { - Kind = PermissionRequestResultKind.Approved, - }); + // PermissionRequest carries per-kind data (e.g. Read.Path, + // Write.FileName, Shell.FullCommandText/PossiblePaths), but we + // don't use it here: permission sandboxing is enforced via + // Hooks.OnPreToolUse instead, so this handler approves all. + return Task.FromResult(GitHub.Copilot.Rpc.PermissionDecision.ApproveOnce()); }, Hooks = new SessionHooks { @@ -580,7 +579,7 @@ await BuildSessionConfig(options.Skill, options.PluginRoot, options.Model, workD // Register event handler BEFORE SelectAsync so SubagentSelectedEvent // from the agent selection is captured in the events list. - session.On(evt => + session.On(evt => { var agentEvent = new AgentEvent( evt.Type, diff --git a/eng/skill-validator/src/Evaluate/Judge.cs b/eng/skill-validator/src/Evaluate/Judge.cs index cfd17b3252..a2e3962ba3 100644 --- a/eng/skill-validator/src/Evaluate/Judge.cs +++ b/eng/skill-validator/src/Evaluate/Judge.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Nodes; using SkillValidator.Shared; -using GitHub.Copilot.SDK; +using GitHub.Copilot.Rpc; namespace SkillValidator.Evaluate; @@ -47,10 +47,7 @@ public static class Judge { // Judge sessions: deny all tool permissions. Judging should be a // pure LLM task — no file access or tool execution needed. - return Task.FromResult(new PermissionRequestResult - { - Kind = PermissionRequestResultKind.UserNotAvailable, - }); + return Task.FromResult(PermissionDecision.UserNotAvailable()); }, cancellationToken: cancellationToken); diff --git a/eng/skill-validator/src/Evaluate/LlmSession.cs b/eng/skill-validator/src/Evaluate/LlmSession.cs index c24a6cb5b1..0725c48539 100644 --- a/eng/skill-validator/src/Evaluate/LlmSession.cs +++ b/eng/skill-validator/src/Evaluate/LlmSession.cs @@ -1,4 +1,5 @@ -using GitHub.Copilot.SDK; +using GitHub.Copilot; +using GitHub.Copilot.Rpc; namespace SkillValidator.Evaluate; @@ -30,7 +31,7 @@ internal static async Task SendAsync( int timeoutMs, bool verbose, string timeoutLabel = "LLM", - PermissionRequestHandler? onPermissionRequest = null, + Func>? onPermissionRequest = null, CancellationToken cancellationToken = default) { var client = await AgentRunner.GetSharedClient(verbose); @@ -52,11 +53,8 @@ internal static async Task SendAsync( Content = systemPrompt, }, InfiniteSessions = new InfiniteSessionConfig { Enabled = false }, - CreateSessionFsHandler = _ => new LocalSessionFsHandler(tempConfigDir), - OnPermissionRequest = onPermissionRequest ?? ((_, _) => Task.FromResult(new PermissionRequestResult - { - Kind = PermissionRequestResultKind.UserNotAvailable, - })), + CreateSessionFsProvider = _ => new LocalSessionFsHandler(tempConfigDir), + OnPermissionRequest = onPermissionRequest ?? ((_, _) => Task.FromResult(PermissionDecision.UserNotAvailable())), }); using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); @@ -70,7 +68,7 @@ internal static async Task SendAsync( string responseContent = ""; int inputTokens = 0, outputTokens = 0, cacheReadTokens = 0, cacheWriteTokens = 0; - session.On(evt => + session.On(evt => { switch (evt) { diff --git a/eng/skill-validator/src/Evaluate/LocalSessionFsHandler.cs b/eng/skill-validator/src/Evaluate/LocalSessionFsHandler.cs index 5fb5677e84..dddb134490 100644 --- a/eng/skill-validator/src/Evaluate/LocalSessionFsHandler.cs +++ b/eng/skill-validator/src/Evaluate/LocalSessionFsHandler.cs @@ -1,6 +1,6 @@ using System.Collections.Concurrent; -using GitHub.Copilot.SDK; -using GitHub.Copilot.SDK.Rpc; +using GitHub.Copilot; +using GitHub.Copilot.Rpc; namespace SkillValidator.Evaluate; @@ -117,14 +117,14 @@ protected override Task StatAsync(string path, Cancellation throw new FileNotFoundException($"Not found: {path}"); } - protected override Task MkdirAsync(string path, bool recursive, int? mode, CancellationToken cancellationToken) + protected override Task MakeDirectoryAsync(string path, bool recursive, int? mode, CancellationToken cancellationToken) { var resolved = ResolvePath(path); Directory.CreateDirectory(resolved); return Task.CompletedTask; } - protected override Task> ReaddirAsync(string path, CancellationToken cancellationToken) + protected override Task> ReadDirectoryAsync(string path, CancellationToken cancellationToken) { var resolved = ResolvePath(path); var entries = new List(); @@ -136,7 +136,7 @@ protected override Task> ReaddirAsync(string path, CancellationTok return Task.FromResult>(entries); } - protected override Task> ReaddirWithTypesAsync(string path, CancellationToken cancellationToken) + protected override Task> ReadDirectoryWithTypesAsync(string path, CancellationToken cancellationToken) { var resolved = ResolvePath(path); var entries = new List(); @@ -154,7 +154,7 @@ protected override Task> ReaddirWithTypesA return Task.FromResult>(entries); } - protected override Task RmAsync(string path, bool recursive, bool force, CancellationToken cancellationToken) + protected override Task RemoveAsync(string path, bool recursive, bool force, CancellationToken cancellationToken) { var resolved = ResolvePath(path); if (File.Exists(resolved)) diff --git a/eng/skill-validator/src/Evaluate/PairwiseJudge.cs b/eng/skill-validator/src/Evaluate/PairwiseJudge.cs index e3f9829744..cfd5b7728e 100644 --- a/eng/skill-validator/src/Evaluate/PairwiseJudge.cs +++ b/eng/skill-validator/src/Evaluate/PairwiseJudge.cs @@ -1,7 +1,7 @@ using System.Text.Json; using System.Text.Json.Nodes; using SkillValidator.Shared; -using GitHub.Copilot.SDK; +using GitHub.Copilot.Rpc; namespace SkillValidator.Evaluate; @@ -87,10 +87,7 @@ public static class PairwiseJudge { // Pairwise judge sessions: deny all tool permissions. The judge // should operate purely on the provided text — no tool execution. - return Task.FromResult(new PermissionRequestResult - { - Kind = PermissionRequestResultKind.UserNotAvailable, - }); + return Task.FromResult(PermissionDecision.UserNotAvailable()); }, cancellationToken: cancellationToken); diff --git a/eng/skill-validator/src/SkillValidator.csproj b/eng/skill-validator/src/SkillValidator.csproj index 7c40e0f10f..0e095416ee 100644 --- a/eng/skill-validator/src/SkillValidator.csproj +++ b/eng/skill-validator/src/SkillValidator.csproj @@ -9,6 +9,12 @@ $(NoWarn);IL2104 + + $(NoWarn);GHCP001 Microsoft.DotNet.SkillValidator @@ -42,34 +48,19 @@ - - - + + + - - - - - - - + diff --git a/eng/skill-validator/tests/Evaluate/RunnerTests.cs b/eng/skill-validator/tests/Evaluate/RunnerTests.cs index 610fdbee52..4d91ece2e8 100644 --- a/eng/skill-validator/tests/Evaluate/RunnerTests.cs +++ b/eng/skill-validator/tests/Evaluate/RunnerTests.cs @@ -1,6 +1,6 @@ using System.Diagnostics; using System.Text.Json; -using GitHub.Copilot.SDK; +using GitHub.Copilot; using SkillValidator.Evaluate; using SkillValidator.Shared; @@ -213,17 +213,17 @@ public async Task SetsWorkingDirectoryToWorkDir() public async Task SetsConfigDirToUniqueTempDirForSkillIsolation() { var config = await AgentRunner.BuildSessionConfig(MockSkill, null, "gpt-4.1", "C:\\tmp\\work"); - Assert.NotEqual("C:\\tmp\\work", config.ConfigDir); - Assert.StartsWith(Path.GetTempPath(), config.ConfigDir); - Assert.True(Directory.Exists(config.ConfigDir)); + Assert.NotEqual("C:\\tmp\\work", config.ConfigDirectory); + Assert.StartsWith(Path.GetTempPath(), config.ConfigDirectory); + Assert.True(Directory.Exists(config.ConfigDirectory)); } [Fact] public async Task SetsConfigDirToUniqueTempDirEvenWithoutSkill() { var config = await AgentRunner.BuildSessionConfig(null, null, "gpt-4.1", "C:\\tmp\\work"); - Assert.NotEqual("C:\\tmp\\work", config.ConfigDir); - Assert.StartsWith(Path.GetTempPath(), config.ConfigDir); + Assert.NotEqual("C:\\tmp\\work", config.ConfigDirectory); + Assert.StartsWith(Path.GetTempPath(), config.ConfigDirectory); } [Fact] @@ -231,7 +231,7 @@ public async Task EachCallGetsUniqueConfigDir() { var config1 = await AgentRunner.BuildSessionConfig(null, null, "gpt-4.1", "C:\\tmp\\work"); var config2 = await AgentRunner.BuildSessionConfig(null, null, "gpt-4.1", "C:\\tmp\\work"); - Assert.NotEqual(config1.ConfigDir, config2.ConfigDir); + Assert.NotEqual(config1.ConfigDirectory, config2.ConfigDirectory); } [Fact] @@ -356,7 +356,7 @@ public async Task DropsMcpCwd() var config = await AgentRunner.BuildSessionConfig(MockSkill, null, "gpt-4.1", "C:\\tmp\\work", mcpServers); Assert.NotNull(config.McpServers); var entry = (McpStdioServerConfig)config.McpServers["ok"]; - Assert.Null(entry.Cwd); + Assert.Null(entry.WorkingDirectory); } [Fact] @@ -451,7 +451,7 @@ public async Task PluginRootNullPreservesSkillDirectories() public class ExtractPathFromToolArgsTests { - private static PreToolUseHookInput MakeInput(object? toolArgs) => + private static PreToolUseHookInput MakeInput(JsonElement? toolArgs) => new() { ToolArgs = toolArgs }; [Fact]