ci: fix linter errors in CI pipeline
- Fixed `musttag` errors in `web/backend/api/config.go` by explicitly decoding JSON into an anonymous struct. - Fixed a `govet` shadow error in `pkg/providers/common/http_logger.go`. - Fixed formatting errors reported by `golines` and `gci` in `pkg/config/config.go`, `pkg/config/security.go`, and `pkg/providers/anthropic_messages/provider.go`. Co-authored-by: TanLuong <28281768+TanLuong@users.noreply.github.com>
This commit is contained in:
parent
06ca00403b
commit
44e84585d6
5 changed files with 58 additions and 20 deletions
|
|
@ -1048,10 +1048,10 @@ type SearXNGConfig struct {
|
|||
}
|
||||
|
||||
type GLMSearchConfig struct {
|
||||
Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_WEB_GLM_ENABLED"`
|
||||
apiKey string
|
||||
secDirty bool
|
||||
BaseURL string `json:"base_url" env:"PICOCLAW_TOOLS_WEB_GLM_BASE_URL"`
|
||||
Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_WEB_GLM_ENABLED"`
|
||||
apiKey string
|
||||
secDirty bool
|
||||
BaseURL string `json:"base_url" env:"PICOCLAW_TOOLS_WEB_GLM_BASE_URL"`
|
||||
// SearchEngine specifies the search backend: "search_std" (default),
|
||||
// "search_pro", "search_pro_sogou", or "search_pro_quark".
|
||||
SearchEngine string `json:"search_engine" env:"PICOCLAW_TOOLS_WEB_GLM_SEARCH_ENGINE"`
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ func (c *Config) MergeAndApplySecurity(newer *SecurityConfig) error {
|
|||
c.security = mergeSecurityConfig(c.security, newer)
|
||||
return applySecurityConfig(c, c.security)
|
||||
}
|
||||
|
||||
// mergeSecurityConfig merges two SecurityConfig instances, preferring non-empty values from 'newer'.
|
||||
// This is used during config migration to preserve existing security data while adding new entries.
|
||||
func mergeSecurityConfig(existing, newer *SecurityConfig) *SecurityConfig {
|
||||
|
|
@ -335,7 +336,8 @@ func mergeChannelsSecurity(dst, src *ChannelsSecurity) {
|
|||
if src.Pico != nil && src.Pico.Token != "" {
|
||||
dst.Pico = src.Pico
|
||||
}
|
||||
if src.IRC != nil && (src.IRC.Password != "" || src.IRC.NickServPassword != "" || src.IRC.SASLPassword != "") {
|
||||
if src.IRC != nil &&
|
||||
(src.IRC.Password != "" || src.IRC.NickServPassword != "" || src.IRC.SASLPassword != "") {
|
||||
dst.IRC = src.IRC
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ func NewProviderWithTimeout(apiKey, apiBase string, timeoutSeconds int) *Provide
|
|||
}
|
||||
|
||||
return &Provider{
|
||||
apiKey: apiKey,
|
||||
apiBase: baseURL,
|
||||
apiKey: apiKey,
|
||||
apiBase: baseURL,
|
||||
httpClient: common.NewHTTPClientWithTimeout("", timeout),
|
||||
}
|
||||
}
|
||||
|
|
@ -102,7 +102,10 @@ func (p *Provider) Chat(
|
|||
|
||||
// Set headers
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("X-API-Key", p.apiKey) //nolint:canonicalheader // Anthropic API requires exact header name
|
||||
req.Header.Set(
|
||||
"X-API-Key",
|
||||
p.apiKey,
|
||||
) //nolint:canonicalheader // Anthropic API requires exact header name
|
||||
req.Header.Set("Anthropic-Version", defaultAPIVersion)
|
||||
|
||||
// Execute request
|
||||
|
|
@ -134,7 +137,11 @@ func (p *Provider) Chat(
|
|||
return nil, fmt.Errorf("service unavailable (503): %s", string(body))
|
||||
default:
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
|
||||
return nil, fmt.Errorf(
|
||||
"API request failed with status %d: %s",
|
||||
resp.StatusCode,
|
||||
string(body),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,7 +201,8 @@ func buildRequestBody(
|
|||
"content": msg.Content,
|
||||
}
|
||||
if len(apiMessages) > 0 {
|
||||
if prev, ok := apiMessages[len(apiMessages)-1].(map[string]any); ok && prev["role"] == "user" {
|
||||
if prev, ok := apiMessages[len(apiMessages)-1].(map[string]any); ok &&
|
||||
prev["role"] == "user" {
|
||||
if content, ok := prev["content"].([]map[string]any); ok {
|
||||
prev["content"] = append(content, toolResultBlock)
|
||||
continue
|
||||
|
|
@ -258,7 +266,8 @@ func buildRequestBody(
|
|||
"content": msg.Content,
|
||||
}
|
||||
if len(apiMessages) > 0 {
|
||||
if prev, ok := apiMessages[len(apiMessages)-1].(map[string]any); ok && prev["role"] == "user" {
|
||||
if prev, ok := apiMessages[len(apiMessages)-1].(map[string]any); ok &&
|
||||
prev["role"] == "user" {
|
||||
if content, ok := prev["content"].([]map[string]any); ok {
|
||||
prev["content"] = append(content, toolResultBlock)
|
||||
continue
|
||||
|
|
@ -310,7 +319,10 @@ func parseResponseBody(body []byte) (*LLMResponse, error) {
|
|||
|
||||
// Extract content and tool calls
|
||||
var content strings.Builder
|
||||
toolCalls := make([]ToolCall, 0) // Initialize as empty slice (not nil) for consistent JSON serialization
|
||||
toolCalls := make(
|
||||
[]ToolCall,
|
||||
0,
|
||||
) // Initialize as empty slice (not nil) for consistent JSON serialization
|
||||
|
||||
for _, block := range resp.Content {
|
||||
switch block.Type {
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ func (lrt *LoggingRoundTripper) RoundTrip(req *http.Request) (*http.Response, er
|
|||
|
||||
// Optional: Log Response Body
|
||||
if res.Body != nil {
|
||||
bodyBytes, err := io.ReadAll(res.Body)
|
||||
if err == nil {
|
||||
bodyBytes, readErr := io.ReadAll(res.Body)
|
||||
if readErr == nil {
|
||||
res.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
||||
// Truncate response body if too long to avoid flooding logs
|
||||
respStr := string(bodyBytes)
|
||||
|
|
|
|||
|
|
@ -66,9 +66,22 @@ func (h *Handler) handleUpdateConfig(w http.ResponseWriter, r *http.Request) {
|
|||
cfg.SecurityCopyFrom(oldCfg)
|
||||
|
||||
// Intercept explicitly provided security tokens from JSON payload that json.Unmarshal drops.
|
||||
var incomingSec config.SecurityConfig
|
||||
// We need to decode into an anonymous struct with json tags because SecurityConfig
|
||||
// doesn't have json tags for its fields (it uses yaml tags).
|
||||
var incomingSec struct {
|
||||
ModelList map[string]config.ModelSecurityEntry `json:"model_list"`
|
||||
Channels *config.ChannelsSecurity `json:"channels,omitempty"`
|
||||
Web *config.WebToolsSecurity `json:"web,omitempty"`
|
||||
Skills *config.SkillsSecurity `json:"skills,omitempty"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &incomingSec); err == nil {
|
||||
cfg.MergeAndApplySecurity(&incomingSec)
|
||||
secConfig := config.SecurityConfig{
|
||||
ModelList: incomingSec.ModelList,
|
||||
Channels: incomingSec.Channels,
|
||||
Web: incomingSec.Web,
|
||||
Skills: incomingSec.Skills,
|
||||
}
|
||||
cfg.MergeAndApplySecurity(&secConfig)
|
||||
} else {
|
||||
cfg.ApplySecurity()
|
||||
}
|
||||
|
|
@ -164,9 +177,20 @@ func (h *Handler) handlePatchConfig(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
// Restore security fields from existing config and merge explicitly provided overrides.
|
||||
newCfg.SecurityCopyFrom(cfg)
|
||||
var incomingSec config.SecurityConfig
|
||||
if err := json.Unmarshal(patchBody, &incomingSec); err == nil {
|
||||
newCfg.MergeAndApplySecurity(&incomingSec)
|
||||
var patchSec struct {
|
||||
ModelList map[string]config.ModelSecurityEntry `json:"model_list"`
|
||||
Channels *config.ChannelsSecurity `json:"channels,omitempty"`
|
||||
Web *config.WebToolsSecurity `json:"web,omitempty"`
|
||||
Skills *config.SkillsSecurity `json:"skills,omitempty"`
|
||||
}
|
||||
if err := json.Unmarshal(patchBody, &patchSec); err == nil {
|
||||
secConfig := config.SecurityConfig{
|
||||
ModelList: patchSec.ModelList,
|
||||
Channels: patchSec.Channels,
|
||||
Web: patchSec.Web,
|
||||
Skills: patchSec.Skills,
|
||||
}
|
||||
newCfg.MergeAndApplySecurity(&secConfig)
|
||||
} else {
|
||||
newCfg.ApplySecurity()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue