fix: resolve lint errors from upstream merge

- Remove unused activeRequests field, selectCandidates,
  findNearestUserMessage, and buildCommandsRuntime from loop.go
- Remove duplicate createHTTPClient (moved to pkg/utils by upstream)
- Fix golines violation (long line in helpers.go)
- Fix misspell: serialises -> serializes
- Fix golines: wrap long json.RawMessage literal in test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
dj-oyu 2026-03-14 20:05:54 +09:00
parent dbd9599913
commit c65d45dae3
5 changed files with 6 additions and 144 deletions

View file

@ -295,7 +295,8 @@ func setupAndStartServices(
if strings.HasPrefix(webAppURL, "https://") { if strings.HasPrefix(webAppURL, "https://") {
hostname, tsErr := tailscale.DetectHostname() hostname, tsErr := tailscale.DetectHostname()
if tsErr != nil { if tsErr != nil {
logger.ErrorCF("miniapp", "HTTPS URL configured but Tailscale not available", map[string]any{"error": tsErr.Error()}) logger.ErrorCF("miniapp", "HTTPS URL configured but Tailscale not available",
map[string]any{"error": tsErr.Error()})
} else { } else {
certDir := filepath.Join(cfg.WorkspacePath(), "state", "certs") certDir := filepath.Join(cfg.WorkspacePath(), "state", "certs")
certFile, keyFile, certErr := tailscale.FetchCert(hostname, certDir) certFile, keyFile, certErr := tailscale.FetchCert(hostname, certDir)

View file

@ -66,8 +66,6 @@ type AgentLoop struct {
mcp mcpRuntime mcp mcpRuntime
mu sync.RWMutex mu sync.RWMutex
// Track active requests for safe provider cleanup
activeRequests sync.WaitGroup
providerCache map[string]providers.LLMProvider providerCache map[string]providers.LLMProvider
@ -2263,69 +2261,6 @@ func (al *AgentLoop) runLLMIteration(
return finalContent, iteration, nil return finalContent, iteration, nil
} }
// selectCandidates returns the model candidates and resolved model name to use
// for a conversation turn. When model routing is configured and the incoming
// message scores below the complexity threshold, it returns the light model
// candidates instead of the primary ones.
//
// The returned (candidates, model) pair is used for all LLM calls within one
// turn — tool follow-up iterations use the same tier as the initial call so
// that a multi-step tool chain doesn't switch models mid-way.
func (al *AgentLoop) selectCandidates(
agent *AgentInstance,
userMsg string,
history []providers.Message,
) (candidates []providers.FallbackCandidate, model string) {
if agent.Router == nil || len(agent.LightCandidates) == 0 {
return agent.Candidates, agent.Model
}
_, usedLight, score := agent.Router.SelectModel(userMsg, history, agent.Model)
if !usedLight {
logger.DebugCF("agent", "Model routing: primary model selected",
map[string]any{
"agent_id": agent.ID,
"score": score,
"threshold": agent.Router.Threshold(),
})
return agent.Candidates, agent.Model
}
logger.InfoCF("agent", "Model routing: light model selected",
map[string]any{
"agent_id": agent.ID,
"light_model": agent.Router.LightModel(),
"score": score,
"threshold": agent.Router.Threshold(),
})
return agent.LightCandidates, agent.Router.LightModel()
}
// findNearestUserMessage finds the nearest user message to the given index.
// It searches backward first, then forward if no user message is found.
func (al *AgentLoop) findNearestUserMessage(messages []providers.Message, mid int) int {
originalMid := mid
for mid > 0 && messages[mid].Role != "user" {
mid--
}
if messages[mid].Role == "user" {
return mid
}
mid = originalMid
for mid < len(messages) && messages[mid].Role != "user" {
mid++
}
if mid < len(messages) {
return mid
}
return originalMid
}
// callLLMWithRetry calls the LLM with streaming support, fallback chain, // callLLMWithRetry calls the LLM with streaming support, fallback chain,
// and retry logic for timeout and context window errors. // and retry logic for timeout and context window errors.
func (al *AgentLoop) callLLMWithRetry( func (al *AgentLoop) callLLMWithRetry(
@ -2657,42 +2592,6 @@ func (al *AgentLoop) publishToolMedia(ctx context.Context, result *tools.ToolRes
}) })
} }
func (al *AgentLoop) buildCommandsRuntime(agent *AgentInstance, opts *processOptions) *commands.Runtime {
registry := al.GetRegistry()
cfg := al.GetConfig()
rt := &commands.Runtime{
Config: cfg,
ListAgentIDs: registry.ListAgentIDs,
ListDefinitions: al.cmdRegistry.Definitions,
GetEnabledChannels: func() []string {
if al.channelManager == nil {
return nil
}
return al.channelManager.GetEnabledChannels()
},
SwitchChannel: func(value string) error {
if al.channelManager == nil {
return fmt.Errorf("channel manager not initialized")
}
if _, exists := al.channelManager.GetChannel(value); !exists && value != "cli" {
return fmt.Errorf("channel '%s' not found or not enabled", value)
}
return nil
},
}
if agent != nil {
rt.GetModelInfo = func() (string, string) {
return agent.Model, cfg.Agents.Defaults.Provider
}
rt.SwitchModel = func(value string) (string, error) {
oldModel := agent.Model
agent.Model = value
return oldModel, nil
}
}
return rt
}
// forceTextResponse makes a final LLM call without tools when max iterations // forceTextResponse makes a final LLM call without tools when max iterations
// are exhausted, forcing a text response. // are exhausted, forcing a text response.
func (al *AgentLoop) forceTextResponse(ctx context.Context, agent *AgentInstance, messages []providers.Message) string { func (al *AgentLoop) forceTextResponse(ctx context.Context, agent *AgentInstance, messages []providers.Message) string {

View file

@ -270,7 +270,7 @@ func buildRequestBody(
func buildTools(tools []ToolDefinition) []any { func buildTools(tools []ToolDefinition) []any {
result := make([]any, len(tools)) result := make([]any, len(tools))
for i, tool := range tools { for i, tool := range tools {
// Unmarshal Parameters (json.RawMessage) into map so it serialises // Unmarshal Parameters (json.RawMessage) into map so it serializes
// correctly as a nested JSON object rather than a raw byte string. // correctly as a nested JSON object rather than a raw byte string.
var schema any var schema any
if len(tool.Function.Parameters) > 0 { if len(tool.Function.Parameters) > 0 {

View file

@ -137,7 +137,9 @@ func TestBuildRequestBody(t *testing.T) {
Function: ToolFunctionDefinition{ Function: ToolFunctionDefinition{
Name: "get_weather", Name: "get_weather",
Description: "Get current weather", Description: "Get current weather",
Parameters: json.RawMessage(`{"type":"object","properties":{"location":{"type":"string","description":"City name"}}}`), Parameters: json.RawMessage(
`{"type":"object","properties":{"location":{"type":"string","description":"City name"}}}`,
),
}, },
}, },
}, },

View file

@ -89,46 +89,6 @@ func (it *APIKeyIterator) Next() (string, bool) {
return key, true return key, true
} }
// createHTTPClient creates an HTTP client with optional proxy support
func createHTTPClient(proxyURL string, timeout time.Duration) (*http.Client, error) {
client := &http.Client{
Timeout: timeout,
Transport: &http.Transport{
MaxIdleConns: 10,
IdleConnTimeout: 30 * time.Second,
DisableCompression: false,
TLSHandshakeTimeout: 15 * time.Second,
},
}
if proxyURL != "" {
proxy, err := url.Parse(proxyURL)
if err != nil {
return nil, fmt.Errorf("invalid proxy URL: %w", err)
}
scheme := strings.ToLower(proxy.Scheme)
switch scheme {
case "http", "https", "socks5", "socks5h":
default:
return nil, fmt.Errorf(
"unsupported proxy scheme %q (supported: http, https, socks5, socks5h)",
proxy.Scheme,
)
}
if proxy.Host == "" {
return nil, fmt.Errorf("invalid proxy URL: missing host")
}
client.Transport.(*http.Transport).Proxy = http.ProxyURL(proxy)
} else {
client.Transport.(*http.Transport).Proxy = http.ProxyFromEnvironment
}
return client, nil
}
type SearchProvider interface { type SearchProvider interface {
Search(ctx context.Context, query string, count int) (string, error) Search(ctx context.Context, query string, count int) (string, error)
} }