fix: satisfy backend lint

This commit is contained in:
kone
2026-05-17 06:45:35 +08:00
parent 3afb4afeda
commit b866c0fd27
10 changed files with 147 additions and 155 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ func main() {
runMainServer() runMainServer()
} }
func runSetupServer() { func runSetupServer() { //nolint:unused // kept for setup wizard server mode restoration.
r := gin.New() r := gin.New()
r.Use(middleware.Recovery()) r.Use(middleware.Recovery())
r.Use(middleware.CORS(config.CORSConfig{})) r.Use(middleware.CORS(config.CORSConfig{}))
+2 -2
View File
@@ -12,8 +12,8 @@ const (
// Role constants // Role constants
const ( const (
RoleAdmin = "admin" RoleAdmin = "admin"
RoleUser = "user" RoleUser = "user"
RoleUserAdmin = "useradmin" RoleUserAdmin = "useradmin"
) )
+1 -1
View File
@@ -177,7 +177,7 @@ func sha256Hex(seed string) string {
func isHexString(value string) bool { func isHexString(value string) bool {
for _, c := range value { for _, c := range value {
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { if (c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F') {
return false return false
} }
} }
+84 -94
View File
@@ -159,7 +159,7 @@ type KiroToolSpecification struct {
} }
type KiroInputSchema struct { type KiroInputSchema struct {
JSON interface{} `json:"json"` JSON any `json:"json"`
} }
type KiroAssistantResponseMessage struct { type KiroAssistantResponseMessage struct {
@@ -168,11 +168,11 @@ type KiroAssistantResponseMessage struct {
} }
type KiroToolUse struct { type KiroToolUse struct {
ToolUseID string `json:"toolUseId"` ToolUseID string `json:"toolUseId"`
Name string `json:"name"` Name string `json:"name"`
Input map[string]interface{} `json:"input"` Input map[string]any `json:"input"`
IsTruncated bool `json:"-"` IsTruncated bool `json:"-"`
TruncatedRaw string `json:"-"` TruncatedRaw string `json:"-"`
} }
type toolUseState struct { type toolUseState struct {
@@ -501,7 +501,7 @@ func StreamEventStreamAsAnthropicWithContext(ctx context.Context, body io.Reader
}, },
}) })
} }
processStreamingToolUseEvent := func(event map[string]interface{}) error { processStreamingToolUseEvent := func(event map[string]any) error {
tu := nestedEvent(event, "toolUseEvent") tu := nestedEvent(event, "toolUseEvent")
toolUseID := getString(tu, "toolUseId") toolUseID := getString(tu, "toolUseId")
name := getString(tu, "name") name := getString(tu, "name")
@@ -514,7 +514,7 @@ func StreamEventStreamAsAnthropicWithContext(ctx context.Context, body io.Reader
if err := emitStreamingToolInput(toolUseID, name, v); err != nil { if err := emitStreamingToolInput(toolUseID, name, v); err != nil {
return err return err
} }
case map[string]interface{}: case map[string]any:
encoded, err := json.Marshal(v) encoded, err := json.Marshal(v)
if err != nil { if err != nil {
return err return err
@@ -825,7 +825,7 @@ func StreamEventStreamAsAnthropicWithContext(ctx context.Context, body io.Reader
continue continue
} }
var event map[string]interface{} var event map[string]any
if err := json.Unmarshal(msg.Payload, &event); err != nil { if err := json.Unmarshal(msg.Payload, &event); err != nil {
continue continue
} }
@@ -988,10 +988,6 @@ func extractSystemPrompt(claudeBody []byte) string {
return systemField.String() return systemField.String()
} }
func isThinkingEnabledWithHeaders(body []byte, headers http.Header) bool {
return deriveThinkingDirective(body, headers) != nil
}
func deriveThinkingDirective(body []byte, headers http.Header) *thinkingDirective { func deriveThinkingDirective(body []byte, headers http.Header) *thinkingDirective {
if override := thinkingDirectiveFromModel(gjson.GetBytes(body, "model").String()); override != nil { if override := thinkingDirectiveFromModel(gjson.GetBytes(body, "model").String()); override != nil {
return override return override
@@ -1129,10 +1125,6 @@ func isToolChoiceNone(claudeBody []byte) bool {
return strings.EqualFold(strings.TrimSpace(toolChoice.Get("type").String()), "none") return strings.EqualFold(strings.TrimSpace(toolChoice.Get("type").String()), "none")
} }
func kiroToolNameAlias(name string) string {
return mapKiroToolName(name, nil)
}
func prependSystemHistory(history []KiroHistoryMessage, systemPrompt, modelID, origin string) []KiroHistoryMessage { func prependSystemHistory(history []KiroHistoryMessage, systemPrompt, modelID, origin string) []KiroHistoryMessage {
systemPrompt = strings.TrimSpace(systemPrompt) systemPrompt = strings.TrimSpace(systemPrompt)
if systemPrompt == "" { if systemPrompt == "" {
@@ -1220,9 +1212,7 @@ func appendChunkedToolDescription(name, description string) string {
if suffix == "" { if suffix == "" {
return description return description
} }
if strings.Contains(description, suffix) { description = strings.Replace(description, suffix, "", 1)
description = strings.Replace(description, suffix, "", 1)
}
if strings.TrimSpace(description) == "" { if strings.TrimSpace(description) == "" {
return suffix return suffix
} }
@@ -1311,11 +1301,11 @@ func normalizeKiroJSONSchema(schema any) any {
} }
func normalizeKiroJSONSchemaValue(schema any, enforceObjectKeywords bool) any { func normalizeKiroJSONSchemaValue(schema any, enforceObjectKeywords bool) any {
obj, ok := schema.(map[string]interface{}) obj, ok := schema.(map[string]any)
if !ok || obj == nil { if !ok || obj == nil {
return defaultKiroJSONSchema() return defaultKiroJSONSchema()
} }
normalized := make(map[string]interface{}, len(obj)+4) normalized := make(map[string]any, len(obj)+4)
for key, value := range obj { for key, value := range obj {
normalized[key] = normalizeSchemaChild(key, value) normalized[key] = normalizeSchemaChild(key, value)
} }
@@ -1329,9 +1319,9 @@ func normalizeKiroJSONSchemaValue(schema any, enforceObjectKeywords bool) any {
hasSchemaKey(normalized, "required") || hasSchemaKey(normalized, "required") ||
hasSchemaKey(normalized, "additionalProperties") hasSchemaKey(normalized, "additionalProperties")
if needsObjectKeywords { if needsObjectKeywords {
properties, ok := normalized["properties"].(map[string]interface{}) properties, ok := normalized["properties"].(map[string]any)
if !ok || properties == nil { if !ok || properties == nil {
normalized["properties"] = map[string]interface{}{} normalized["properties"] = map[string]any{}
} else { } else {
for key, value := range properties { for key, value := range properties {
properties[key] = normalizeKiroJSONSchemaValue(value, false) properties[key] = normalizeKiroJSONSchemaValue(value, false)
@@ -1341,7 +1331,7 @@ func normalizeKiroJSONSchemaValue(schema any, enforceObjectKeywords bool) any {
normalized["required"] = normalizeSchemaRequired(normalized["required"]) normalized["required"] = normalizeSchemaRequired(normalized["required"])
switch additional := normalized["additionalProperties"].(type) { switch additional := normalized["additionalProperties"].(type) {
case bool: case bool:
case map[string]interface{}: case map[string]any:
normalized["additionalProperties"] = normalizeKiroJSONSchemaValue(additional, false) normalized["additionalProperties"] = normalizeKiroJSONSchemaValue(additional, false)
default: default:
normalized["additionalProperties"] = true normalized["additionalProperties"] = true
@@ -1350,26 +1340,26 @@ func normalizeKiroJSONSchemaValue(schema any, enforceObjectKeywords bool) any {
return normalized return normalized
} }
func hasSchemaKey(schema map[string]interface{}, key string) bool { func hasSchemaKey(schema map[string]any, key string) bool {
_, ok := schema[key] _, ok := schema[key]
return ok return ok
} }
func defaultKiroJSONSchema() map[string]interface{} { func defaultKiroJSONSchema() map[string]any {
return map[string]interface{}{ return map[string]any{
"type": "object", "type": "object",
"properties": map[string]interface{}{}, "properties": map[string]any{},
"required": []interface{}{}, "required": []any{},
"additionalProperties": true, "additionalProperties": true,
} }
} }
func normalizeSchemaRequired(value interface{}) []interface{} { func normalizeSchemaRequired(value any) []any {
arr, ok := value.([]interface{}) arr, ok := value.([]any)
if !ok { if !ok {
return []interface{}{} return []any{}
} }
out := make([]interface{}, 0, len(arr)) out := make([]any, 0, len(arr))
for _, item := range arr { for _, item := range arr {
if s, ok := item.(string); ok { if s, ok := item.(string); ok {
out = append(out, s) out = append(out, s)
@@ -1378,22 +1368,22 @@ func normalizeSchemaRequired(value interface{}) []interface{} {
return out return out
} }
func normalizeSchemaChild(key string, value interface{}) interface{} { func normalizeSchemaChild(key string, value any) any {
switch key { switch key {
case "items", "not": case "items", "not":
if obj, ok := value.(map[string]interface{}); ok { if obj, ok := value.(map[string]any); ok {
return normalizeKiroJSONSchemaValue(obj, false) return normalizeKiroJSONSchemaValue(obj, false)
} }
if arr, ok := value.([]interface{}); ok { if arr, ok := value.([]any); ok {
out := make([]interface{}, 0, len(arr)) out := make([]any, 0, len(arr))
for _, item := range arr { for _, item := range arr {
out = append(out, normalizeKiroJSONSchemaValue(item, false)) out = append(out, normalizeKiroJSONSchemaValue(item, false))
} }
return out return out
} }
case "oneOf", "anyOf", "allOf": case "oneOf", "anyOf", "allOf":
if arr, ok := value.([]interface{}); ok { if arr, ok := value.([]any); ok {
out := make([]interface{}, 0, len(arr)) out := make([]any, 0, len(arr))
for _, item := range arr { for _, item := range arr {
out = append(out, normalizeKiroJSONSchemaValue(item, false)) out = append(out, normalizeKiroJSONSchemaValue(item, false))
} }
@@ -1658,7 +1648,7 @@ func buildAssistantMessageStruct(msg gjson.Result, requestCtx *KiroRequestContex
_, _ = contentBuilder.WriteString(part.Get("text").String()) _, _ = contentBuilder.WriteString(part.Get("text").String())
case "tool_use": case "tool_use":
toolName := mapKiroToolName(part.Get("name").String(), requestCtx) toolName := mapKiroToolName(part.Get("name").String(), requestCtx)
input := map[string]interface{}{} input := map[string]any{}
toolInput := part.Get("input") toolInput := part.Get("input")
if toolInput.IsObject() { if toolInput.IsObject() {
toolInput.ForEach(func(key, value gjson.Result) bool { toolInput.ForEach(func(key, value gjson.Result) bool {
@@ -1704,7 +1694,7 @@ func mergeAdjacentMessages(messages []gjson.Result) []gjson.Result {
merged = append(merged, msg) merged = append(merged, msg)
continue continue
} }
mergedMsg := map[string]interface{}{ mergedMsg := map[string]any{
"role": role, "role": role,
"content": json.RawMessage(mergeMessageContent(lastMsg, msg)), "content": json.RawMessage(mergeMessageContent(lastMsg, msg)),
} }
@@ -1715,7 +1705,7 @@ func mergeAdjacentMessages(messages []gjson.Result) []gjson.Result {
} }
func mergeMessageContent(msg1, msg2 gjson.Result) string { func mergeMessageContent(msg1, msg2 gjson.Result) string {
var blocks1, blocks2 []map[string]interface{} var blocks1, blocks2 []map[string]any
content1 := msg1.Get("content") content1 := msg1.Get("content")
content2 := msg2.Get("content") content2 := msg2.Get("content")
if content1.IsArray() { if content1.IsArray() {
@@ -1723,14 +1713,14 @@ func mergeMessageContent(msg1, msg2 gjson.Result) string {
blocks1 = append(blocks1, blockToMap(block)) blocks1 = append(blocks1, blockToMap(block))
} }
} else if content1.Type == gjson.String { } else if content1.Type == gjson.String {
blocks1 = append(blocks1, map[string]interface{}{"type": "text", "text": content1.String()}) blocks1 = append(blocks1, map[string]any{"type": "text", "text": content1.String()})
} }
if content2.IsArray() { if content2.IsArray() {
for _, block := range content2.Array() { for _, block := range content2.Array() {
blocks2 = append(blocks2, blockToMap(block)) blocks2 = append(blocks2, blockToMap(block))
} }
} else if content2.Type == gjson.String { } else if content2.Type == gjson.String {
blocks2 = append(blocks2, map[string]interface{}{"type": "text", "text": content2.String()}) blocks2 = append(blocks2, map[string]any{"type": "text", "text": content2.String()})
} }
if len(blocks1) > 0 && len(blocks2) > 0 && blocks1[len(blocks1)-1]["type"] == "text" && blocks2[0]["type"] == "text" { if len(blocks1) > 0 && len(blocks2) > 0 && blocks1[len(blocks1)-1]["type"] == "text" && blocks2[0]["type"] == "text" {
leftText, leftOK := blocks1[len(blocks1)-1]["text"].(string) leftText, leftOK := blocks1[len(blocks1)-1]["text"].(string)
@@ -1745,13 +1735,13 @@ func mergeMessageContent(msg1, msg2 gjson.Result) string {
return string(result) return string(result)
} }
func blockToMap(block gjson.Result) map[string]interface{} { func blockToMap(block gjson.Result) map[string]any {
result := make(map[string]interface{}) result := make(map[string]any)
block.ForEach(func(key, value gjson.Result) bool { block.ForEach(func(key, value gjson.Result) bool {
if value.IsObject() { if value.IsObject() {
result[key.String()] = blockToMap(value) result[key.String()] = blockToMap(value)
} else if value.IsArray() { } else if value.IsArray() {
var arr []interface{} var arr []any
for _, item := range value.Array() { for _, item := range value.Array() {
if item.IsObject() { if item.IsObject() {
arr = append(arr, blockToMap(item)) arr = append(arr, blockToMap(item))
@@ -1789,7 +1779,7 @@ func parseEventStream(body io.Reader) (string, []KiroToolUse, Usage, string, err
continue continue
} }
var event map[string]interface{} var event map[string]any
if err := json.Unmarshal(msg.Payload, &event); err != nil { if err := json.Unmarshal(msg.Payload, &event); err != nil {
continue continue
} }
@@ -1835,8 +1825,8 @@ func parseEventStream(body io.Reader) (string, []KiroToolUse, Usage, string, err
} }
if currentTool != nil && currentTool.ToolUseID != "" && !processedIDs[currentTool.ToolUseID] { if currentTool != nil && currentTool.ToolUseID != "" && !processedIDs[currentTool.ToolUseID] {
completed, _ := processToolUseEvent(map[string]interface{}{ completed, _ := processToolUseEvent(map[string]any{
"toolUseEvent": map[string]interface{}{ "toolUseEvent": map[string]any{
"toolUseId": currentTool.ToolUseID, "toolUseId": currentTool.ToolUseID,
"name": currentTool.Name, "name": currentTool.Name,
"stop": true, "stop": true,
@@ -1866,7 +1856,7 @@ func parseEventStream(body io.Reader) (string, []KiroToolUse, Usage, string, err
} }
func buildClaudeResponse(content string, toolUses []KiroToolUse, model string, usage Usage, stopReason string, requestCtx KiroRequestContext) []byte { func buildClaudeResponse(content string, toolUses []KiroToolUse, model string, usage Usage, stopReason string, requestCtx KiroRequestContext) []byte {
var blocks []map[string]interface{} var blocks []map[string]any
blocks = append(blocks, extractThinkingBlocks(content)...) blocks = append(blocks, extractThinkingBlocks(content)...)
usableTools := 0 usableTools := 0
for _, tool := range toolUses { for _, tool := range toolUses {
@@ -1874,7 +1864,7 @@ func buildClaudeResponse(content string, toolUses []KiroToolUse, model string, u
continue continue
} }
usableTools++ usableTools++
blocks = append(blocks, map[string]interface{}{ blocks = append(blocks, map[string]any{
"type": "tool_use", "type": "tool_use",
"id": tool.ToolUseID, "id": tool.ToolUseID,
"name": restoreResponseToolName(tool.Name, requestCtx), "name": restoreResponseToolName(tool.Name, requestCtx),
@@ -1883,11 +1873,11 @@ func buildClaudeResponse(content string, toolUses []KiroToolUse, model string, u
} }
pureThinking := hasThinkingBlocksOnly(blocks) && usableTools == 0 pureThinking := hasThinkingBlocksOnly(blocks) && usableTools == 0
if pureThinking { if pureThinking {
blocks = append(blocks, map[string]interface{}{"type": "text", "text": ""}) blocks = append(blocks, map[string]any{"type": "text", "text": ""})
stopReason = "max_tokens" stopReason = "max_tokens"
} }
if len(blocks) == 0 { if len(blocks) == 0 {
blocks = append(blocks, map[string]interface{}{"type": "text", "text": ""}) blocks = append(blocks, map[string]any{"type": "text", "text": ""})
} }
if stopReason == "" { if stopReason == "" {
if usableTools > 0 { if usableTools > 0 {
@@ -1896,14 +1886,14 @@ func buildClaudeResponse(content string, toolUses []KiroToolUse, model string, u
stopReason = "end_turn" stopReason = "end_turn"
} }
} }
response := map[string]interface{}{ response := map[string]any{
"id": "msg_" + uuid.NewString()[:24], "id": "msg_" + uuid.NewString()[:24],
"type": "message", "type": "message",
"role": "assistant", "role": "assistant",
"model": model, "model": model,
"content": blocks, "content": blocks,
"stop_reason": stopReason, "stop_reason": stopReason,
"usage": map[string]interface{}{ "usage": map[string]any{
"input_tokens": usage.InputTokens, "input_tokens": usage.InputTokens,
"output_tokens": usage.OutputTokens, "output_tokens": usage.OutputTokens,
"cache_read_input_tokens": usage.CacheReadInputTokens, "cache_read_input_tokens": usage.CacheReadInputTokens,
@@ -1925,7 +1915,7 @@ func restoreResponseToolName(name string, requestCtx KiroRequestContext) string
return name return name
} }
func hasThinkingBlocksOnly(blocks []map[string]interface{}) bool { func hasThinkingBlocksOnly(blocks []map[string]any) bool {
if len(blocks) == 0 { if len(blocks) == 0 {
return false return false
} }
@@ -1944,36 +1934,36 @@ func hasThinkingBlocksOnly(blocks []map[string]interface{}) bool {
return hasThinking return hasThinking
} }
func extractThinkingBlocks(content string) []map[string]interface{} { func extractThinkingBlocks(content string) []map[string]any {
if content == "" { if content == "" {
return nil return nil
} }
if findRealThinkingStartTag(content, 0) == -1 { if findRealThinkingStartTag(content, 0) == -1 {
return []map[string]interface{}{{"type": "text", "text": content}} return []map[string]any{{"type": "text", "text": content}}
} }
var blocks []map[string]interface{} var blocks []map[string]any
pos := 0 pos := 0
for pos < len(content) { for pos < len(content) {
start := findRealThinkingStartTag(content, pos) start := findRealThinkingStartTag(content, pos)
if start == -1 { if start == -1 {
if text := content[pos:]; strings.TrimSpace(text) != "" { if text := content[pos:]; strings.TrimSpace(text) != "" {
blocks = append(blocks, map[string]interface{}{"type": "text", "text": text}) blocks = append(blocks, map[string]any{"type": "text", "text": text})
} }
break break
} }
end := findRealThinkingEndTag(content, start+len(thinkingStartTag)) end := findRealThinkingEndTag(content, start+len(thinkingStartTag))
if end == -1 { if end == -1 {
if text := content[pos:]; strings.TrimSpace(text) != "" { if text := content[pos:]; strings.TrimSpace(text) != "" {
blocks = append(blocks, map[string]interface{}{"type": "text", "text": text}) blocks = append(blocks, map[string]any{"type": "text", "text": text})
} }
break break
} }
if text := content[pos:start]; strings.TrimSpace(text) != "" { if text := content[pos:start]; strings.TrimSpace(text) != "" {
blocks = append(blocks, map[string]interface{}{"type": "text", "text": text}) blocks = append(blocks, map[string]any{"type": "text", "text": text})
} }
thinking := strings.TrimPrefix(content[start+len(thinkingStartTag):end], "\n") thinking := strings.TrimPrefix(content[start+len(thinkingStartTag):end], "\n")
if strings.TrimSpace(thinking) != "" { if strings.TrimSpace(thinking) != "" {
blocks = append(blocks, map[string]interface{}{ blocks = append(blocks, map[string]any{
"type": "thinking", "type": "thinking",
"thinking": thinking, "thinking": thinking,
"signature": thinkingSignature(thinking), "signature": thinkingSignature(thinking),
@@ -1985,7 +1975,7 @@ func extractThinkingBlocks(content string) []map[string]interface{} {
} }
} }
if len(blocks) == 0 { if len(blocks) == 0 {
blocks = append(blocks, map[string]interface{}{"type": "text", "text": ""}) blocks = append(blocks, map[string]any{"type": "text", "text": ""})
} }
return blocks return blocks
} }
@@ -2238,19 +2228,19 @@ func skipHeaderValue(headers []byte, offset int, valueType byte) (int, bool) {
} }
} }
func processToolUseEvent(event map[string]interface{}, currentTool *toolUseState, processedIDs map[string]bool) ([]KiroToolUse, *toolUseState) { func processToolUseEvent(event map[string]any, currentTool *toolUseState, processedIDs map[string]bool) ([]KiroToolUse, *toolUseState) {
tu := nestedEvent(event, "toolUseEvent") tu := nestedEvent(event, "toolUseEvent")
toolUseID := getString(tu, "toolUseId") toolUseID := getString(tu, "toolUseId")
name := getString(tu, "name") name := getString(tu, "name")
isStop, _ := tu["stop"].(bool) isStop, _ := tu["stop"].(bool)
var inputFragment string var inputFragment string
var inputMap map[string]interface{} var inputMap map[string]any
if inputRaw, ok := tu["input"]; ok { if inputRaw, ok := tu["input"]; ok {
switch v := inputRaw.(type) { switch v := inputRaw.(type) {
case string: case string:
inputFragment = v inputFragment = v
case map[string]interface{}: case map[string]any:
inputMap = v inputMap = v
} }
} }
@@ -2283,7 +2273,7 @@ func repairJSON(input string) string {
if str == "" { if str == "" {
return "{}" return "{}"
} }
var parsed interface{} var parsed any
if err := json.Unmarshal([]byte(str), &parsed); err == nil { if err := json.Unmarshal([]byte(str), &parsed); err == nil {
return str return str
} }
@@ -2382,7 +2372,7 @@ func finalizeRawToolUse(toolUseID, name, rawInput string) KiroToolUse {
tool := KiroToolUse{ tool := KiroToolUse{
ToolUseID: toolUseID, ToolUseID: toolUseID,
Name: normalizeResponseToolName(name), Name: normalizeResponseToolName(name),
Input: map[string]interface{}{}, Input: map[string]any{},
} }
rawInput = strings.TrimSpace(rawInput) rawInput = strings.TrimSpace(rawInput)
tool.TruncatedRaw = rawInput tool.TruncatedRaw = rawInput
@@ -2394,9 +2384,9 @@ func finalizeRawToolUse(toolUseID, name, rawInput string) KiroToolUse {
return tool return tool
} }
func finalizeStructuredToolUse(toolUseID, name string, input map[string]interface{}) KiroToolUse { func finalizeStructuredToolUse(toolUseID, name string, input map[string]any) KiroToolUse {
if input == nil { if input == nil {
input = map[string]interface{}{} input = map[string]any{}
} }
tool := KiroToolUse{ tool := KiroToolUse{
ToolUseID: toolUseID, ToolUseID: toolUseID,
@@ -2508,14 +2498,14 @@ func parseEmbeddedToolCalls(text string) (string, []KiroToolUse) {
for index < len(text) { for index < len(text) {
start := strings.Index(text[index:], embeddedToolCallPrefix) start := strings.Index(text[index:], embeddedToolCallPrefix)
if start == -1 { if start == -1 {
builder.WriteString(text[index:]) _, _ = builder.WriteString(text[index:])
break break
} }
start += index start += index
builder.WriteString(text[index:start]) _, _ = builder.WriteString(text[index:start])
tool, _, end, ok := parseEmbeddedToolCallAt(text, start) tool, _, end, ok := parseEmbeddedToolCallAt(text, start)
if !ok { if !ok {
builder.WriteString(text[start:]) _, _ = builder.WriteString(text[start:])
break break
} }
toolUses = append(toolUses, tool) toolUses = append(toolUses, tool)
@@ -2596,7 +2586,7 @@ func findMatchingJSONBracket(text string, start int) int {
return -1 return -1
} }
func isTruncatedToolUse(name, rawInput string, input map[string]interface{}) bool { func isTruncatedToolUse(name, rawInput string, input map[string]any) bool {
rawInput = strings.TrimSpace(rawInput) rawInput = strings.TrimSpace(rawInput)
if rawInput == "" { if rawInput == "" {
return hasToolRequirements(name) return hasToolRequirements(name)
@@ -2625,7 +2615,7 @@ func hasToolRequirements(name string) bool {
return ok return ok
} }
func hasMissingRequiredFields(name string, input map[string]interface{}) bool { func hasMissingRequiredFields(name string, input map[string]any) bool {
groups, ok := requiredToolFields[strings.ToLower(strings.TrimSpace(name))] groups, ok := requiredToolFields[strings.ToLower(strings.TrimSpace(name))]
if !ok { if !ok {
return false return false
@@ -2645,7 +2635,7 @@ func hasMissingRequiredFields(name string, input map[string]interface{}) bool {
return false return false
} }
func updateUsageFromEvent(usage *Usage, eventType string, event map[string]interface{}) { func updateUsageFromEvent(usage *Usage, eventType string, event map[string]any) {
if usage == nil { if usage == nil {
return return
} }
@@ -2653,7 +2643,7 @@ func updateUsageFromEvent(usage *Usage, eventType string, event map[string]inter
if len(meta) == 0 { if len(meta) == 0 {
meta = event meta = event
} }
if tokenUsage, ok := meta["tokenUsage"].(map[string]interface{}); ok { if tokenUsage, ok := meta["tokenUsage"].(map[string]any); ok {
if value, ok := firstInt(tokenUsage, "uncachedInputTokens", "inputTokens", "inputTokenCount", "promptTokens", "prompt_tokens"); ok { if value, ok := firstInt(tokenUsage, "uncachedInputTokens", "inputTokens", "inputTokenCount", "promptTokens", "prompt_tokens"); ok {
usage.InputTokens = value usage.InputTokens = value
} }
@@ -2707,7 +2697,7 @@ func updateUsageFromEvent(usage *Usage, eventType string, event map[string]inter
} }
} }
func firstInt(m map[string]interface{}, keys ...string) (int, bool) { func firstInt(m map[string]any, keys ...string) (int, bool) {
for _, key := range keys { for _, key := range keys {
if value, ok := toInt(m[key]); ok { if value, ok := toInt(m[key]); ok {
return value, true return value, true
@@ -2716,7 +2706,7 @@ func firstInt(m map[string]interface{}, keys ...string) (int, bool) {
return 0, false return 0, false
} }
func firstFloat(m map[string]interface{}, keys ...string) (float64, bool) { func firstFloat(m map[string]any, keys ...string) (float64, bool) {
for _, key := range keys { for _, key := range keys {
switch v := m[key].(type) { switch v := m[key].(type) {
case float64: case float64:
@@ -2786,11 +2776,11 @@ func countKiroTextTokens(text string) int {
return tokens return tokens
} }
func readToolUses(primary, fallback map[string]interface{}) []KiroToolUse { func readToolUses(primary, fallback map[string]any) []KiroToolUse {
var raw []interface{} var raw []any
if value, ok := primary["toolUses"].([]interface{}); ok { if value, ok := primary["toolUses"].([]any); ok {
raw = value raw = value
} else if value, ok := fallback["toolUses"].([]interface{}); ok { } else if value, ok := fallback["toolUses"].([]any); ok {
raw = value raw = value
} }
if len(raw) == 0 { if len(raw) == 0 {
@@ -2798,12 +2788,12 @@ func readToolUses(primary, fallback map[string]interface{}) []KiroToolUse {
} }
out := make([]KiroToolUse, 0, len(raw)) out := make([]KiroToolUse, 0, len(raw))
for _, item := range raw { for _, item := range raw {
tool, ok := item.(map[string]interface{}) tool, ok := item.(map[string]any)
if !ok { if !ok {
continue continue
} }
input := map[string]interface{}{} input := map[string]any{}
if value, ok := tool["input"].(map[string]interface{}); ok { if value, ok := tool["input"].(map[string]any); ok {
input = value input = value
} }
out = append(out, finalizeStructuredToolUse(getString(tool, "toolUseId"), getString(tool, "name"), input)) out = append(out, finalizeStructuredToolUse(getString(tool, "toolUseId"), getString(tool, "name"), input))
@@ -2811,28 +2801,28 @@ func readToolUses(primary, fallback map[string]interface{}) []KiroToolUse {
return out return out
} }
func nestedEvent(event map[string]interface{}, key string) map[string]interface{} { func nestedEvent(event map[string]any, key string) map[string]any {
if nested, ok := event[key].(map[string]interface{}); ok { if nested, ok := event[key].(map[string]any); ok {
return nested return nested
} }
return event return event
} }
func getString(m map[string]interface{}, key string) string { func getString(m map[string]any, key string) string {
if value, ok := m[key].(string); ok { if value, ok := m[key].(string); ok {
return value return value
} }
return "" return ""
} }
func readStopReason(m map[string]interface{}) string { func readStopReason(m map[string]any) string {
if stop := getString(m, "stop_reason"); stop != "" { if stop := getString(m, "stop_reason"); stop != "" {
return stop return stop
} }
return getString(m, "stopReason") return getString(m, "stopReason")
} }
func toInt(value interface{}) (int, bool) { func toInt(value any) (int, bool) {
switch v := value.(type) { switch v := value.(type) {
case float64: case float64:
return int(v), true return int(v), true
+35 -33
View File
@@ -17,10 +17,10 @@ const remoteWebSearchDescription = "WebSearch looks up information outside the m
var cachedWebSearchDescription atomic.Value // stores string var cachedWebSearchDescription atomic.Value // stores string
type MCPRequest struct { type MCPRequest struct {
ID string `json:"id"` ID string `json:"id"`
JSONRPC string `json:"jsonrpc"` JSONRPC string `json:"jsonrpc"`
Method string `json:"method"` Method string `json:"method"`
Params interface{} `json:"params,omitempty"` Params any `json:"params,omitempty"`
} }
type MCPResponse struct { type MCPResponse struct {
@@ -63,7 +63,9 @@ type SearchIndicator struct {
func GetCachedWebSearchDescription() string { func GetCachedWebSearchDescription() string {
if v := cachedWebSearchDescription.Load(); v != nil { if v := cachedWebSearchDescription.Load(); v != nil {
return strings.TrimSpace(v.(string)) if desc, ok := v.(string); ok {
return strings.TrimSpace(desc)
}
} }
return "" return ""
} }
@@ -138,18 +140,18 @@ func GenerateToolUseID() string {
} }
func ReplaceWebSearchToolDescription(body []byte) ([]byte, error) { func ReplaceWebSearchToolDescription(body []byte) ([]byte, error) {
var payload map[string]interface{} var payload map[string]any
if err := json.Unmarshal(body, &payload); err != nil { if err := json.Unmarshal(body, &payload); err != nil {
return body, err return body, err
} }
rawTools, ok := payload["tools"].([]interface{}) rawTools, ok := payload["tools"].([]any)
if !ok { if !ok {
return body, nil return body, nil
} }
replaced := make([]interface{}, 0, len(rawTools)) replaced := make([]any, 0, len(rawTools))
for _, rawTool := range rawTools { for _, rawTool := range rawTools {
tool, ok := rawTool.(map[string]interface{}) tool, ok := rawTool.(map[string]any)
if !ok { if !ok {
replaced = append(replaced, rawTool) replaced = append(replaced, rawTool)
continue continue
@@ -160,13 +162,13 @@ func ReplaceWebSearchToolDescription(body []byte) ([]byte, error) {
replaced = append(replaced, rawTool) replaced = append(replaced, rawTool)
continue continue
} }
replaced = append(replaced, map[string]interface{}{ replaced = append(replaced, map[string]any{
"name": "web_search", "name": "web_search",
"description": minimalWebSearchDescription, "description": minimalWebSearchDescription,
"input_schema": map[string]interface{}{ "input_schema": map[string]any{
"type": "object", "type": "object",
"properties": map[string]interface{}{ "properties": map[string]any{
"query": map[string]interface{}{ "query": map[string]any{
"type": "string", "type": "string",
"description": "The search query to execute", "description": "The search query to execute",
}, },
@@ -186,42 +188,42 @@ func ReplaceWebSearchToolDescription(body []byte) ([]byte, error) {
} }
func InjectToolResultsClaude(claudePayload []byte, toolUseID, query string, results *WebSearchResults) ([]byte, error) { func InjectToolResultsClaude(claudePayload []byte, toolUseID, query string, results *WebSearchResults) ([]byte, error) {
var payload map[string]interface{} var payload map[string]any
if err := json.Unmarshal(claudePayload, &payload); err != nil { if err := json.Unmarshal(claudePayload, &payload); err != nil {
return claudePayload, fmt.Errorf("parse claude payload: %w", err) return claudePayload, fmt.Errorf("parse claude payload: %w", err)
} }
rawMessages, ok := payload["messages"].([]interface{}) rawMessages, ok := payload["messages"].([]any)
if !ok { if !ok {
return claudePayload, fmt.Errorf("claude payload missing messages array") return claudePayload, fmt.Errorf("claude payload missing messages array")
} }
assistantMsg := map[string]interface{}{ assistantMsg := map[string]any{
"role": "assistant", "role": "assistant",
"content": []interface{}{ "content": []any{
map[string]interface{}{ map[string]any{
"type": "tool_use", "type": "tool_use",
"id": toolUseID, "id": toolUseID,
"name": "web_search", "name": "web_search",
"input": map[string]interface{}{"query": query}, "input": map[string]any{"query": query},
}, },
}, },
} }
userContent := []interface{}{ userContent := []any{
map[string]interface{}{ map[string]any{
"type": "tool_result", "type": "tool_result",
"tool_use_id": toolUseID, "tool_use_id": toolUseID,
"content": formatToolResultText(results), "content": formatToolResultText(results),
}, },
} }
if guidance := searchGuidanceText(); guidance != "" { if guidance := searchGuidanceText(); guidance != "" {
userContent = append(userContent, map[string]interface{}{ userContent = append(userContent, map[string]any{
"type": "text", "type": "text",
"text": guidance, "text": guidance,
}) })
} }
userMsg := map[string]interface{}{ userMsg := map[string]any{
"role": "user", "role": "user",
"content": userContent, "content": userContent,
} }
@@ -240,20 +242,20 @@ func InjectSearchIndicatorsInResponse(responsePayload []byte, searches []SearchI
return responsePayload, nil return responsePayload, nil
} }
var response map[string]interface{} var response map[string]any
if err := json.Unmarshal(responsePayload, &response); err != nil { if err := json.Unmarshal(responsePayload, &response); err != nil {
return responsePayload, err return responsePayload, err
} }
content, _ := response["content"].([]interface{}) content, _ := response["content"].([]any)
updated := make([]interface{}, 0, len(searches)*2+len(content)) updated := make([]any, 0, len(searches)*2+len(content))
for _, search := range searches { for _, search := range searches {
updated = append(updated, map[string]interface{}{ updated = append(updated, map[string]any{
"type": "server_tool_use", "type": "server_tool_use",
"id": search.ToolUseID, "id": search.ToolUseID,
"name": "web_search", "name": "web_search",
"input": map[string]interface{}{"query": search.Query}, "input": map[string]any{"query": search.Query},
}) })
updated = append(updated, map[string]interface{}{ updated = append(updated, map[string]any{
"type": "web_search_tool_result", "type": "web_search_tool_result",
"content": buildSearchResultContent(search.Results), "content": buildSearchResultContent(search.Results),
}) })
@@ -268,8 +270,8 @@ func InjectSearchIndicatorsInResponse(responsePayload []byte, searches []SearchI
return encoded, nil return encoded, nil
} }
func buildSearchResultContent(results *WebSearchResults) []map[string]interface{} { func buildSearchResultContent(results *WebSearchResults) []map[string]any {
content := make([]map[string]interface{}, 0) content := make([]map[string]any, 0)
if results == nil { if results == nil {
return content return content
} }
@@ -278,7 +280,7 @@ func buildSearchResultContent(results *WebSearchResults) []map[string]interface{
if result.Snippet != nil { if result.Snippet != nil {
snippet = strings.TrimSpace(*result.Snippet) snippet = strings.TrimSpace(*result.Snippet)
} }
content = append(content, map[string]interface{}{ content = append(content, map[string]any{
"type": "web_search_result", "type": "web_search_result",
"title": result.Title, "title": result.Title,
"url": result.URL, "url": result.URL,
@@ -325,7 +327,7 @@ func isWebSearchToolName(name, toolType string) bool {
} }
} }
func getInterfaceString(v interface{}) string { func getInterfaceString(v any) string {
if v == nil { if v == nil {
return "" return ""
} }
+18 -18
View File
@@ -14,14 +14,14 @@ type BufferedStreamResult struct {
} }
func GenerateSearchIndicatorEvents(query, toolUseID string, results *WebSearchResults, startIndex int) [][]byte { func GenerateSearchIndicatorEvents(query, toolUseID string, results *WebSearchResults, startIndex int) [][]byte {
searchContent := make([]map[string]interface{}, 0) searchContent := make([]map[string]any, 0)
if results != nil { if results != nil {
for _, result := range results.Results { for _, result := range results.Results {
snippet := "" snippet := ""
if result.Snippet != nil { if result.Snippet != nil {
snippet = strings.TrimSpace(*result.Snippet) snippet = strings.TrimSpace(*result.Snippet)
} }
searchContent = append(searchContent, map[string]interface{}{ searchContent = append(searchContent, map[string]any{
"type": "web_search_result", "type": "web_search_result",
"title": result.Title, "title": result.Title,
"url": result.URL, "url": result.URL,
@@ -33,21 +33,21 @@ func GenerateSearchIndicatorEvents(query, toolUseID string, results *WebSearchRe
inputJSON, _ := json.Marshal(map[string]string{"query": query}) inputJSON, _ := json.Marshal(map[string]string{"query": query})
events := []map[string]interface{}{ events := []map[string]any{
{ {
"type": "content_block_start", "type": "content_block_start",
"index": startIndex, "index": startIndex,
"content_block": map[string]interface{}{ "content_block": map[string]any{
"type": "server_tool_use", "type": "server_tool_use",
"id": toolUseID, "id": toolUseID,
"name": "web_search", "name": "web_search",
"input": map[string]interface{}{}, "input": map[string]any{},
}, },
}, },
{ {
"type": "content_block_delta", "type": "content_block_delta",
"index": startIndex, "index": startIndex,
"delta": map[string]interface{}{ "delta": map[string]any{
"type": "input_json_delta", "type": "input_json_delta",
"partial_json": string(inputJSON), "partial_json": string(inputJSON),
}, },
@@ -59,7 +59,7 @@ func GenerateSearchIndicatorEvents(query, toolUseID string, results *WebSearchRe
{ {
"type": "content_block_start", "type": "content_block_start",
"index": startIndex + 1, "index": startIndex + 1,
"content_block": map[string]interface{}{ "content_block": map[string]any{
"type": "web_search_tool_result", "type": "web_search_tool_result",
"content": searchContent, "content": searchContent,
}, },
@@ -96,20 +96,20 @@ func AnalyzeBufferedStream(chunks [][]byte) BufferedStreamResult {
continue continue
} }
var event map[string]interface{} var event map[string]any
if err := json.Unmarshal([]byte(payload), &event); err != nil { if err := json.Unmarshal([]byte(payload), &event); err != nil {
continue continue
} }
switch eventType, _ := event["type"].(string); eventType { switch eventType, _ := event["type"].(string); eventType {
case "message_delta": case "message_delta":
if delta, ok := event["delta"].(map[string]interface{}); ok { if delta, ok := event["delta"].(map[string]any); ok {
if stopReason, ok := delta["stop_reason"].(string); ok && strings.TrimSpace(stopReason) != "" { if stopReason, ok := delta["stop_reason"].(string); ok && strings.TrimSpace(stopReason) != "" {
result.StopReason = stopReason result.StopReason = stopReason
} }
} }
case "content_block_start": case "content_block_start":
contentBlock, ok := event["content_block"].(map[string]interface{}) contentBlock, ok := event["content_block"].(map[string]any)
if !ok { if !ok {
continue continue
} }
@@ -130,7 +130,7 @@ func AnalyzeBufferedStream(chunks [][]byte) BufferedStreamResult {
if currentToolName == "" { if currentToolName == "" {
continue continue
} }
delta, ok := event["delta"].(map[string]interface{}) delta, ok := event["delta"].(map[string]any)
if !ok { if !ok {
continue continue
} }
@@ -139,7 +139,7 @@ func AnalyzeBufferedStream(chunks [][]byte) BufferedStreamResult {
continue continue
} }
if partialJSON, ok := delta["partial_json"].(string); ok { if partialJSON, ok := delta["partial_json"].(string); ok {
toolInputBuilder.WriteString(partialJSON) _, _ = toolInputBuilder.WriteString(partialJSON)
} }
case "content_block_stop": case "content_block_stop":
if !isWebSearchToolName(currentToolName, "") { if !isWebSearchToolName(currentToolName, "") {
@@ -191,7 +191,7 @@ func MaxContentBlockIndex(chunks [][]byte) int {
if payload == "" || payload == "[DONE]" { if payload == "" || payload == "[DONE]" {
continue continue
} }
var event map[string]interface{} var event map[string]any
if err := json.Unmarshal([]byte(payload), &event); err != nil { if err := json.Unmarshal([]byte(payload), &event); err != nil {
continue continue
} }
@@ -221,7 +221,7 @@ func filterSSEChunk(chunk []byte, webSearchToolUseIndex, indexOffset int) ([]byt
continue continue
} }
} }
builder.WriteString(line + "\n") _, _ = builder.WriteString(line + "\n")
hasContent = true hasContent = true
continue continue
} }
@@ -238,12 +238,12 @@ func filterSSEChunk(chunk []byte, webSearchToolUseIndex, indexOffset int) ([]byt
if adjusted == "" { if adjusted == "" {
continue continue
} }
builder.WriteString("data: " + adjusted + "\n") _, _ = builder.WriteString("data: " + adjusted + "\n")
hasContent = true hasContent = true
continue continue
} }
builder.WriteString(line + "\n") _, _ = builder.WriteString(line + "\n")
if strings.TrimSpace(line) != "" { if strings.TrimSpace(line) != "" {
hasContent = true hasContent = true
} }
@@ -259,7 +259,7 @@ func shouldSuppressEventPayload(payload string, webSearchToolUseIndex int) bool
if payload == "" { if payload == "" {
return false return false
} }
var event map[string]interface{} var event map[string]any
if err := json.Unmarshal([]byte(payload), &event); err != nil { if err := json.Unmarshal([]byte(payload), &event); err != nil {
return false return false
} }
@@ -280,7 +280,7 @@ func adjustEventPayload(payload string, indexOffset int) string {
if payload == "" || indexOffset == 0 { if payload == "" || indexOffset == 0 {
return payload return payload
} }
var event map[string]interface{} var event map[string]any
if err := json.Unmarshal([]byte(payload), &event); err != nil { if err := json.Unmarshal([]byte(payload), &event); err != nil {
return payload return payload
} }
+1 -1
View File
@@ -185,7 +185,7 @@ func (s *Store) ReserveRequest(ctx context.Context, tokenKey string) (time.Durat
if err != nil { if err != nil {
return 0, fmt.Errorf("kiro cooldown reserve request: %w", err) return 0, fmt.Errorf("kiro cooldown reserve request: %w", err)
} }
parts, ok := values.([]interface{}) parts, ok := values.([]any)
if !ok || len(parts) != 3 { if !ok || len(parts) != 3 {
return 0, fmt.Errorf("kiro cooldown reserve request: unexpected response %T", values) return 0, fmt.Errorf("kiro cooldown reserve request: unexpected response %T", values)
} }
@@ -84,7 +84,7 @@ func buildKiroRequestID(resp *http.Response) string {
return strings.TrimSpace(resp.Header.Get("x-amz-request-id")) return strings.TrimSpace(resp.Header.Get("x-amz-request-id"))
} }
func isKiroInvalidModelIDBody(respBody []byte) bool { func isKiroInvalidModelIDBody(respBody []byte) bool { //nolint:unused // exercised by internal tests for error classification.
var payload struct { var payload struct {
Reason string `json:"reason"` Reason string `json:"reason"`
Message string `json:"message"` Message string `json:"message"`
+1 -1
View File
@@ -491,7 +491,7 @@ func buildKiroEndpoints(account *Account) []kiroEndpointConfig {
} }
} }
func buildKiroPayloadForAccount(ctx context.Context, account *Account, anthropicBody []byte, modelID, token, requestModel string, headers http.Header) ([]byte, error) { func buildKiroPayloadForAccount(ctx context.Context, account *Account, anthropicBody []byte, modelID, token, requestModel string, headers http.Header) ([]byte, error) { //nolint:unused // exercised by package tests as a narrow payload helper.
result, err := buildKiroPayloadForAccountWithRepo(ctx, nil, account, anthropicBody, modelID, token, requestModel, headers) result, err := buildKiroPayloadForAccountWithRepo(ctx, nil, account, anthropicBody, modelID, token, requestModel, headers)
if err != nil { if err != nil {
return nil, err return nil, err
+3 -3
View File
@@ -357,11 +357,11 @@ func buildKiroWebSearchMCPRequest(query string) kiropkg.MCPRequest {
ID: fmt.Sprintf("web_search_%s", kiropkg.GenerateToolUseID()), ID: fmt.Sprintf("web_search_%s", kiropkg.GenerateToolUseID()),
JSONRPC: "2.0", JSONRPC: "2.0",
Method: "tools/call", Method: "tools/call",
Params: map[string]interface{}{ Params: map[string]any{
"name": "web_search", "name": "web_search",
"arguments": map[string]interface{}{ "arguments": map[string]any{
"query": query, "query": query,
"_meta": map[string]interface{}{ "_meta": map[string]any{
"_isValid": true, "_isValid": true,
"_activePath": []string{"query"}, "_activePath": []string{"query"},
"_completedPaths": [][]string{{"query"}}, "_completedPaths": [][]string{{"query"}},