Merge branch 'master'
This commit is contained in:
commit
0b5285aab3
10 changed files with 368 additions and 26 deletions
|
|
@ -622,7 +622,7 @@ data:
|
|||
"api_key": "picoclaw-secret-123",
|
||||
"chat_enabled": true,
|
||||
"hot_reload": true,
|
||||
"log_level": "info"
|
||||
"log_level": "debug"
|
||||
},
|
||||
"hooks": {
|
||||
"enabled": true,
|
||||
|
|
@ -669,6 +669,8 @@ data:
|
|||
"weather": true,
|
||||
"summarize": true,
|
||||
"github": true,
|
||||
"monday": true,
|
||||
"harvest": true,
|
||||
"freeride": true,
|
||||
"hdn-server": true
|
||||
}
|
||||
|
|
@ -786,6 +788,8 @@ data:
|
|||
"weather",
|
||||
"summarize",
|
||||
"github",
|
||||
"monday",
|
||||
"harvest",
|
||||
"freeride",
|
||||
"hdn-server"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -102,11 +102,13 @@ func NewAgentInstance(
|
|||
toolsRegistry.Register(tools.NewListDirTool(workspace, readRestrict, allowReadPaths))
|
||||
}
|
||||
if cfg.Tools.IsToolEnabled("exec") {
|
||||
execTool, err := tools.NewExecToolWithConfig(workspace, restrict, cfg, allowReadPaths)
|
||||
execTool, err := tools.NewExecToolWithDenyPaths(workspace, restrict, [][]*regexp.Regexp{allowReadPaths}, denyWritePaths, cfg)
|
||||
if err != nil {
|
||||
logger.ErrorCF("agent", "Failed to initialize exec tool; continuing without exec",
|
||||
map[string]any{"error": err.Error()})
|
||||
} else {
|
||||
execTool = nil
|
||||
}
|
||||
if execTool != nil {
|
||||
toolsRegistry.Register(execTool)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,11 +26,20 @@ func NewAgentLoop(
|
|||
msgBus *bus.MessageBus,
|
||||
provider providers.LLMProvider,
|
||||
) *AgentLoop {
|
||||
logger.Debug("Initializing AgentRegistry...")
|
||||
registry := NewAgentRegistry(cfg, provider)
|
||||
|
||||
// Set up shared fallback chain with rate limiting.
|
||||
cooldownPath := filepath.Join(filepath.Dir(filepath.Clean(registry.GetDefaultAgent().Workspace)), "cooldowns.json")
|
||||
// Harden: ensure we have a valid workspace for the cooldown file even if the default agent isn't ready.
|
||||
baseDir := filepath.Dir(configPath)
|
||||
if defaultAgent := registry.GetDefaultAgent(); defaultAgent != nil {
|
||||
baseDir = filepath.Dir(filepath.Clean(defaultAgent.Workspace))
|
||||
}
|
||||
|
||||
cooldownPath := filepath.Join(baseDir, "cooldowns.json")
|
||||
logger.Debugf("Initializing CooldownTracker at %s", cooldownPath)
|
||||
cooldown := providers.NewCooldownTracker(cooldownPath)
|
||||
|
||||
rl := providers.NewRateLimiterRegistry()
|
||||
// Register rate limiters for all agents' candidates so that RPM limits
|
||||
// configured in ModelConfig are enforced before each LLM call.
|
||||
|
|
@ -46,6 +55,7 @@ func NewAgentLoop(
|
|||
defaultAgent := registry.GetDefaultAgent()
|
||||
var stateManager *state.Manager
|
||||
if defaultAgent != nil {
|
||||
logger.Debugf("Initializing State Manager for agent %s", defaultAgent.ID)
|
||||
stateManager = state.NewManager(defaultAgent.Workspace)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -114,24 +114,46 @@ func (p *startupBlockedProvider) GetDefaultModel() string {
|
|||
}
|
||||
|
||||
// Run starts the gateway runtime using the configuration loaded from configPath.
|
||||
func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) (runErr error) {
|
||||
panicPath := filepath.Join(homePath, logPath, panicFile)
|
||||
panicFunc, err := logger.InitPanic(panicPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error initializing panic log: %w", err)
|
||||
}
|
||||
defer panicFunc()
|
||||
func Run(
|
||||
debug bool,
|
||||
homePath string,
|
||||
configPath string,
|
||||
allowEmptyStartup bool,
|
||||
) (runErr error) {
|
||||
fmt.Printf("📂 Home Path: %s\n", homePath)
|
||||
fmt.Printf("📄 Config Path: %s\n", configPath)
|
||||
|
||||
if err = logger.EnableFileLogging(filepath.Join(homePath, logPath, logFile)); err != nil {
|
||||
// Ensure home directory exists early
|
||||
if err := os.MkdirAll(homePath, 0o755); err != nil {
|
||||
return fmt.Errorf("failed to create home directory: %w", err)
|
||||
}
|
||||
|
||||
// Initialize panic logging
|
||||
panicPath := filepath.Join(homePath, logPath, panicFile)
|
||||
fmt.Printf("🔧 Initializing panic log: %s\n", panicPath)
|
||||
panicCleanup, err := logger.InitPanic(panicPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize panic log: %w", err)
|
||||
}
|
||||
defer panicCleanup()
|
||||
fmt.Println("✓ Panic log initialized")
|
||||
|
||||
// Enable main file logging
|
||||
mainLogPath := filepath.Join(homePath, logPath, logFile)
|
||||
fmt.Printf("🔧 Enabling file logging: %s\n", mainLogPath)
|
||||
if err = logger.EnableFileLogging(mainLogPath); err != nil {
|
||||
logger.Fatal(fmt.Sprintf("error enabling file logging: %v", err))
|
||||
}
|
||||
defer logger.DisableFileLogging()
|
||||
fmt.Println("✓ File logging enabled")
|
||||
|
||||
// Set initial log level from config if possible, otherwise default to INFO
|
||||
if debug {
|
||||
logger.SetLevel(logger.DEBUG)
|
||||
} else {
|
||||
logger.SetLevelFromString(config.ResolveGatewayLogLevel(configPath))
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if runErr != nil {
|
||||
logger.ErrorCF("gateway", "Gateway startup failed", map[string]any{
|
||||
|
|
@ -144,10 +166,12 @@ func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) (runEr
|
|||
}
|
||||
}()
|
||||
|
||||
fmt.Println("🔍 Loading configuration...")
|
||||
cfg, err := config.LoadConfig(configPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error loading config: %w", err)
|
||||
}
|
||||
logger.Info("✓ Configuration loaded")
|
||||
|
||||
if err = preCheckConfig(cfg); err != nil {
|
||||
return fmt.Errorf("config pre-check failed: %w", err)
|
||||
|
|
@ -156,6 +180,7 @@ func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) (runEr
|
|||
// Debug mode permanently overrides the config log level to DEBUG.
|
||||
if debug {
|
||||
fmt.Println("🔍 Debug mode enabled")
|
||||
logger.SetLevel(logger.DEBUG)
|
||||
} else {
|
||||
effectiveLogLevel := config.EffectiveGatewayLogLevel(cfg)
|
||||
logger.SetLevelFromString(effectiveLogLevel)
|
||||
|
|
@ -167,7 +192,7 @@ func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) (runEr
|
|||
return fmt.Errorf("error opening gateway listeners: %w", err)
|
||||
}
|
||||
|
||||
// Enforce singleton: write PID file with generated token.
|
||||
// Enforce singleton and generate auth token
|
||||
pidData, err := pid.WritePidFile(homePath, bindPlan.ProbeHost, cfg.Gateway.Port)
|
||||
if err != nil {
|
||||
logger.Warnf("write pid file failed: %v", err)
|
||||
|
|
@ -177,6 +202,8 @@ func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) (runEr
|
|||
return fmt.Errorf("singleton check failed: %w", err)
|
||||
}
|
||||
defer pid.RemovePidFile(homePath)
|
||||
|
||||
logger.Info("✓ PID file and auth token initialized")
|
||||
closeListeners := true
|
||||
defer func() {
|
||||
if !closeListeners {
|
||||
|
|
@ -187,17 +214,26 @@ func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) (runEr
|
|||
}
|
||||
}()
|
||||
|
||||
msgBus := bus.NewMessageBus()
|
||||
|
||||
provider, modelID, err := createStartupProvider(cfg, allowEmptyStartup)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating provider: %w", err)
|
||||
}
|
||||
logger.Infof("✓ LLM Provider initialized (Model: %s)", modelID)
|
||||
|
||||
if modelID != "" {
|
||||
cfg.Agents.Defaults.ModelName = modelID
|
||||
}
|
||||
|
||||
msgBus := bus.NewMessageBus()
|
||||
agentLoop := agent.NewAgentLoop(cfg, configPath, msgBus, provider)
|
||||
logger.Info("✓ Agent loop initialized")
|
||||
|
||||
runningServices, err := setupAndStartServices(cfg, agentLoop, msgBus, pidData.Token, listenResult)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error setting up services: %w", err)
|
||||
}
|
||||
logger.Info("✓ Core services started")
|
||||
|
||||
fmt.Println("\n📦 Agent Status:")
|
||||
startupInfo := agentLoop.GetStartupInfo()
|
||||
|
|
@ -212,11 +248,6 @@ func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) (runEr
|
|||
"skills_total": skillsInfo["total"],
|
||||
"skills_available": skillsInfo["available"],
|
||||
})
|
||||
|
||||
runningServices, err := setupAndStartServices(cfg, agentLoop, msgBus, pidData.Token, listenResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
closeListeners = false
|
||||
|
||||
// Setup manual reload channel for /reload endpoint
|
||||
|
|
|
|||
|
|
@ -58,6 +58,29 @@ var protocolMetaByName = map[string]protocolMeta{
|
|||
"longcat": {defaultAPIBase: "https://api.longcat.chat/openai"},
|
||||
"modelscope": {defaultAPIBase: "https://api-inference.modelscope.cn/v1"},
|
||||
"mimo": {defaultAPIBase: "https://api.xiaomimimo.com/v1"},
|
||||
|
||||
// Specialty and Custom Protocols
|
||||
"anthropic": {defaultAPIBase: "https://api.anthropic.com"},
|
||||
"google": {defaultAPIBase: "https://openrouter.ai/api/v1"}, // Alias for OpenRouter/OpenAI-compatible
|
||||
"elevenlabs": {},
|
||||
"claude-cli": {},
|
||||
"codex-cli": {},
|
||||
"antigravity": {},
|
||||
"cli": {},
|
||||
"fs": {},
|
||||
"memory": {},
|
||||
"dummy": {},
|
||||
"openai-tts": {},
|
||||
"gpt-4-v": {defaultAPIBase: "https://api.openai.com/v1"},
|
||||
"gpt-4o": {defaultAPIBase: "https://api.openai.com/v1"},
|
||||
"gpt-4-turbo": {defaultAPIBase: "https://api.openai.com/v1"},
|
||||
"azure": {},
|
||||
"azure-openai": {},
|
||||
"bedrock": {},
|
||||
"github-copilot": {},
|
||||
"github-copilot-chat": {},
|
||||
"copilot": {},
|
||||
"claude": {defaultAPIBase: "https://api.anthropic.com"},
|
||||
}
|
||||
|
||||
// createClaudeAuthProvider creates a Claude provider using OAuth credentials from auth store.
|
||||
|
|
@ -88,15 +111,15 @@ func createCodexAuthProvider() (LLMProvider, error) {
|
|||
// If no prefix is specified, it defaults to "openai".
|
||||
// Examples:
|
||||
// - "openai/gpt-4o" -> ("openai", "gpt-4o")
|
||||
// - "anthropic/claude-sonnet-4.6" -> ("anthropic", "claude-sonnet-4.6")
|
||||
// - "gpt-4o" -> ("openai", "gpt-4o") // default protocol
|
||||
// - "anthropic/claude-3-opus" -> ("anthropic", "claude-3-opus")
|
||||
// - "gpt-4o" -> ("openai", "gpt-4o")
|
||||
func ExtractProtocol(model string) (protocol, modelID string) {
|
||||
model = strings.TrimSpace(model)
|
||||
protocol, modelID, found := strings.Cut(model, "/")
|
||||
p, m, found := strings.Cut(model, "/")
|
||||
if !found {
|
||||
return "openai", model
|
||||
}
|
||||
return protocol, modelID
|
||||
return p, m
|
||||
}
|
||||
|
||||
// ResolveAPIBase returns the configured API base, or the protocol default when
|
||||
|
|
@ -133,7 +156,13 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
|
|||
protocol, modelID := ExtractProtocol(cfg.Model)
|
||||
if cfg.Protocol != "" {
|
||||
protocol = cfg.Protocol
|
||||
modelID = cfg.Model
|
||||
// If protocol was explicitly set, modelID should be the full model string
|
||||
// unless it was already prefixed with the SAME protocol.
|
||||
if p, m, found := strings.Cut(cfg.Model, "/"); found && strings.EqualFold(p, protocol) {
|
||||
modelID = m
|
||||
} else {
|
||||
modelID = cfg.Model
|
||||
}
|
||||
}
|
||||
|
||||
userAgent := cfg.UserAgent
|
||||
|
|
|
|||
|
|
@ -74,6 +74,10 @@ func (p *HTTPProvider) GetDefaultModel() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (p *HTTPProvider) SupportsThinking() bool {
|
||||
return p.delegate.SupportsThinking()
|
||||
}
|
||||
|
||||
func (p *HTTPProvider) SupportsNativeSearch() bool {
|
||||
return p.delegate.SupportsNativeSearch()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,6 +180,32 @@ func (p *Provider) buildRequestBody(
|
|||
}
|
||||
}
|
||||
|
||||
// Thinking support for OpenRouter
|
||||
if level, ok := options["thinking_level"].(string); ok && level != "" && level != "off" {
|
||||
if u, err := url.Parse(p.apiBase); err == nil && u.Hostname() == "openrouter.ai" {
|
||||
// Map level to budget tokens (using same scale as Anthropic)
|
||||
budget := 0
|
||||
switch level {
|
||||
case "low":
|
||||
budget = 4096
|
||||
case "medium":
|
||||
budget = 16384
|
||||
case "high":
|
||||
budget = 32000
|
||||
case "xhigh":
|
||||
budget = 64000
|
||||
}
|
||||
if budget > 0 {
|
||||
requestBody["thinking"] = map[string]any{
|
||||
"type": "enabled",
|
||||
"budget_tokens": budget,
|
||||
}
|
||||
// Remove temperature when thinking is enabled (strict requirement for some models)
|
||||
delete(requestBody, "temperature")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Merge extra body fields configured per-provider/model.
|
||||
// These are injected last so they take precedence over defaults.
|
||||
maps.Copy(requestBody, p.extraBody)
|
||||
|
|
@ -466,6 +492,16 @@ func buildToolsList(tools []ToolDefinition, nativeSearch bool) []any {
|
|||
return result
|
||||
}
|
||||
|
||||
func (p *Provider) SupportsThinking() bool {
|
||||
// Enable thinking support for OpenRouter.
|
||||
// OpenRouter acts as a passthrough for Anthropic and DeepSeek-R1 models that support thinking.
|
||||
u, err := url.Parse(p.apiBase)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return u.Hostname() == "openrouter.ai"
|
||||
}
|
||||
|
||||
func (p *Provider) SupportsNativeSearch() bool {
|
||||
return isNativeSearchHost(p.apiBase)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ type ExecTool struct {
|
|||
allowPatterns []*regexp.Regexp
|
||||
customAllowPatterns []*regexp.Regexp
|
||||
allowedPathPatterns []*regexp.Regexp
|
||||
denyWritePaths []*regexp.Regexp
|
||||
restrictToWorkspace bool
|
||||
allowRemote bool
|
||||
sessionManager *SessionManager
|
||||
|
|
@ -115,7 +116,7 @@ var (
|
|||
)
|
||||
|
||||
func NewExecTool(workingDir string, restrict bool, allowPaths ...[]*regexp.Regexp) (*ExecTool, error) {
|
||||
return NewExecToolWithConfig(workingDir, restrict, nil, allowPaths...)
|
||||
return NewExecToolWithDenyPaths(workingDir, restrict, allowPaths, nil, nil)
|
||||
}
|
||||
|
||||
func NewExecToolWithConfig(
|
||||
|
|
@ -123,6 +124,16 @@ func NewExecToolWithConfig(
|
|||
restrict bool,
|
||||
cfg *config.Config,
|
||||
allowPaths ...[]*regexp.Regexp,
|
||||
) (*ExecTool, error) {
|
||||
return NewExecToolWithDenyPaths(workingDir, restrict, allowPaths, nil, cfg)
|
||||
}
|
||||
|
||||
func NewExecToolWithDenyPaths(
|
||||
workingDir string,
|
||||
restrict bool,
|
||||
allowPaths [][]*regexp.Regexp,
|
||||
denyWritePaths []*regexp.Regexp,
|
||||
cfg *config.Config,
|
||||
) (*ExecTool, error) {
|
||||
denyPatterns := make([]*regexp.Regexp, 0)
|
||||
customAllowPatterns := make([]*regexp.Regexp, 0)
|
||||
|
|
@ -149,7 +160,6 @@ func NewExecToolWithConfig(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
// If deny patterns are disabled, we won't add any patterns, allowing all commands.
|
||||
fmt.Println("Warning: deny patterns are disabled. All commands will be allowed.")
|
||||
}
|
||||
for _, pattern := range execConfig.CustomAllowPatterns {
|
||||
|
|
@ -175,6 +185,7 @@ func NewExecToolWithConfig(
|
|||
allowPatterns: nil,
|
||||
customAllowPatterns: customAllowPatterns,
|
||||
allowedPathPatterns: allowedPathPatterns,
|
||||
denyWritePaths: denyWritePaths,
|
||||
restrictToWorkspace: restrict,
|
||||
allowRemote: allowRemote,
|
||||
sessionManager: getSessionManager(),
|
||||
|
|
@ -1038,6 +1049,45 @@ func (t *ExecTool) guardCommand(command, cwd string) string {
|
|||
return "Command blocked by safety guard (dangerous pattern detected)"
|
||||
}
|
||||
}
|
||||
|
||||
// Check deny write paths - block commands that write to protected directories
|
||||
if len(t.denyWritePaths) > 0 {
|
||||
words := strings.Fields(cmd)
|
||||
for i, word := range words {
|
||||
// Skip flags but check their argument (next word)
|
||||
if word == "-p" || word == "-rf" || word == "-r" || word == "-f" || word == "-d" {
|
||||
// Check the next word as the actual path
|
||||
if i+1 < len(words) {
|
||||
nextWord := words[i+1]
|
||||
for _, pattern := range t.denyWritePaths {
|
||||
if pattern.MatchString(nextWord) {
|
||||
return fmt.Sprintf("Command blocked: cannot write to %s (access denied)", nextWord)
|
||||
}
|
||||
// Also check path components
|
||||
pathParts := strings.Split(nextWord, "/")
|
||||
for _, part := range pathParts {
|
||||
if pattern.MatchString(part) {
|
||||
return fmt.Sprintf("Command blocked: cannot write to %s (access denied)", part)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
for _, pattern := range t.denyWritePaths {
|
||||
if pattern.MatchString(word) {
|
||||
return fmt.Sprintf("Command blocked: cannot write to %s (access denied)", word)
|
||||
}
|
||||
// Also check path components like "skills" in "mkdir -p skills/my_skill"
|
||||
pathParts := strings.Split(word, "/")
|
||||
for _, part := range pathParts {
|
||||
if pattern.MatchString(part) {
|
||||
return fmt.Sprintf("Command blocked: cannot write to %s (access denied)", part)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(t.allowPatterns) > 0 {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
|
|
@ -1613,3 +1614,54 @@ func TestEncodeKeyTokenWithPtyKeyMode(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestShellTool_DenyWritePaths(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
command string
|
||||
denyPaths []*regexp.Regexp
|
||||
expectBlock bool
|
||||
}{
|
||||
{
|
||||
name: "mkdir blocked",
|
||||
command: "mkdir -p skills",
|
||||
denyPaths: []*regexp.Regexp{regexp.MustCompile(`^skills(/.*)?$`)},
|
||||
expectBlock: true,
|
||||
},
|
||||
{
|
||||
name: "mkdir -p blocked",
|
||||
command: "mkdir -p skills/my_skill",
|
||||
denyPaths: []*regexp.Regexp{regexp.MustCompile(`^skills(/.*)?$`)},
|
||||
expectBlock: true,
|
||||
},
|
||||
{
|
||||
name: "mkdir allowed",
|
||||
command: "mkdir -p workspace/data",
|
||||
denyPaths: []*regexp.Regexp{regexp.MustCompile(`^skills(/.*)?$`)},
|
||||
expectBlock: false,
|
||||
},
|
||||
{
|
||||
name: "touch skills file blocked",
|
||||
command: "touch skills/test.txt",
|
||||
denyPaths: []*regexp.Regexp{regexp.MustCompile(`^skills(/.*)?$`)},
|
||||
expectBlock: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tool, err := NewExecToolWithDenyPaths("", false, nil, tt.denyPaths, nil)
|
||||
require.NoError(t, err)
|
||||
result := tool.Execute(context.Background(), map[string]any{
|
||||
"action": "run",
|
||||
"command": tt.command,
|
||||
})
|
||||
if tt.expectBlock {
|
||||
require.True(t, result.IsError, "expected block for command: %s", tt.command)
|
||||
require.Contains(t, result.ForLLM, "access denied")
|
||||
} else {
|
||||
require.False(t, result.IsError, "expected allow for command: %s, got: %s", tt.command, result.ForLLM)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
124
test_results.txt
Normal file
124
test_results.txt
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
# v3.466
|
||||
no required module provides package v3.466; to add it:
|
||||
go get v3.466
|
||||
FAIL v3.466 [setup failed]
|
||||
# Balancing
|
||||
package Balancing is not in std (/usr/local/go/src/Balancing)
|
||||
FAIL Balancing [setup failed]
|
||||
# Makefile
|
||||
package Makefile is not in std (/usr/local/go/src/Makefile)
|
||||
FAIL Makefile [setup failed]
|
||||
# across
|
||||
package across is not in std (/usr/local/go/src/across)
|
||||
FAIL across [setup failed]
|
||||
# components.
|
||||
malformed import path "components.": trailing dot in path element
|
||||
FAIL components. [setup failed]
|
||||
? github.com/sipeed/picoclaw/cmd/freeride-diag [no test files]
|
||||
ok github.com/sipeed/picoclaw/cmd/membench (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/agent (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/auth (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/cliui (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/cron (cached)
|
||||
? github.com/sipeed/picoclaw/cmd/picoclaw/internal/freeride [no test files]
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/gateway (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/migrate (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/model (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/onboard (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/skills (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/status (cached)
|
||||
ok github.com/sipeed/picoclaw/cmd/picoclaw/internal/version (cached)
|
||||
? github.com/sipeed/picoclaw/cmd/picoclaw-launcher-tui [no test files]
|
||||
? github.com/sipeed/picoclaw/cmd/picoclaw-launcher-tui/config [no test files]
|
||||
? github.com/sipeed/picoclaw/cmd/picoclaw-launcher-tui/ui [no test files]
|
||||
? github.com/sipeed/picoclaw/examples/pico-echo-server [no test files]
|
||||
? github.com/sipeed/picoclaw/pkg [no test files]
|
||||
ok github.com/sipeed/picoclaw/pkg/agent (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/audio (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/audio/asr (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/audio/tts (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/auth (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/bus (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/dingtalk (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/discord (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/feishu (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/irc (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/line (cached)
|
||||
? github.com/sipeed/picoclaw/pkg/channels/maixcam [no test files]
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/matrix (cached)
|
||||
? github.com/sipeed/picoclaw/pkg/channels/onebot [no test files]
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/pico (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/qq (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/slack (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/teams_webhook (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/telegram (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/vk (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/wecom (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/weixin (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/channels/whatsapp (cached)
|
||||
? github.com/sipeed/picoclaw/pkg/channels/whatsapp_native [no test files]
|
||||
ok github.com/sipeed/picoclaw/pkg/commands (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/config (cached)
|
||||
? github.com/sipeed/picoclaw/pkg/constants [no test files]
|
||||
ok github.com/sipeed/picoclaw/pkg/credential (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/cron (cached)
|
||||
? github.com/sipeed/picoclaw/pkg/devices [no test files]
|
||||
? github.com/sipeed/picoclaw/pkg/devices/events [no test files]
|
||||
? github.com/sipeed/picoclaw/pkg/devices/sources [no test files]
|
||||
ok github.com/sipeed/picoclaw/pkg/fileutil (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/gateway (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/health (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/heartbeat (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/identity (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/isolation (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/logger (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/mcp (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/media (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/memory (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/migrate (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/migrate/internal (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/migrate/sources/openclaw (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/netbind (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/pid (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers/anthropic (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers/anthropic_messages (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers/azure (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers/bedrock (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers/cli (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers/common (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers/httpapi (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers/oauth (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers/openai_compat (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/providers/openai_responses_common (cached)
|
||||
? github.com/sipeed/picoclaw/pkg/providers/protocoltypes [no test files]
|
||||
ok github.com/sipeed/picoclaw/pkg/routing (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/seahorse (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/security (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/security/behavior (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/security/canary (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/security/ipia (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/security/pii (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/security/policy (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/session (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/skills (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/state (cached)
|
||||
? github.com/sipeed/picoclaw/pkg/tokenizer [no test files]
|
||||
ok github.com/sipeed/picoclaw/pkg/tools (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/tools/fs (cached)
|
||||
? github.com/sipeed/picoclaw/pkg/tools/hardware [no test files]
|
||||
ok github.com/sipeed/picoclaw/pkg/tools/integration (cached)
|
||||
? github.com/sipeed/picoclaw/pkg/tools/shared [no test files]
|
||||
ok github.com/sipeed/picoclaw/pkg/updater (cached)
|
||||
ok github.com/sipeed/picoclaw/pkg/utils (cached)
|
||||
ok github.com/sipeed/picoclaw/web/backend (cached)
|
||||
ok github.com/sipeed/picoclaw/web/backend/api (cached)
|
||||
? github.com/sipeed/picoclaw/web/backend/dashboardauth [no test files]
|
||||
ok github.com/sipeed/picoclaw/web/backend/launcherconfig (cached)
|
||||
ok github.com/sipeed/picoclaw/web/backend/middleware (cached)
|
||||
? github.com/sipeed/picoclaw/web/backend/model [no test files]
|
||||
ok github.com/sipeed/picoclaw/web/backend/utils (cached)
|
||||
FAIL
|
||||
Loading…
Add table
Reference in a new issue