Files
opsxdb/server/internal/aitools/audit.go
T
logan 2336c9433c feat(ai): Agent SSE + Anthropic/responses tools + P1 确认写
- Agent 支持 SSE(步骤边推、正文分块),JSON 非流式 fallback
- tool calling 覆盖 openai-chat / anthropic / responses(单测解析回灌)
- P1:mcp.json mode=read_write 才可写;需 confirm_danger;Agent 剥离模型自带令牌
- GET /api/ai/mcp-status、POST /api/ai/agent/confirm;审计 source=mcp|agent
2026-10-15 13:00:40 +08:00

58 lines
1.3 KiB
Go

package aitools
import (
"encoding/json"
"os"
"path/filepath"
"sync"
"time"
)
// AuditEntry MCP/Agent 工具审计;不含密码与大结果全文。 // Logan.Li
type AuditEntry struct {
Time string `json:"time"`
Tool string `json:"tool"`
ConnectionID string `json:"connection_id,omitempty"`
Mode string `json:"mode"`
Source string `json:"source,omitempty"` // mcp | agent
OK bool `json:"ok"`
Summary string `json:"summary,omitempty"`
Error string `json:"error,omitempty"`
}
var auditMu sync.Mutex
func AuditPath() (string, error) {
dir, err := opsxdbDir()
if err != nil {
return "", err
}
return filepath.Join(dir, "logs", "mcp-audit.jsonl"), nil
}
// AppendAudit 追加一行 JSONL;失败静默(不影响工具主路径)。
func AppendAudit(e AuditEntry) {
if e.Time == "" {
e.Time = time.Now().Format(time.RFC3339)
}
path, err := AuditPath()
if err != nil {
return
}
auditMu.Lock()
defer auditMu.Unlock()
if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
return
}
b, err := json.Marshal(e)
if err != nil {
return
}
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
if err != nil {
return
}
defer f.Close()
_, _ = f.Write(append(b, '\n'))
}