Merge branch 'main' into codex/conduct-risk-and-bug-assessment-4fecjc

This commit is contained in:
野生派Coder~
2026-02-14 13:58:29 +08:00
committed by GitHub
10 changed files with 67 additions and 30 deletions

View File

@@ -31,7 +31,6 @@ import (
var errGatewayNotRunningSlash = errors.New("gateway not running")
const llmCallTimeout = 90 * time.Second
const perSessionQueueSize = 64
type sessionWorker struct {
@@ -53,6 +52,7 @@ type AgentLoop struct {
orchestrator *tools.Orchestrator
running atomic.Bool
compactionCfg config.ContextCompactionConfig
llmCallTimeout time.Duration
workersMu sync.Mutex
workers map[string]*sessionWorker
}
@@ -137,6 +137,7 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers
tools: toolsRegistry,
orchestrator: orchestrator,
compactionCfg: cfg.Agents.Defaults.ContextCompaction,
llmCallTimeout: time.Duration(cfg.Providers.Proxy.TimeoutSec) * time.Second,
workers: make(map[string]*sessionWorker),
}
@@ -561,7 +562,7 @@ func (al *AgentLoop) runLLMToolLoop(
})
llmStart := time.Now()
llmCtx, cancelLLM := context.WithTimeout(ctx, llmCallTimeout)
llmCtx, cancelLLM := context.WithTimeout(ctx, al.llmCallTimeout)
response, err := al.callLLMWithModelFallback(llmCtx, messages, providerToolDefs, map[string]interface{}{
"max_tokens": 8192,
"temperature": 0.7,
@@ -680,7 +681,7 @@ func (al *AgentLoop) runLLMToolLoop(
})
finalizeMessages = sanitizeMessagesForToolCalling(finalizeMessages)
llmCtx, cancelLLM := context.WithTimeout(ctx, llmCallTimeout)
llmCtx, cancelLLM := context.WithTimeout(ctx, al.llmCallTimeout)
finalResp, err := al.callLLMWithModelFallback(llmCtx, finalizeMessages, nil, map[string]interface{}{
"max_tokens": 1024,
"temperature": 0.3,

View File

@@ -63,6 +63,13 @@ func NewTelegramChannel(cfg config.TelegramConfig, bus *bus.MessageBus) (*Telegr
}, nil
}
func withTelegramAPITimeout(ctx context.Context) (context.Context, context.CancelFunc) {
if ctx == nil {
ctx = context.Background()
}
return context.WithTimeout(ctx, telegramAPICallTimeout)
}
func (c *TelegramChannel) SetTranscriber(transcriber *voice.GroqTranscriber) {
c.transcriber = transcriber
}
@@ -84,7 +91,9 @@ func (c *TelegramChannel) Start(ctx context.Context) error {
c.setRunning(true)
botInfo, err := c.bot.GetMe(context.Background())
getMeCtx, cancelGetMe := withTelegramAPITimeout(ctx)
botInfo, err := c.bot.GetMe(getMeCtx)
cancelGetMe()
if err != nil {
return fmt.Errorf("failed to get bot info: %w", err)
}
@@ -205,13 +214,12 @@ func (c *TelegramChannel) Send(ctx context.Context, msg bus.OutboundMessage) err
}
chatID := telegoutil.ID(chatIDInt)
// Stop thinking animation
if stop, ok := c.stopThinking.Load(msg.ChatID); ok {
// Stop thinking animation first to avoid animation/update races.
if stop, ok := c.stopThinking.LoadAndDelete(msg.ChatID); ok {
logger.DebugCF("telegram", "Telegram thinking stop signal", map[string]interface{}{
logger.FieldChatID: msg.ChatID,
})
safeCloseSignal(stop)
c.stopThinking.Delete(msg.ChatID)
} else {
logger.DebugCF("telegram", "Telegram thinking stop skipped (not found)", map[string]interface{}{
logger.FieldChatID: msg.ChatID,
@@ -222,18 +230,21 @@ func (c *TelegramChannel) Send(ctx context.Context, msg bus.OutboundMessage) err
// Try to edit placeholder
if pID, ok := c.placeholders.Load(msg.ChatID); ok {
c.placeholders.Delete(msg.ChatID)
// Always reset placeholder state even when edit/send fails.
defer c.placeholders.Delete(msg.ChatID)
logger.DebugCF("telegram", "Telegram editing thinking placeholder", map[string]interface{}{
logger.FieldChatID: msg.ChatID,
"message_id": pID.(int),
})
_, err := c.bot.EditMessageText(ctx, &telego.EditMessageTextParams{
editCtx, cancelEdit := withTelegramAPITimeout(ctx)
_, err := c.bot.EditMessageText(editCtx, &telego.EditMessageTextParams{
ChatID: chatID,
MessageID: pID.(int),
Text: htmlContent,
ParseMode: telego.ModeHTML,
})
cancelEdit()
if err == nil {
logger.DebugCF("telegram", "Telegram placeholder updated", map[string]interface{}{
@@ -252,14 +263,18 @@ func (c *TelegramChannel) Send(ctx context.Context, msg bus.OutboundMessage) err
})
}
_, err = c.bot.SendMessage(ctx, telegoutil.Message(chatID, htmlContent).WithParseMode(telego.ModeHTML))
sendCtx, cancelSend := withTelegramAPITimeout(ctx)
_, err = c.bot.SendMessage(sendCtx, telegoutil.Message(chatID, htmlContent).WithParseMode(telego.ModeHTML))
cancelSend()
if err != nil {
logger.WarnCF("telegram", "HTML parse failed, fallback to plain text", map[string]interface{}{
logger.FieldError: err.Error(),
})
plain := plainTextFromTelegramHTML(htmlContent)
_, err = c.bot.SendMessage(ctx, telegoutil.Message(chatID, plain))
sendPlainCtx, cancelSendPlain := withTelegramAPITimeout(ctx)
_, err = c.bot.SendMessage(sendPlainCtx, telegoutil.Message(chatID, plain))
cancelSendPlain()
if err != nil {
logger.ErrorCF("telegram", "Telegram plain-text fallback send failed", map[string]interface{}{
logger.FieldChatID: msg.ChatID,

View File

@@ -107,9 +107,10 @@ type ProvidersConfig struct {
}
type ProviderConfig struct {
APIKey string `json:"api_key" env:"CLAWGO_PROVIDERS_{{.Name}}_API_KEY"`
APIBase string `json:"api_base" env:"CLAWGO_PROVIDERS_{{.Name}}_API_BASE"`
Auth string `json:"auth" env:"CLAWGO_PROVIDERS_{{.Name}}_AUTH"`
APIKey string `json:"api_key" env:"CLAWGO_PROVIDERS_{{.Name}}_API_KEY"`
APIBase string `json:"api_base" env:"CLAWGO_PROVIDERS_{{.Name}}_API_BASE"`
Auth string `json:"auth" env:"CLAWGO_PROVIDERS_{{.Name}}_AUTH"`
TimeoutSec int `json:"timeout_sec" env:"CLAWGO_PROVIDERS_PROXY_TIMEOUT_SEC"`
}
type GatewayConfig struct {
@@ -276,7 +277,8 @@ func DefaultConfig() *Config {
},
Providers: ProvidersConfig{
Proxy: ProviderConfig{
APIBase: "http://localhost:8080/v1",
APIBase: "http://localhost:8080/v1",
TimeoutSec: 90,
},
},
Gateway: GatewayConfig{

View File

@@ -39,6 +39,9 @@ func Validate(cfg *Config) []error {
if cfg.Providers.Proxy.APIBase == "" {
errs = append(errs, fmt.Errorf("providers.proxy.api_base is required"))
}
if cfg.Providers.Proxy.TimeoutSec <= 0 {
errs = append(errs, fmt.Errorf("providers.proxy.timeout_sec must be > 0"))
}
if cfg.Gateway.Port <= 0 || cfg.Gateway.Port > 65535 {
errs = append(errs, fmt.Errorf("gateway.port must be in 1..65535"))

View File

@@ -24,18 +24,18 @@ type HTTPProvider struct {
apiKey string
apiBase string
authMode string
timeout time.Duration
httpClient *http.Client
}
const defaultChatTimeout = 90 * time.Second
func NewHTTPProvider(apiKey, apiBase, authMode string) *HTTPProvider {
func NewHTTPProvider(apiKey, apiBase, authMode string, timeout time.Duration) *HTTPProvider {
return &HTTPProvider{
apiKey: apiKey,
apiBase: apiBase,
authMode: authMode,
timeout: timeout,
httpClient: &http.Client{
Timeout: defaultChatTimeout,
Timeout: timeout,
},
}
}
@@ -50,7 +50,7 @@ func (p *HTTPProvider) Chat(ctx context.Context, messages []Message, tools []Too
"model": model,
"messages_count": len(messages),
"tools_count": len(tools),
"timeout": defaultChatTimeout.String(),
"timeout": p.timeout.String(),
})
requestBody := map[string]interface{}{
@@ -208,6 +208,9 @@ func CreateProvider(cfg *config.Config) (LLMProvider, error) {
if apiBase == "" {
return nil, fmt.Errorf("no API base (CLIProxyAPI) configured")
}
if cfg.Providers.Proxy.TimeoutSec <= 0 {
return nil, fmt.Errorf("invalid providers.proxy.timeout_sec: %d", cfg.Providers.Proxy.TimeoutSec)
}
return NewHTTPProvider(apiKey, apiBase, authMode), nil
return NewHTTPProvider(apiKey, apiBase, authMode, time.Duration(cfg.Providers.Proxy.TimeoutSec)*time.Second), nil
}

View File

@@ -93,7 +93,7 @@ func (si *SkillInstaller) Uninstall(skillName string) error {
}
func (si *SkillInstaller) ListAvailableSkills(ctx context.Context) ([]AvailableSkill, error) {
url := "https://raw.githubusercontent.com/sipeed/clawgo-skills/main/skills.json"
url := "https://raw.githubusercontent.com/YspCoder/clawgo-skills/main/skills.json"
client := &http.Client{Timeout: 15 * time.Second}
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)

View File

@@ -39,6 +39,11 @@ func NewExecTool(cfg config.ShellConfig, workspace string) *ExecTool {
allowPatterns = append(allowPatterns, regexp.MustCompile(`(?i)\b`+regexp.QuoteMeta(p)+`\b`))
}
allowPatterns := make([]*regexp.Regexp, 0, len(cfg.AllowedCmds))
for _, p := range cfg.AllowedCmds {
allowPatterns = append(allowPatterns, regexp.MustCompile(`\b`+regexp.QuoteMeta(p)+`\b`))
}
return &ExecTool{
workingDir: workspace,
timeout: cfg.Timeout,