Files
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

223 lines
6.8 KiB
Go

package runtimeprep
import (
"context"
"strings"
"testing"
)
type countingCommandCatalog struct {
calls int
capabilities []CommandCapability
}
func (catalog *countingCommandCatalog) Capabilities(_ context.Context, _ CommandContext) []CommandCapability {
catalog.calls++
return append([]CommandCapability(nil), catalog.capabilities...)
}
func TestRenderSkillBundleUsesOneHostCommandSnapshot(t *testing.T) {
capabilities := testCommandCapabilities()
filtered := make([]CommandCapability, 0, len(capabilities))
for _, capability := range capabilities {
if capability.ID == "issue-manager.issue.task.create-batch" ||
strings.HasPrefix(capability.ID, "computer.") {
continue
}
if strings.HasPrefix(capability.ID, "browser.") {
capability.Visibility = "integration"
}
filtered = append(filtered, capability)
}
catalog := &countingCommandCatalog{capabilities: filtered}
preparer := NewDefaultPreparer(t.TempDir())
preparer.CommandCatalog = catalog
preparer.CLICommand = "tutti-dev"
bundle, err := preparer.RenderSkillBundle(t.Context(), PrepareInput{
WorkspaceID: "workspace-1",
AgentSessionID: "session-1",
AgentTargetID: "local:codex",
Provider: "codex",
BrowserUse: true,
ComputerUse: true,
})
if err != nil {
t.Fatal(err)
}
if catalog.calls != 1 {
t.Fatalf("catalog calls = %d, want 1", catalog.calls)
}
issue := bundleSkillContent(t, bundle, "tutti/issue-manager")
if !strings.Contains(issue, "Host has no usable batch-create capability") ||
!strings.Contains(issue, "tutti-dev issue task create") {
t.Fatalf("issue skill did not select the advertised single-create flow: %s", issue)
}
for _, forbidden := range []string{
"issue task create-batch",
"--room-id",
} {
if strings.Contains(issue, forbidden) {
t.Fatalf("issue skill leaked unsupported syntax %q: %s", forbidden, issue)
}
}
for _, id := range []string{"tutti/browser-use", "tutti/computer-use"} {
if bundleHasSkill(bundle, id) {
t.Fatalf("bundle materialized unavailable skill %q", id)
}
}
guide := bundleSkillFileContent(t, bundle, "tutti/tutti-cli", commandGuideReferencePath)
if strings.Contains(guide, "browser navigate") ||
strings.Contains(guide, "computer screenshot") ||
strings.Contains(guide, "--room-id") {
t.Fatalf("guide leaked commands outside the agent-facing snapshot: %s", guide)
}
if !strings.Contains(guide, "tutti-dev issue update --issue-id <issue-id> --json") {
t.Fatalf("guide missing advertised command: %s", guide)
}
}
func TestRenderSkillBundleOmitsTaskCenterSkillAndPromptWithoutIssueFamily(t *testing.T) {
capabilities := testCommandCapabilities()
filtered := make([]CommandCapability, 0, len(capabilities))
for _, capability := range capabilities {
if strings.HasPrefix(capability.ID, "issue-manager.") {
continue
}
filtered = append(filtered, capability)
}
preparer := NewDefaultPreparer(t.TempDir())
preparer.CommandCatalog = &countingCommandCatalog{capabilities: filtered}
preparer.CLICommand = "tutti-dev"
bundle, err := preparer.RenderSkillBundle(t.Context(), PrepareInput{
WorkspaceID: "workspace-1",
AgentSessionID: "session-1",
AgentTargetID: "local:codex",
Provider: "codex",
})
if err != nil {
t.Fatal(err)
}
if bundleHasSkill(bundle, "tutti/issue-manager") {
t.Fatal("task-center skill was materialized without an issue command family")
}
contents := make([]string, 0, len(bundle.Skills)+1)
for _, skill := range bundle.Skills {
contents = append(contents, skill.Content)
for _, file := range skill.Files {
contents = append(contents, file.Content)
}
}
if bundle.RecommendedSystemPrompt != nil {
contents = append(contents, bundle.RecommendedSystemPrompt.Content)
}
for _, content := range contents {
for _, forbidden := range []string{"issue-manager", "workspace-issue", "Issue Manager", "Task Manager", "issue task"} {
if strings.Contains(content, forbidden) {
t.Fatalf("task-center prompt leaked %q without an issue command family: %s", forbidden, content)
}
}
}
}
func TestRenderSkillBundleOmitsConnectorPolicyWhenCLICommandIsNotRegistered(t *testing.T) {
capabilities := testCommandCapabilities()
filtered := make([]CommandCapability, 0, len(capabilities))
for _, capability := range capabilities {
if capability.ID != "connector.available" {
filtered = append(filtered, capability)
}
}
preparer := NewDefaultPreparer(t.TempDir())
preparer.CommandCatalog = staticCommandCatalog(filtered)
preparer.CLICommand = "tutti-dev"
bundle, err := preparer.RenderSkillBundle(t.Context(), PrepareInput{
WorkspaceID: "workspace-1",
AgentSessionID: "session-1",
AgentTargetID: "local:codex",
Provider: "codex",
})
if err != nil {
t.Fatal(err)
}
if bundle.RecommendedSystemPrompt == nil {
t.Fatal("missing recommended system prompt")
}
for _, forbidden := range []string{
"connector available",
"injected `connector` MCP server",
"connector-specific command",
} {
if strings.Contains(bundle.RecommendedSystemPrompt.Content, forbidden) {
t.Fatalf("recommended system prompt leaked disabled connector policy %q: %s", forbidden, bundle.RecommendedSystemPrompt.Content)
}
}
guide := bundleSkillFileContent(t, bundle, "tutti/tutti-cli", commandGuideReferencePath)
if strings.Contains(guide, "connector available") {
t.Fatalf("command guide leaked disabled connector CLI: %s", guide)
}
}
func TestRuntimeTemplateFailsOnUnknownCommandOrInput(t *testing.T) {
resolver, err := newCommandResolver("tutti", []CommandCapability{{
ID: "known",
Path: []string{"known"},
InputSchema: map[string]any{"properties": map[string]any{"value": map[string]any{"type": "string"}}},
}})
if err != nil {
t.Fatal(err)
}
input := PrepareInput{commandCapabilities: resolver}
for name, template := range map[string]string{
"unknown command": `{{command "missing"}}`,
"unknown input": `{{command "known" (args "missing" "value")}}`,
} {
t.Run(name, func(t *testing.T) {
if _, err := renderRuntimeTemplate(name, template, input, nil); err == nil {
t.Fatal("renderRuntimeTemplate() error = nil")
}
})
}
}
func bundleSkillContent(t *testing.T, bundle SkillBundle, id string) string {
t.Helper()
for _, skill := range bundle.Skills {
if skill.SkillID == id {
return skill.Content
}
}
t.Fatalf("skill %q not found", id)
return ""
}
func bundleSkillFileContent(t *testing.T, bundle SkillBundle, id string, path string) string {
t.Helper()
for _, skill := range bundle.Skills {
if skill.SkillID != id {
continue
}
for _, file := range skill.Files {
if file.Path == path {
return file.Content
}
}
}
t.Fatalf("skill file %q/%q not found", id, path)
return ""
}
func bundleHasSkill(bundle SkillBundle, id string) bool {
for _, skill := range bundle.Skills {
if skill.SkillID == id {
return true
}
}
return false
}