Files
tutti/services/tuttid/api/daemon_app_mentions_test.go
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

232 lines
8.5 KiB
Go

package api
import (
"context"
"net/http"
"testing"
tuttigenerated "github.com/tutti-os/tutti/services/tuttid/api/generated"
workspacebiz "github.com/tutti-os/tutti/services/tuttid/biz/workspace"
cliservice "github.com/tutti-os/tutti/services/tuttid/service/cli"
)
func TestDaemonAPIGeneratedRoutesListWorkspaceAppMentionCandidates(t *testing.T) {
cliProvider := &workspaceAppMentionTestCLIProvider{
capabilities: []cliservice.Capability{
workspaceAppMentionTestCapability("installed-app.open", "installed-app", "Installed CLI", "https://cli.example/installed.png", "Installed CLI description"),
workspaceAppMentionTestCapability("disabled-app.open", "disabled-app", "Disabled CLI", "", "Disabled CLI description"),
workspaceAppMentionTestCapability("agent-codex.open", "agent-codex", "Codex", "", "Codex CLI description"),
},
}
registry, err := cliservice.NewRegistryFromProviders(cliProvider)
if err != nil {
t.Fatalf("NewRegistryFromProviders() error = %v", err)
}
mux := http.NewServeMux()
var gotWorkspaceID string
RegisterRoutes(
mux,
NewRoutes(DaemonAPI{
AppCenterService: stubWorkspaceAppCenterService{
listFn: func(_ context.Context, workspaceID string) ([]workspacebiz.WorkspaceApp, error) {
gotWorkspaceID = workspaceID
return []workspacebiz.WorkspaceApp{
workspaceAppMentionTestApp("installed-app", "Installed App", "Installed App description", true, true),
workspaceAppMentionTestApp("installed-no-cli", "Installed No CLI", "Installed without CLI description", true, true),
workspaceAppMentionTestApp("disabled-app", "Disabled App", "Disabled App description", true, false),
workspaceAppMentionTestApp("uninstalled-app", "Uninstalled App", "Uninstalled App description", false, false),
}, nil
},
},
CLIRegistry: registry,
}),
)
recorder := performGeneratedRouteRequest(
t,
mux,
http.MethodGet,
"/v1/workspaces/workspace-1/agent-context/workspace-app-mentions",
nil,
)
if recorder.Code != http.StatusOK {
t.Fatalf("expected status 200, got %d: %s", recorder.Code, recorder.Body.String())
}
if gotWorkspaceID != "workspace-1" {
t.Fatalf("workspace id = %q, want workspace-1", gotWorkspaceID)
}
if cliProvider.filterCalls != 0 {
t.Fatalf("FilterCapabilities called %d times, want 0", cliProvider.filterCalls)
}
var response tuttigenerated.WorkspaceAppMentionCandidatesResponse
decodeGeneratedRouteResponse(t, recorder, &response)
if response.WorkspaceId != "workspace-1" {
t.Fatalf("response.workspaceId = %q, want workspace-1", response.WorkspaceId)
}
if len(response.Apps) != 2 {
t.Fatalf("apps len = %d, want 2: %#v", len(response.Apps), response.Apps)
}
codex := response.Apps[0]
if codex.AppId != "agent-codex" || codex.Source != tuttigenerated.WorkspaceAppMentionCandidateSourceCliApp {
t.Fatalf("first candidate = %#v, want agent-codex cli app", codex)
}
if codex.Description != "Codex CLI description" || codex.Cli.CommandCount != 1 {
t.Fatalf("codex candidate metadata = %#v, want CLI description and one command", codex)
}
installed := response.Apps[1]
if installed.AppId != "installed-app" || installed.Source != tuttigenerated.WorkspaceAppMentionCandidateSourceWorkspaceApp {
t.Fatalf("second candidate = %#v, want installed workspace app", installed)
}
if installed.DisplayName != "Installed App" || installed.Description != "Installed App description" {
t.Fatalf("installed candidate name/description = %#v", installed)
}
if installed.Cli.CommandCount != 1 {
t.Fatalf("installed command count = %d, want 1", installed.Cli.CommandCount)
}
if len(installed.Cli.CommandPaths) != 1 || installed.Cli.CommandPaths[0] != "installed-app open" {
t.Fatalf("installed command paths = %#v, want installed-app open", installed.Cli.CommandPaths)
}
if !installed.References.ListSupported || !installed.References.SearchSupported {
t.Fatalf("installed references = %#v, want list and search support", installed.References)
}
}
func TestWorkspaceAppMentionCLIAppsExcludeIntegrationCapabilities(t *testing.T) {
appCommands := &workspaceAppMentionDynamicCommands{}
registry := &cliservice.Registry{AppCommands: appCommands}
appsByID := workspaceAppMentionCLIAppsByID(context.Background(), registry, "workspace-1")
if len(appCommands.contexts) != 1 {
t.Fatalf("contexts = %#v, want one call", appCommands.contexts)
}
contextValue := appCommands.contexts[0]
if !contextValue.SkipCapabilityFilters {
t.Fatalf("SkipCapabilityFilters = false, want true for metadata path")
}
if contextValue.IncludeIntegrationCapabilities {
t.Fatalf("IncludeIntegrationCapabilities = true, want false for mention metadata")
}
app := appsByID["automation-app"]
if app.metadata.CommandCount != 1 {
t.Fatalf("command count = %d, want only public command", app.metadata.CommandCount)
}
if len(app.metadata.CommandPaths) != 1 || app.metadata.CommandPaths[0] != "automation list" {
t.Fatalf("command paths = %#v, want only public list command", app.metadata.CommandPaths)
}
}
type workspaceAppMentionTestCLIProvider struct {
capabilities []cliservice.Capability
filterCalls int
}
func (workspaceAppMentionTestCLIProvider) AppID() string {
return "workspace-app-mention-test"
}
func (p *workspaceAppMentionTestCLIProvider) Commands() []cliservice.Command {
commands := make([]cliservice.Command, 0, len(p.capabilities))
for _, capability := range p.capabilities {
commands = append(commands, cliservice.Command{
Capability: capability,
Handler: func(context.Context, cliservice.InvokeRequest) (cliservice.CommandOutput, error) {
return cliservice.CommandOutput{}, nil
},
})
}
return commands
}
func (p *workspaceAppMentionTestCLIProvider) FilterCapabilities(context.Context, cliservice.InvokeContext, []cliservice.Capability) []cliservice.Capability {
p.filterCalls++
return nil
}
func workspaceAppMentionTestCapability(id string, appID string, appName string, iconURL string, description string) cliservice.Capability {
return cliservice.Capability{
ID: id,
Path: []string{appID, "open"},
Summary: "Open " + appName,
Description: "Search " + appName,
Source: cliservice.CapabilitySource{
Kind: cliservice.CapabilitySourceApp,
AppID: appID,
AppName: appName,
IconURL: iconURL,
CLIDescription: description,
},
}
}
func workspaceAppMentionTestApp(appID string, name string, description string, installed bool, enabled bool) workspacebiz.WorkspaceApp {
iconURL := "https://app.example/" + appID + ".png"
var installation *workspacebiz.AppInstallation
if installed {
installation = &workspacebiz.AppInstallation{
WorkspaceID: "workspace-1",
AppID: appID,
Enabled: enabled,
}
}
return workspacebiz.WorkspaceApp{
Package: workspacebiz.AppPackage{
AppID: appID,
Version: "1.0.0",
Manifest: workspacebiz.AppManifest{
AppID: appID,
Name: name,
Description: description,
References: &workspacebiz.AppManifestReferences{
ListEndpoint: "/references/list",
SearchEndpoint: "/references/search",
},
},
Source: workspacebiz.AppPackageSourceImported,
},
Installation: installation,
IconURL: &iconURL,
Runtime: workspacebiz.AppRuntimeState{Status: workspacebiz.AppRuntimeStatusIdle},
}
}
type workspaceAppMentionDynamicCommands struct {
contexts []cliservice.InvokeContext
}
func (f *workspaceAppMentionDynamicCommands) Capabilities(_ context.Context, contextValue cliservice.InvokeContext) []cliservice.Capability {
f.contexts = append(f.contexts, contextValue)
capabilities := []cliservice.Capability{
workspaceAppMentionAppCapability("app.automation-app.automation.list", "automation-app", []string{"automation", "list"}, "List automations"),
}
if contextValue.IncludeIntegrationCapabilities {
capabilities = append(capabilities,
workspaceAppMentionAppCapability("app.automation-app.automation.internal-sync", "automation-app", []string{"automation", "internal-sync"}, "Sync internal automation state"),
)
}
return capabilities
}
func (*workspaceAppMentionDynamicCommands) Invoke(context.Context, cliservice.InvokeRequest) (cliservice.CommandOutput, error) {
return cliservice.CommandOutput{}, cliservice.ErrCommandNotFound
}
func workspaceAppMentionAppCapability(id string, appID string, path []string, summary string) cliservice.Capability {
return cliservice.Capability{
ID: id,
Path: path,
Summary: summary,
Source: cliservice.CapabilitySource{
Kind: cliservice.CapabilitySourceApp,
AppID: appID,
AppName: "Automation",
},
}
}