탭별 설정 해석기를 도입해 Cowork/Code 분기 동작을 단일화
Some checks failed
Release Gate / gate (push) Has been cancelled

- AgentTabSettingsResolver 신규 추가: 탭 판별, post-tool 검증 활성 여부, Code 전용 비활성 도구 목록 계산

- AgentLoopService.MergeDisabledTools에서 Code 전용 도구 비활성 계산을 resolver 경로로 전환

- AgentLoopTransitions.Execution에서 post-tool verification 판단 시 resolver 결과를 사용하도록 정리

- AgentTabSettingsResolverTests 신규 추가(탭 판별/검증 플래그 분기/비활성 도구 계산)

- README.md 업데이트 시각(2026-04-04 13:32 KST) 및 변경 이력 항목 갱신

- docs/DEVELOPMENT.md 연속 실행 28차 이력 추가

- 검증: dotnet build(use shared compilation off) 경고 0/오류 0, 필터 테스트 49건 통과
This commit is contained in:
2026-04-04 13:32:45 +09:00
parent 15b675d9c4
commit d9169ed3ea
6 changed files with 140 additions and 28 deletions

View File

@@ -222,7 +222,7 @@ public class MyHandler : IActionHandler
### v0.7.3 — AX Agent 권한 코어 재구성 + 입력 계층 정리
업데이트: 2026-04-04 13:25 (KST)
업데이트: 2026-04-04 13:32 (KST)
| 분류 | 내용 |
|------|------|
@@ -278,6 +278,7 @@ public class MyHandler : IActionHandler
| slash 명령 카탈로그 분리 | `ChatWindow` 내부 대형 slash 사전을 `SlashCommandCatalog`로 분리해 입력 계층 결합도를 낮추고 유지보수 범위를 축소 |
| slash 조회 API 전환 | 내장 slash 매칭/조회 경로를 `SlashCommandCatalog.MatchBuiltinCommands`/`TryGetEntry`로 통일 |
| 권한 표시 카탈로그 분리 | 권한 모드 라벨/설명/아이콘/색을 `PermissionModePresentationCatalog`로 분리해 팝업 표면 기준을 단일화 |
| 탭별 설정 해석기 도입 | `AgentTabSettingsResolver`를 추가해 Cowork/Code 분기(검증 활성/Code 전용 도구 비활성)를 단일 경로로 정리 |
| Slash palette 상태 분리 시작 | `ChatWindow`에 몰려 있던 slash 상태를 `SlashPaletteState`로 분리해 이후 Codex/Claude형 composer 개편 기반 마련 |
| 런처 이미지 미리보기 추가 | `#` 클립보드 이미지 항목에서 `Shift+Enter`로 전용 미리보기 창을 열고, 줌·원본 해상도 확인·PNG/JPEG/BMP 저장·클립보드 복사를 지원 |
| 검증 | `dotnet build` 경고 0 / 오류 0, `dotnet test` 436 passed / 0 failed |

View File

@@ -3343,3 +3343,27 @@ else:
### 3) 품질 게이트
- dotnet build src/AxCopilot/AxCopilot.csproj 통과 (경고 0, 오류 0).
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj --no-build --filter "FullyQualifiedName~ChatWindowSlashPolicyTests|FullyQualifiedName~OperationModeReadinessTests" 통과 (43 passed, 0 failed).
## 2026-04-04 추가 진행 기록 (연속 실행 28차: 탭별 설정 해석기 도입)
업데이트: 2026-04-04 13:32 (KST)
### 1) 탭별 설정 해석 단일화
- 신규 파일 AgentTabSettingsResolver 추가.
- ActiveTab 기준 공통 분기 제공:
- IsCodeTab, IsCoworkTab
- IsPostToolVerificationEnabled(activeTab, llm)
- EnumerateCodeTabDisabledTools(codeSettings)
### 2) Agent loop 연동
- AgentLoopService.MergeDisabledTools()에서 Code 탭 전용 도구 비활성 목록을 resolver로 계산하도록 전환.
- AgentLoopTransitions.Execution의 post-tool verification 판단에서 resolver 결과를 사용하도록 정리.
### 3) 테스트 보강
- AgentTabSettingsResolverTests 신규 추가:
- 탭 판별
- Cowork/Code 검증 플래그 분기
- Code 전용 비활성 도구 목록 계산
### 4) 품질 게이트
- dotnet build src/AxCopilot/AxCopilot.csproj -p:UseSharedCompilation=false -nodeReuse:false 통과 (경고 0, 오류 0).
- dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj --filter "FullyQualifiedName~AgentTabSettingsResolverTests|FullyQualifiedName~ChatWindowSlashPolicyTests|FullyQualifiedName~OperationModeReadinessTests" 통과 (49 passed, 0 failed).

View File

@@ -0,0 +1,56 @@
using AxCopilot.Models;
using AxCopilot.Services.Agent;
using FluentAssertions;
using Xunit;
namespace AxCopilot.Tests.Services;
public class AgentTabSettingsResolverTests
{
[Theory]
[InlineData("Code", true, false)]
[InlineData("Cowork", false, true)]
[InlineData("Chat", false, false)]
[InlineData(null, false, false)]
public void TabDetection_ShouldMatchExpected(string? tab, bool isCode, bool isCowork)
{
AgentTabSettingsResolver.IsCodeTab(tab).Should().Be(isCode);
AgentTabSettingsResolver.IsCoworkTab(tab).Should().Be(isCowork);
}
[Fact]
public void IsPostToolVerificationEnabled_ShouldUseTabSpecificFlags()
{
var llm = new LlmSettings
{
EnableCoworkVerification = true,
Code = new CodeSettings
{
EnableCodeVerification = false,
}
};
AgentTabSettingsResolver.IsPostToolVerificationEnabled("Cowork", llm).Should().BeTrue();
AgentTabSettingsResolver.IsPostToolVerificationEnabled("Code", llm).Should().BeFalse();
AgentTabSettingsResolver.IsPostToolVerificationEnabled("Chat", llm).Should().BeFalse();
}
[Fact]
public void EnumerateCodeTabDisabledTools_ShouldReflectCodeSettings()
{
var code = new CodeSettings
{
EnablePlanModeTools = false,
EnableWorktreeTools = true,
EnableTeamTools = false,
EnableCronTools = false,
};
var disabled = AgentTabSettingsResolver.EnumerateCodeTabDisabledTools(code).ToList();
disabled.Should().Contain(["enter_plan_mode", "exit_plan_mode"]);
disabled.Should().Contain(["team_create", "team_delete"]);
disabled.Should().Contain(["cron_create", "cron_delete", "cron_list"]);
disabled.Should().NotContain(["enter_worktree", "exit_worktree"]);
}
}

View File

@@ -1589,33 +1589,13 @@ public partial class AgentLoopService
}
}
if (!string.Equals(ActiveTab, "Code", StringComparison.OrdinalIgnoreCase))
if (!AgentTabSettingsResolver.IsCodeTab(ActiveTab))
return disabled;
var code = _settings.Settings.Llm.Code;
if (!code.EnablePlanModeTools)
foreach (var toolName in AgentTabSettingsResolver.EnumerateCodeTabDisabledTools(code))
{
disabled.Add("enter_plan_mode");
disabled.Add("exit_plan_mode");
}
if (!code.EnableWorktreeTools)
{
disabled.Add("enter_worktree");
disabled.Add("exit_worktree");
}
if (!code.EnableTeamTools)
{
disabled.Add("team_create");
disabled.Add("team_delete");
}
if (!code.EnableCronTools)
{
disabled.Add("cron_create");
disabled.Add("cron_delete");
disabled.Add("cron_list");
disabled.Add(toolName);
}
return disabled;

View File

@@ -1399,12 +1399,13 @@ public partial class AgentLoopService
if (!result.Success || !IsTerminalDocumentTool(call.ToolName) || toolCalls.Count != 1)
return (false, false);
var verificationEnabled = AgentTabSettingsResolver.IsPostToolVerificationEnabled(ActiveTab, llm);
var shouldVerify = ShouldRunPostToolVerification(
ActiveTab,
call.ToolName,
result.Success,
llm.Code.EnableCodeVerification,
llm.EnableCoworkVerification);
verificationEnabled,
verificationEnabled);
var consumedExtraIteration = false;
if (shouldVerify)
{
@@ -1427,12 +1428,13 @@ public partial class AgentLoopService
if (!result.Success)
return false;
var verificationEnabled = AgentTabSettingsResolver.IsPostToolVerificationEnabled(ActiveTab, llm);
var shouldVerify = ShouldRunPostToolVerification(
ActiveTab,
call.ToolName,
result.Success,
llm.Code.EnableCodeVerification,
llm.EnableCoworkVerification);
verificationEnabled,
verificationEnabled);
if (!shouldVerify)
return false;

View File

@@ -0,0 +1,49 @@
using AxCopilot.Models;
namespace AxCopilot.Services.Agent;
internal static class AgentTabSettingsResolver
{
public static bool IsCodeTab(string? activeTab)
=> string.Equals(activeTab, "Code", StringComparison.OrdinalIgnoreCase);
public static bool IsCoworkTab(string? activeTab)
=> string.Equals(activeTab, "Cowork", StringComparison.OrdinalIgnoreCase);
public static bool IsPostToolVerificationEnabled(string? activeTab, LlmSettings llm)
{
if (IsCodeTab(activeTab))
return llm.Code.EnableCodeVerification;
if (IsCoworkTab(activeTab))
return llm.EnableCoworkVerification;
return false;
}
public static IEnumerable<string> EnumerateCodeTabDisabledTools(CodeSettings code)
{
if (!code.EnablePlanModeTools)
{
yield return "enter_plan_mode";
yield return "exit_plan_mode";
}
if (!code.EnableWorktreeTools)
{
yield return "enter_worktree";
yield return "exit_worktree";
}
if (!code.EnableTeamTools)
{
yield return "team_create";
yield return "team_delete";
}
if (!code.EnableCronTools)
{
yield return "cron_create";
yield return "cron_delete";
yield return "cron_list";
}
}
}