fix: format code with golines to pass linter checks

Fixed formatting issues in three files to comply with golines requirements:
- pkg/agent/loop.go: Split long function calls and logger statements
- pkg/config/config.go: Align struct field tags
- pkg/tools/toolloop.go: Split long function calls

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Administrator 2026-03-24 14:19:10 +08:00
parent aca03f5df7
commit 2cb05975bf
3 changed files with 153 additions and 41 deletions

View file

@ -163,7 +163,10 @@ func registerSharedTools(
if cfg.Tools.IsToolEnabled("web") { if cfg.Tools.IsToolEnabled("web") {
searchTool, err := tools.NewWebSearchTool(tools.WebSearchToolOptions{ searchTool, err := tools.NewWebSearchTool(tools.WebSearchToolOptions{
BraveAPIKeys: config.MergeAPIKeys(cfg.Tools.Web.Brave.APIKey(), cfg.Tools.Web.Brave.APIKeys()), BraveAPIKeys: config.MergeAPIKeys(
cfg.Tools.Web.Brave.APIKey(),
cfg.Tools.Web.Brave.APIKeys(),
),
BraveMaxResults: cfg.Tools.Web.Brave.MaxResults, BraveMaxResults: cfg.Tools.Web.Brave.MaxResults,
BraveEnabled: cfg.Tools.Web.Brave.Enabled, BraveEnabled: cfg.Tools.Web.Brave.Enabled,
TavilyAPIKeys: config.MergeAPIKeys( TavilyAPIKeys: config.MergeAPIKeys(
@ -196,7 +199,11 @@ func registerSharedTools(
Proxy: cfg.Tools.Web.Proxy, Proxy: cfg.Tools.Web.Proxy,
}) })
if err != nil { if err != nil {
logger.ErrorCF("agent", "Failed to create web search tool", map[string]any{"error": err.Error()}) logger.ErrorCF(
"agent",
"Failed to create web search tool",
map[string]any{"error": err.Error()},
)
} else if searchTool != nil { } else if searchTool != nil {
agent.Tools.Register(searchTool) agent.Tools.Register(searchTool)
} }
@ -209,7 +216,11 @@ func registerSharedTools(
cfg.Tools.Web.FetchLimitBytes, cfg.Tools.Web.FetchLimitBytes,
cfg.Tools.Web.PrivateHostWhitelist) cfg.Tools.Web.PrivateHostWhitelist)
if err != nil { if err != nil {
logger.ErrorCF("agent", "Failed to create web fetch tool", map[string]any{"error": err.Error()}) logger.ErrorCF(
"agent",
"Failed to create web fetch tool",
map[string]any{"error": err.Error()},
)
} else { } else {
agent.Tools.Register(fetchTool) agent.Tools.Register(fetchTool)
} }
@ -285,7 +296,14 @@ func registerSharedTools(
} }
// Team tool // Team tool
teamSubagentManager := tools.NewSubagentManager(provider, agent.Model, agent.Candidates, agent.Workspace, cfg.Tools.Team, msgBus) teamSubagentManager := tools.NewSubagentManager(
provider,
agent.Model,
agent.Candidates,
agent.Workspace,
cfg.Tools.Team,
msgBus,
)
teamSubagentManager.SetLLMOptions(agent.MaxTokens, agent.Temperature) teamSubagentManager.SetLLMOptions(agent.MaxTokens, agent.Temperature)
teamTool := tools.NewTeamTool(teamSubagentManager, cfg) teamTool := tools.NewTeamTool(teamSubagentManager, cfg)
@ -492,7 +510,12 @@ func (al *AgentLoop) Run(ctx context.Context) error {
"queue_depth": al.pendingSteeringCountForScope(target.SessionKey), "queue_depth": al.pendingSteeringCountForScope(target.SessionKey),
}) })
continued, continueErr := al.Continue(ctx, target.SessionKey, target.Channel, target.ChatID) continued, continueErr := al.Continue(
ctx,
target.SessionKey,
target.Channel,
target.ChatID,
)
if continueErr != nil { if continueErr != nil {
logger.WarnCF("agent", "Failed to continue queued steering", logger.WarnCF("agent", "Failed to continue queued steering",
map[string]any{ map[string]any{
@ -520,14 +543,22 @@ func (al *AgentLoop) Run(ctx context.Context) error {
"queue_depth": al.pendingSteeringCountForScope(target.SessionKey), "queue_depth": al.pendingSteeringCountForScope(target.SessionKey),
}) })
continued, continueErr := al.Continue(ctx, target.SessionKey, target.Channel, target.ChatID) continued, continueErr := al.Continue(
ctx,
target.SessionKey,
target.Channel,
target.ChatID,
)
if continueErr != nil { if continueErr != nil {
logger.WarnCF("agent", "Failed to continue queued steering after shutdown drain", logger.WarnCF(
"agent",
"Failed to continue queued steering after shutdown drain",
map[string]any{ map[string]any{
"channel": target.Channel, "channel": target.Channel,
"chat_id": target.ChatID, "chat_id": target.ChatID,
"error": continueErr.Error(), "error": continueErr.Error(),
}) },
)
return return
} }
if continued == "" { if continued == "" {
@ -586,11 +617,15 @@ func (al *AgentLoop) drainBusToSteering(ctx context.Context, activeScope, active
msgScope, _, scopeOK := al.resolveSteeringTarget(msg) msgScope, _, scopeOK := al.resolveSteeringTarget(msg)
if !scopeOK || msgScope != activeScope { if !scopeOK || msgScope != activeScope {
if err := al.requeueInboundMessage(msg); err != nil { if err := al.requeueInboundMessage(msg); err != nil {
logger.WarnCF("agent", "Failed to requeue non-steering inbound message", map[string]any{ logger.WarnCF(
"agent",
"Failed to requeue non-steering inbound message",
map[string]any{
"error": err.Error(), "error": err.Error(),
"channel": msg.Channel, "channel": msg.Channel,
"sender_id": msg.SenderID, "sender_id": msg.SenderID,
}) },
)
} }
continue continue
} }
@ -624,7 +659,10 @@ func (al *AgentLoop) Stop() {
al.running.Store(false) al.running.Store(false)
} }
func (al *AgentLoop) publishResponseIfNeeded(ctx context.Context, channel, chatID, response string) { func (al *AgentLoop) publishResponseIfNeeded(
ctx context.Context,
channel, chatID, response string,
) {
if response == "" { if response == "" {
return return
} }
@ -1074,7 +1112,10 @@ var audioAnnotationRe = regexp.MustCompile(`\[(voice|audio)(?::[^\]]*)?\]`)
// transcribeAudioInMessage resolves audio media refs, transcribes them, and // transcribeAudioInMessage resolves audio media refs, transcribes them, and
// replaces audio annotations in msg.Content with the transcribed text. // replaces audio annotations in msg.Content with the transcribed text.
// Returns the (possibly modified) message and true if audio was transcribed. // Returns the (possibly modified) message and true if audio was transcribed.
func (al *AgentLoop) transcribeAudioInMessage(ctx context.Context, msg bus.InboundMessage) (bus.InboundMessage, bool) { func (al *AgentLoop) transcribeAudioInMessage(
ctx context.Context,
msg bus.InboundMessage,
) (bus.InboundMessage, bool) {
if al.transcriber == nil || al.mediaStore == nil || len(msg.Media) == 0 { if al.transcriber == nil || al.mediaStore == nil || len(msg.Media) == 0 {
return msg, false return msg, false
} }
@ -1084,7 +1125,11 @@ func (al *AgentLoop) transcribeAudioInMessage(ctx context.Context, msg bus.Inbou
for _, ref := range msg.Media { for _, ref := range msg.Media {
path, meta, err := al.mediaStore.ResolveWithMeta(ref) path, meta, err := al.mediaStore.ResolveWithMeta(ref)
if err != nil { if err != nil {
logger.WarnCF("voice", "Failed to resolve media ref", map[string]any{"ref": ref, "error": err}) logger.WarnCF(
"voice",
"Failed to resolve media ref",
map[string]any{"ref": ref, "error": err},
)
continue continue
} }
if !utils.IsAudioFile(meta.Filename, meta.ContentType) { if !utils.IsAudioFile(meta.Filename, meta.ContentType) {
@ -1162,7 +1207,11 @@ func (al *AgentLoop) sendTranscriptionFeedback(
ReplyToMessageID: messageID, ReplyToMessageID: messageID,
}) })
if err != nil { if err != nil {
logger.WarnCF("voice", "Failed to send transcription feedback", map[string]any{"error": err.Error()}) logger.WarnCF(
"voice",
"Failed to send transcription feedback",
map[string]any{"error": err.Error()},
)
} }
} }
@ -1362,7 +1411,9 @@ func (al *AgentLoop) processMessage(ctx context.Context, msg bus.InboundMessage)
return al.runAgentLoop(ctx, agent, opts) return al.runAgentLoop(ctx, agent, opts)
} }
func (al *AgentLoop) resolveMessageRoute(msg bus.InboundMessage) (routing.ResolvedRoute, *AgentInstance, error) { func (al *AgentLoop) resolveMessageRoute(
msg bus.InboundMessage,
) (routing.ResolvedRoute, *AgentInstance, error) {
registry := al.GetRegistry() registry := al.GetRegistry()
route := registry.ResolveRoute(routing.RouteInput{ route := registry.ResolveRoute(routing.RouteInput{
Channel: msg.Channel, Channel: msg.Channel,
@ -1378,7 +1429,10 @@ func (al *AgentLoop) resolveMessageRoute(msg bus.InboundMessage) (routing.Resolv
agent = registry.GetDefaultAgent() agent = registry.GetDefaultAgent()
} }
if agent == nil { if agent == nil {
return routing.ResolvedRoute{}, nil, fmt.Errorf("no agent available for route (agent_id=%s)", route.AgentID) return routing.ResolvedRoute{}, nil, fmt.Errorf(
"no agent available for route (agent_id=%s)",
route.AgentID,
)
} }
return route, agent, nil return route, agent, nil
@ -2579,12 +2633,15 @@ turnLoop:
} }
if steerMsgs := al.dequeueSteeringMessagesForScope(ts.sessionKey); len(steerMsgs) > 0 { if steerMsgs := al.dequeueSteeringMessagesForScope(ts.sessionKey); len(steerMsgs) > 0 {
logger.InfoCF("agent", "Steering arrived after turn completion; continuing turn before finalizing", logger.InfoCF(
"agent",
"Steering arrived after turn completion; continuing turn before finalizing",
map[string]any{ map[string]any{
"agent_id": ts.agent.ID, "agent_id": ts.agent.ID,
"steering_count": len(steerMsgs), "steering_count": len(steerMsgs),
"session_key": ts.sessionKey, "session_key": ts.sessionKey,
}) },
)
pendingMessages = append(pendingMessages, steerMsgs...) pendingMessages = append(pendingMessages, steerMsgs...)
finalContent = "" finalContent = ""
goto turnLoop goto turnLoop
@ -2701,11 +2758,18 @@ func (al *AgentLoop) selectCandidates(
"score": score, "score": score,
"threshold": agent.Router.Threshold(), "threshold": agent.Router.Threshold(),
}) })
return agent.LightCandidates, resolvedCandidateModel(agent.LightCandidates, agent.Router.LightModel()) return agent.LightCandidates, resolvedCandidateModel(
agent.LightCandidates,
agent.Router.LightModel(),
)
} }
// maybeSummarize triggers summarization if the session history exceeds thresholds. // maybeSummarize triggers summarization if the session history exceeds thresholds.
func (al *AgentLoop) maybeSummarize(agent *AgentInstance, sessionKey string, turnScope turnEventScope) { func (al *AgentLoop) maybeSummarize(
agent *AgentInstance,
sessionKey string,
turnScope turnEventScope,
) {
newHistory := agent.Sessions.GetHistory(sessionKey) newHistory := agent.Sessions.GetHistory(sessionKey)
tokenEstimate := al.estimateTokens(newHistory) tokenEstimate := al.estimateTokens(newHistory)
threshold := agent.ContextWindow * agent.SummarizeTokenPercent / 100 threshold := agent.ContextWindow * agent.SummarizeTokenPercent / 100
@ -2739,7 +2803,10 @@ type compressionResult struct {
// prompt is built dynamically by BuildMessages and is NOT stored here. // prompt is built dynamically by BuildMessages and is NOT stored here.
// The compression note is recorded in the session summary so that // The compression note is recorded in the session summary so that
// BuildMessages can include it in the next system prompt. // BuildMessages can include it in the next system prompt.
func (al *AgentLoop) forceCompression(agent *AgentInstance, sessionKey string) (compressionResult, bool) { func (al *AgentLoop) forceCompression(
agent *AgentInstance,
sessionKey string,
) (compressionResult, bool) {
history := agent.Sessions.GetHistory(sessionKey) history := agent.Sessions.GetHistory(sessionKey)
if len(history) <= 2 { if len(history) <= 2 {
return compressionResult{}, false return compressionResult{}, false
@ -2892,7 +2959,11 @@ func formatToolsForLog(toolDefs []providers.ToolDefinition) string {
} }
// summarizeSession summarizes the conversation history for a session. // summarizeSession summarizes the conversation history for a session.
func (al *AgentLoop) summarizeSession(agent *AgentInstance, sessionKey string, turnScope turnEventScope) { func (al *AgentLoop) summarizeSession(
agent *AgentInstance,
sessionKey string,
turnScope turnEventScope,
) {
ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second)
defer cancel() defer cancel()
@ -3180,7 +3251,10 @@ func (al *AgentLoop) handleCommand(
} }
} }
func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance, opts *processOptions) *commands.Runtime { func (al *AgentLoop) buildCommandsRuntime(
agent *AgentInstance,
opts *processOptions,
) *commands.Runtime {
registry := al.GetRegistry() registry := al.GetRegistry()
cfg := al.GetConfig() cfg := al.GetConfig()
rt := &commands.Runtime{ rt := &commands.Runtime{
@ -3221,7 +3295,10 @@ func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance, opts *processOpt
} }
if agent != nil { if agent != nil {
rt.GetModelInfo = func() (string, string) { rt.GetModelInfo = func() (string, string) {
return agent.Model, resolvedCandidateProvider(agent.Candidates, cfg.Agents.Defaults.Provider) return agent.Model, resolvedCandidateProvider(
agent.Candidates,
cfg.Agents.Defaults.Provider,
)
} }
rt.SwitchModel = func(value string) (string, error) { rt.SwitchModel = func(value string) (string, error) {
value = strings.TrimSpace(value) value = strings.TrimSpace(value)
@ -3235,7 +3312,12 @@ func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance, opts *processOpt
return "", fmt.Errorf("failed to initialize model %q: %w", value, err) return "", fmt.Errorf("failed to initialize model %q: %w", value, err)
} }
nextCandidates := resolveModelCandidates(cfg, cfg.Agents.Defaults.Provider, modelCfg.Model, agent.Fallbacks) nextCandidates := resolveModelCandidates(
cfg,
cfg.Agents.Defaults.Provider,
modelCfg.Model,
agent.Fallbacks,
)
if len(nextCandidates) == 0 { if len(nextCandidates) == 0 {
return "", fmt.Errorf("model %q did not resolve to any provider candidates", value) return "", fmt.Errorf("model %q did not resolve to any provider candidates", value)
} }
@ -3324,7 +3406,10 @@ func (al *AgentLoop) applyExplicitSkillCommand(
canonicalSkill, ok := agent.ContextBuilder.ResolveSkillName(fields[1]) canonicalSkill, ok := agent.ContextBuilder.ResolveSkillName(fields[1])
if !ok { if !ok {
return true, true, fmt.Sprintf("Unknown skill: %s\nUse /list skills to see installed skills.", fields[1]) return true, true, fmt.Sprintf(
"Unknown skill: %s\nUse /list skills to see installed skills.",
fields[1],
)
} }
if len(fields) == 2 { if len(fields) == 2 {

View file

@ -1395,7 +1395,10 @@ func LoadConfig(path string) (*Config, error) {
var cfg *Config var cfg *Config
switch versionInfo.Version { switch versionInfo.Version {
case 0: case 0:
logger.InfoF("config migrate start", map[string]any{"from": versionInfo.Version, "to": CurrentVersion}) logger.InfoF(
"config migrate start",
map[string]any{"from": versionInfo.Version, "to": CurrentVersion},
)
// Legacy config (no version field) // Legacy config (no version field)
v, e := loadConfigV0(data) v, e := loadConfigV0(data)
if e != nil { if e != nil {
@ -1403,10 +1406,16 @@ func LoadConfig(path string) (*Config, error) {
} }
cfg, e = v.Migrate() cfg, e = v.Migrate()
if e != nil { if e != nil {
logger.DebugF("config migrate fail", map[string]any{"from": versionInfo.Version, "to": CurrentVersion}) logger.DebugF(
"config migrate fail",
map[string]any{"from": versionInfo.Version, "to": CurrentVersion},
)
return nil, e return nil, e
} }
logger.DebugF("config migrate success", map[string]any{"from": versionInfo.Version, "to": CurrentVersion}) logger.DebugF(
"config migrate success",
map[string]any{"from": versionInfo.Version, "to": CurrentVersion},
)
defer func() { defer func() {
_ = SaveConfig(path, cfg) _ = SaveConfig(path, cfg)
}() }()
@ -1437,9 +1446,11 @@ func LoadConfig(path string) (*Config, error) {
for _, m := range cfg.ModelList { for _, m := range cfg.ModelList {
for _, k := range m.apiKeys { for _, k := range m.apiKeys {
if k != "" && !strings.HasPrefix(k, "enc://") && !strings.HasPrefix(k, "file://") { if k != "" && !strings.HasPrefix(k, "enc://") && !strings.HasPrefix(k, "file://") {
fmt.Fprintf(os.Stderr, fmt.Fprintf(
os.Stderr,
"picoclaw: warning: model %q has a plaintext api_key; call SaveConfig to encrypt it\n", "picoclaw: warning: model %q has a plaintext api_key; call SaveConfig to encrypt it\n",
m.ModelName) m.ModelName,
)
break // Only warn once per model break // Only warn once per model
} }
} }

View file

@ -67,7 +67,13 @@ func RunToolLoop(
llmOpts = map[string]any{} llmOpts = map[string]any{}
} }
// 3. Call LLM // 3. Call LLM
response, err := config.Provider.Chat(ctx, messages, providerToolDefs, config.Model, llmOpts) response, err := config.Provider.Chat(
ctx,
messages,
providerToolDefs,
config.Model,
llmOpts,
)
if err != nil { if err != nil {
logger.ErrorCF("toolloop", "LLM call failed", logger.ErrorCF("toolloop", "LLM call failed",
map[string]any{ map[string]any{
@ -119,8 +125,11 @@ func RunToolLoop(
// 3.6 Truncation Recovery: LLM response was cut off (max_tokens hit or malformed JSON). // 3.6 Truncation Recovery: LLM response was cut off (max_tokens hit or malformed JSON).
// Inject a recovery message so the LLM knows to retry with a shorter, complete response. // Inject a recovery message so the LLM knows to retry with a shorter, complete response.
if response.FinishReason == "truncated" { if response.FinishReason == "truncated" {
logger.WarnCF("toolloop", "LLM response was truncated (max_tokens hit), injecting recovery message", logger.WarnCF(
map[string]any{"iteration": iteration}) "toolloop",
"LLM response was truncated (max_tokens hit), injecting recovery message",
map[string]any{"iteration": iteration},
)
messages = append(messages, providers.Message{ messages = append(messages, providers.Message{
Role: "assistant", Role: "assistant",
Content: response.Content, Content: response.Content,
@ -233,7 +242,14 @@ func RunToolLoop(
var toolResult *ToolResult var toolResult *ToolResult
if config.Tools != nil { if config.Tools != nil {
toolResult = config.Tools.ExecuteWithContext(ctx, tc.Name, tc.Arguments, channel, chatID, nil) toolResult = config.Tools.ExecuteWithContext(
ctx,
tc.Name,
tc.Arguments,
channel,
chatID,
nil,
)
} else { } else {
toolResult = ErrorResult("No tools available") toolResult = ErrorResult("No tools available")
} }