fix: use common.Marshal/Unmarshal per Rule 1 + telegram null safety
- model/user.go: replace json.Unmarshal/Marshal with common.* wrapper functions as required by project Rule 1 (3 occurrences) - relay/channel/claude/relay-claude.go: replace 3 json.* calls with common.* (tool call args unmarshal, response marshal) - relay/channel/gemini/relay-gemini.go: replace 5 json.* calls with common.* (content parsing, function args, response marshal) - adapters/telegram/index.ts: add optional chaining on callback query message.chat.id and null coalescing on message.text to prevent crash when callback message is undefined Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -718,7 +718,7 @@ bot.on('callback_query:data', async (ctx) => {
|
|||||||
|
|
||||||
const requestId = parts[1]!
|
const requestId = parts[1]!
|
||||||
const allowed = parts[2] === 'yes'
|
const allowed = parts[2] === 'yes'
|
||||||
const chatId = String(ctx.callbackQuery.message?.chat.id)
|
const chatId = String(ctx.callbackQuery.message?.chat?.id)
|
||||||
|
|
||||||
bridge.sendPermissionResponse(chatId, requestId, allowed)
|
bridge.sendPermissionResponse(chatId, requestId, allowed)
|
||||||
const runtime = getRuntimeState(chatId)
|
const runtime = getRuntimeState(chatId)
|
||||||
@@ -727,7 +727,7 @@ bot.on('callback_query:data', async (ctx) => {
|
|||||||
const statusText = allowed ? '✅ 已允许' : '❌ 已拒绝'
|
const statusText = allowed ? '✅ 已允许' : '❌ 已拒绝'
|
||||||
try {
|
try {
|
||||||
await ctx.editMessageText(
|
await ctx.editMessageText(
|
||||||
ctx.callbackQuery.message?.text + `\n\n${statusText}`,
|
(ctx.callbackQuery.message?.text ?? '') + `\n\n${statusText}`,
|
||||||
)
|
)
|
||||||
} catch { /* ignore */ }
|
} catch { /* ignore */ }
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -81,7 +80,7 @@ func (user *User) SetAccessToken(token string) {
|
|||||||
func (user *User) GetSetting() dto.UserSetting {
|
func (user *User) GetSetting() dto.UserSetting {
|
||||||
setting := dto.UserSetting{}
|
setting := dto.UserSetting{}
|
||||||
if user.Setting != "" {
|
if user.Setting != "" {
|
||||||
err := json.Unmarshal([]byte(user.Setting), &setting)
|
err := common.Unmarshal([]byte(user.Setting), &setting)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.SysLog("failed to unmarshal setting: " + err.Error())
|
common.SysLog("failed to unmarshal setting: " + err.Error())
|
||||||
}
|
}
|
||||||
@@ -90,7 +89,7 @@ func (user *User) GetSetting() dto.UserSetting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (user *User) SetSetting(setting dto.UserSetting) {
|
func (user *User) SetSetting(setting dto.UserSetting) {
|
||||||
settingBytes, err := json.Marshal(setting)
|
settingBytes, err := common.Marshal(setting)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.SysLog("failed to marshal setting: " + err.Error())
|
common.SysLog("failed to marshal setting: " + err.Error())
|
||||||
return
|
return
|
||||||
@@ -151,7 +150,7 @@ func generateDefaultSidebarConfigForRole(userRole int) string {
|
|||||||
// 普通用户不包含admin区域
|
// 普通用户不包含admin区域
|
||||||
|
|
||||||
// 转换为JSON字符串
|
// 转换为JSON字符串
|
||||||
configBytes, err := json.Marshal(defaultConfig)
|
configBytes, err := common.Marshal(defaultConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
common.SysLog("生成默认边栏配置失败: " + err.Error())
|
common.SysLog("生成默认边栏配置失败: " + err.Error())
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ func RequestOpenAI2ClaudeMessage(c *gin.Context, textRequest dto.GeneralOpenAIRe
|
|||||||
if message.ToolCalls != nil {
|
if message.ToolCalls != nil {
|
||||||
for _, toolCall := range message.ParseToolCalls() {
|
for _, toolCall := range message.ParseToolCalls() {
|
||||||
inputObj := make(map[string]any)
|
inputObj := make(map[string]any)
|
||||||
if err := json.Unmarshal([]byte(toolCall.Function.Arguments), &inputObj); err != nil {
|
if err := common.Unmarshal([]byte(toolCall.Function.Arguments), &inputObj); err != nil {
|
||||||
common.SysLog("tool call function arguments is not a map[string]any: " + fmt.Sprintf("%v", toolCall.Function.Arguments))
|
common.SysLog("tool call function arguments is not a map[string]any: " + fmt.Sprintf("%v", toolCall.Function.Arguments))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -540,7 +540,7 @@ func ResponseClaude2OpenAI(claudeResponse *dto.ClaudeResponse) *dto.OpenAITextRe
|
|||||||
for _, message := range claudeResponse.Content {
|
for _, message := range claudeResponse.Content {
|
||||||
switch message.Type {
|
switch message.Type {
|
||||||
case "tool_use":
|
case "tool_use":
|
||||||
args, _ := json.Marshal(message.Input)
|
args, _ := common.Marshal(message.Input)
|
||||||
tools = append(tools, dto.ToolCallResponse{
|
tools = append(tools, dto.ToolCallResponse{
|
||||||
ID: message.Id,
|
ID: message.Id,
|
||||||
Type: "function", // compatible with other OpenAI derivative applications
|
Type: "function", // compatible with other OpenAI derivative applications
|
||||||
@@ -919,7 +919,7 @@ func HandleClaudeResponseData(c *gin.Context, info *relaycommon.RelayInfo, claud
|
|||||||
case types.RelayFormatOpenAI:
|
case types.RelayFormatOpenAI:
|
||||||
openaiResponse := ResponseClaude2OpenAI(&claudeResponse)
|
openaiResponse := ResponseClaude2OpenAI(&claudeResponse)
|
||||||
openaiResponse.Usage = buildOpenAIStyleUsageFromClaudeUsage(claudeInfo.Usage)
|
openaiResponse.Usage = buildOpenAIStyleUsageFromClaudeUsage(claudeInfo.Usage)
|
||||||
responseData, err = json.Marshal(openaiResponse)
|
responseData, err = common.Marshal(openaiResponse)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return types.NewError(err, types.ErrorCodeBadResponseBody)
|
return types.NewError(err, types.ErrorCodeBadResponseBody)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -467,10 +467,10 @@ func CovertOpenAI2Gemini(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
|
|||||||
contentStr := message.StringContent()
|
contentStr := message.StringContent()
|
||||||
|
|
||||||
// 1. 尝试解析为 JSON 对象
|
// 1. 尝试解析为 JSON 对象
|
||||||
if err := json.Unmarshal([]byte(contentStr), &contentMap); err != nil {
|
if err := common.Unmarshal([]byte(contentStr), &contentMap); err != nil {
|
||||||
// 2. 如果失败,尝试解析为 JSON 数组
|
// 2. 如果失败,尝试解析为 JSON 数组
|
||||||
var contentSlice []interface{}
|
var contentSlice []interface{}
|
||||||
if err := json.Unmarshal([]byte(contentStr), &contentSlice); err == nil {
|
if err := common.Unmarshal([]byte(contentStr), &contentSlice); err == nil {
|
||||||
// 如果是数组,包装成对象
|
// 如果是数组,包装成对象
|
||||||
contentMap = map[string]interface{}{"result": contentSlice}
|
contentMap = map[string]interface{}{"result": contentSlice}
|
||||||
} else {
|
} else {
|
||||||
@@ -502,7 +502,7 @@ func CovertOpenAI2Gemini(c *gin.Context, textRequest dto.GeneralOpenAIRequest, i
|
|||||||
for _, call := range message.ParseToolCalls() {
|
for _, call := range message.ParseToolCalls() {
|
||||||
args := map[string]interface{}{}
|
args := map[string]interface{}{}
|
||||||
if call.Function.Arguments != "" {
|
if call.Function.Arguments != "" {
|
||||||
if json.Unmarshal([]byte(call.Function.Arguments), &args) != nil {
|
if common.Unmarshal([]byte(call.Function.Arguments), &args) != nil {
|
||||||
return nil, fmt.Errorf("invalid arguments for function %s, args: %s", call.Function.Name, call.Function.Arguments)
|
return nil, fmt.Errorf("invalid arguments for function %s, args: %s", call.Function.Name, call.Function.Arguments)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -994,9 +994,7 @@ func unescapeMapOrSlice(data interface{}) interface{} {
|
|||||||
func getResponseToolCall(item *dto.GeminiPart) *dto.ToolCallResponse {
|
func getResponseToolCall(item *dto.GeminiPart) *dto.ToolCallResponse {
|
||||||
var argsBytes []byte
|
var argsBytes []byte
|
||||||
var err error
|
var err error
|
||||||
// 移除 unescapeMapOrSlice 调用,直接使用 json.Marshal
|
argsBytes, err = common.Marshal(item.FunctionCall.Arguments)
|
||||||
// JSON 序列化/反序列化已经正确处理了转义字符
|
|
||||||
argsBytes, err = json.Marshal(item.FunctionCall.Arguments)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -1569,7 +1567,7 @@ func GeminiImageHandler(c *gin.Context, info *relaycommon.RelayInfo, resp *http.
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonResponse, jsonErr := json.Marshal(openAIResponse)
|
jsonResponse, jsonErr := common.Marshal(openAIResponse)
|
||||||
if jsonErr != nil {
|
if jsonErr != nil {
|
||||||
return nil, types.NewError(jsonErr, types.ErrorCodeBadResponseBody)
|
return nil, types.NewError(jsonErr, types.ErrorCodeBadResponseBody)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user