feat: ASR语音转写管线 + 群聊身份混淆修复

- 新增ASR语音识别管线: QQ语音→下载音频→qwen3-asr-flash转录→注入用户消息
- 模型名称全部从models.json路由获取,无硬编码
- 修复群聊中AI将非管理员用户误称为管理员昵称(叶酱)的问题
  - 助手回复缓存时标注[回复 昵称 (UID)],防止对话历史中身份混淆
  - 群聊上下文指令改为肯定性表述,移除具体名称提及
- trace面板时间戳改为YYYY-MM-DD HH:MM:SS格式,耗时统一显示为秒
- 修复Go time.Duration纳秒值在前端显示问题(Duration/1e6转毫秒)
- 新增video_tool插件模板
- 优化OpenAI adapter reasoning_content处理

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-31 16:46:47 +08:00
parent d112fdd540
commit a9c79d7887
16 changed files with 780 additions and 67 deletions
+28
View File
@@ -10,6 +10,24 @@ import (
"git.yeij.top/AskaEth/Cyrene/pkg/plugins/sdk"
)
// CtxKeyIsAdmin is the context key for the admin flag.
type ctxKey string
const CtxKeyIsAdmin ctxKey = "isAdmin"
// adminOnlyTools lists tools that require admin permission to execute.
var adminOnlyTools = map[string]bool{
"host_exec": true,
"os_exec": true,
"host_file": true,
}
// IsAdminFromCtx returns true if the context carries an admin flag.
func IsAdminFromCtx(ctx context.Context) bool {
v, _ := ctx.Value(CtxKeyIsAdmin).(bool)
return v
}
// CallLogRecord 工具调用记录
type CallLogRecord struct {
CallID string `json:"call_id"`
@@ -197,6 +215,16 @@ func (r *ToolRegistry) Execute(ctx context.Context, toolID string, args map[stri
return &sdk.ToolResult{Success: false, Error: err.Error()}, nil
}
// Admin-only tools: deny non-admin callers.
if adminOnlyTools[toolID] && !IsAdminFromCtx(ctx) {
errMsg := fmt.Sprintf("工具 %s 仅限管理员使用", toolID)
r.callLog.push(CallLogRecord{
ToolName: toolID, Error: errMsg, Success: false,
DurationMs: int(time.Since(startTime).Milliseconds()),
})
return &sdk.ToolResult{Success: false, Error: errMsg}, nil
}
result, err := tool.Execute(ctx, args)
durationMs := int(time.Since(startTime).Milliseconds())