fix(providers): resolve protocol parsing crash and restore thinking support
This commit is contained in:
parent
e39f85b37b
commit
71a1a2b2c4
7 changed files with 256 additions and 22 deletions
|
|
@ -622,7 +622,7 @@ data:
|
||||||
"api_key": "picoclaw-secret-123",
|
"api_key": "picoclaw-secret-123",
|
||||||
"chat_enabled": true,
|
"chat_enabled": true,
|
||||||
"hot_reload": true,
|
"hot_reload": true,
|
||||||
"log_level": "info"
|
"log_level": "debug"
|
||||||
},
|
},
|
||||||
"hooks": {
|
"hooks": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,20 @@ func NewAgentLoop(
|
||||||
msgBus *bus.MessageBus,
|
msgBus *bus.MessageBus,
|
||||||
provider providers.LLMProvider,
|
provider providers.LLMProvider,
|
||||||
) *AgentLoop {
|
) *AgentLoop {
|
||||||
|
logger.Debug("Initializing AgentRegistry...")
|
||||||
registry := NewAgentRegistry(cfg, provider)
|
registry := NewAgentRegistry(cfg, provider)
|
||||||
|
|
||||||
// Set up shared fallback chain with rate limiting.
|
// 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)
|
cooldown := providers.NewCooldownTracker(cooldownPath)
|
||||||
|
|
||||||
rl := providers.NewRateLimiterRegistry()
|
rl := providers.NewRateLimiterRegistry()
|
||||||
// Register rate limiters for all agents' candidates so that RPM limits
|
// Register rate limiters for all agents' candidates so that RPM limits
|
||||||
// configured in ModelConfig are enforced before each LLM call.
|
// configured in ModelConfig are enforced before each LLM call.
|
||||||
|
|
@ -46,6 +55,7 @@ func NewAgentLoop(
|
||||||
defaultAgent := registry.GetDefaultAgent()
|
defaultAgent := registry.GetDefaultAgent()
|
||||||
var stateManager *state.Manager
|
var stateManager *state.Manager
|
||||||
if defaultAgent != nil {
|
if defaultAgent != nil {
|
||||||
|
logger.Debugf("Initializing State Manager for agent %s", defaultAgent.ID)
|
||||||
stateManager = state.NewManager(defaultAgent.Workspace)
|
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.
|
// Run starts the gateway runtime using the configuration loaded from configPath.
|
||||||
func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) (runErr error) {
|
func Run(
|
||||||
panicPath := filepath.Join(homePath, logPath, panicFile)
|
debug bool,
|
||||||
panicFunc, err := logger.InitPanic(panicPath)
|
homePath string,
|
||||||
if err != nil {
|
configPath string,
|
||||||
return fmt.Errorf("error initializing panic log: %w", err)
|
allowEmptyStartup bool,
|
||||||
}
|
) (runErr error) {
|
||||||
defer panicFunc()
|
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))
|
logger.Fatal(fmt.Sprintf("error enabling file logging: %v", err))
|
||||||
}
|
}
|
||||||
defer logger.DisableFileLogging()
|
defer logger.DisableFileLogging()
|
||||||
|
fmt.Println("✓ File logging enabled")
|
||||||
|
|
||||||
|
// Set initial log level from config if possible, otherwise default to INFO
|
||||||
if debug {
|
if debug {
|
||||||
logger.SetLevel(logger.DEBUG)
|
logger.SetLevel(logger.DEBUG)
|
||||||
} else {
|
} else {
|
||||||
logger.SetLevelFromString(config.ResolveGatewayLogLevel(configPath))
|
logger.SetLevelFromString(config.ResolveGatewayLogLevel(configPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
logger.ErrorCF("gateway", "Gateway startup failed", map[string]any{
|
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)
|
cfg, err := config.LoadConfig(configPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error loading config: %w", err)
|
return fmt.Errorf("error loading config: %w", err)
|
||||||
}
|
}
|
||||||
|
logger.Info("✓ Configuration loaded")
|
||||||
|
|
||||||
if err = preCheckConfig(cfg); err != nil {
|
if err = preCheckConfig(cfg); err != nil {
|
||||||
return fmt.Errorf("config pre-check failed: %w", err)
|
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.
|
// Debug mode permanently overrides the config log level to DEBUG.
|
||||||
if debug {
|
if debug {
|
||||||
fmt.Println("🔍 Debug mode enabled")
|
fmt.Println("🔍 Debug mode enabled")
|
||||||
|
logger.SetLevel(logger.DEBUG)
|
||||||
} else {
|
} else {
|
||||||
effectiveLogLevel := config.EffectiveGatewayLogLevel(cfg)
|
effectiveLogLevel := config.EffectiveGatewayLogLevel(cfg)
|
||||||
logger.SetLevelFromString(effectiveLogLevel)
|
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)
|
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)
|
pidData, err := pid.WritePidFile(homePath, bindPlan.ProbeHost, cfg.Gateway.Port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Warnf("write pid file failed: %v", err)
|
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)
|
return fmt.Errorf("singleton check failed: %w", err)
|
||||||
}
|
}
|
||||||
defer pid.RemovePidFile(homePath)
|
defer pid.RemovePidFile(homePath)
|
||||||
|
|
||||||
|
logger.Info("✓ PID file and auth token initialized")
|
||||||
closeListeners := true
|
closeListeners := true
|
||||||
defer func() {
|
defer func() {
|
||||||
if !closeListeners {
|
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)
|
provider, modelID, err := createStartupProvider(cfg, allowEmptyStartup)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error creating provider: %w", err)
|
return fmt.Errorf("error creating provider: %w", err)
|
||||||
}
|
}
|
||||||
|
logger.Infof("✓ LLM Provider initialized (Model: %s)", modelID)
|
||||||
|
|
||||||
if modelID != "" {
|
if modelID != "" {
|
||||||
cfg.Agents.Defaults.ModelName = modelID
|
cfg.Agents.Defaults.ModelName = modelID
|
||||||
}
|
}
|
||||||
|
|
||||||
msgBus := bus.NewMessageBus()
|
|
||||||
agentLoop := agent.NewAgentLoop(cfg, configPath, msgBus, provider)
|
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:")
|
fmt.Println("\n📦 Agent Status:")
|
||||||
startupInfo := agentLoop.GetStartupInfo()
|
startupInfo := agentLoop.GetStartupInfo()
|
||||||
|
|
@ -212,11 +248,6 @@ func Run(debug bool, homePath, configPath string, allowEmptyStartup bool) (runEr
|
||||||
"skills_total": skillsInfo["total"],
|
"skills_total": skillsInfo["total"],
|
||||||
"skills_available": skillsInfo["available"],
|
"skills_available": skillsInfo["available"],
|
||||||
})
|
})
|
||||||
|
|
||||||
runningServices, err := setupAndStartServices(cfg, agentLoop, msgBus, pidData.Token, listenResult)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
closeListeners = false
|
closeListeners = false
|
||||||
|
|
||||||
// Setup manual reload channel for /reload endpoint
|
// Setup manual reload channel for /reload endpoint
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,29 @@ var protocolMetaByName = map[string]protocolMeta{
|
||||||
"longcat": {defaultAPIBase: "https://api.longcat.chat/openai"},
|
"longcat": {defaultAPIBase: "https://api.longcat.chat/openai"},
|
||||||
"modelscope": {defaultAPIBase: "https://api-inference.modelscope.cn/v1"},
|
"modelscope": {defaultAPIBase: "https://api-inference.modelscope.cn/v1"},
|
||||||
"mimo": {defaultAPIBase: "https://api.xiaomimimo.com/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.
|
// 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".
|
// If no prefix is specified, it defaults to "openai".
|
||||||
// Examples:
|
// Examples:
|
||||||
// - "openai/gpt-4o" -> ("openai", "gpt-4o")
|
// - "openai/gpt-4o" -> ("openai", "gpt-4o")
|
||||||
// - "anthropic/claude-sonnet-4.6" -> ("anthropic", "claude-sonnet-4.6")
|
// - "anthropic/claude-3-opus" -> ("anthropic", "claude-3-opus")
|
||||||
// - "gpt-4o" -> ("openai", "gpt-4o") // default protocol
|
// - "gpt-4o" -> ("openai", "gpt-4o")
|
||||||
func ExtractProtocol(model string) (protocol, modelID string) {
|
func ExtractProtocol(model string) (protocol, modelID string) {
|
||||||
model = strings.TrimSpace(model)
|
model = strings.TrimSpace(model)
|
||||||
protocol, modelID, found := strings.Cut(model, "/")
|
p, m, found := strings.Cut(model, "/")
|
||||||
if !found {
|
if !found {
|
||||||
return "openai", model
|
return "openai", model
|
||||||
}
|
}
|
||||||
return protocol, modelID
|
return p, m
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResolveAPIBase returns the configured API base, or the protocol default when
|
// 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)
|
protocol, modelID := ExtractProtocol(cfg.Model)
|
||||||
if cfg.Protocol != "" {
|
if cfg.Protocol != "" {
|
||||||
protocol = 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
|
userAgent := cfg.UserAgent
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,10 @@ func (p *HTTPProvider) GetDefaultModel() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *HTTPProvider) SupportsThinking() bool {
|
||||||
|
return p.delegate.SupportsThinking()
|
||||||
|
}
|
||||||
|
|
||||||
func (p *HTTPProvider) SupportsNativeSearch() bool {
|
func (p *HTTPProvider) SupportsNativeSearch() bool {
|
||||||
return p.delegate.SupportsNativeSearch()
|
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.
|
// Merge extra body fields configured per-provider/model.
|
||||||
// These are injected last so they take precedence over defaults.
|
// These are injected last so they take precedence over defaults.
|
||||||
maps.Copy(requestBody, p.extraBody)
|
maps.Copy(requestBody, p.extraBody)
|
||||||
|
|
@ -466,6 +492,16 @@ func buildToolsList(tools []ToolDefinition, nativeSearch bool) []any {
|
||||||
return result
|
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 {
|
func (p *Provider) SupportsNativeSearch() bool {
|
||||||
return isNativeSearchHost(p.apiBase)
|
return isNativeSearchHost(p.apiBase)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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