- 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
118 lines
4.2 KiB
Go
118 lines
4.2 KiB
Go
package aitools
|
||
|
||
// ToolSpec 工具元数据:MCP stdio 与侧栏 Agent(OpenAI tools)共用同一份契约。 // Logan.Li
|
||
type ToolSpec struct {
|
||
Name string
|
||
Description string
|
||
Properties map[string]any
|
||
Required []string
|
||
}
|
||
|
||
// ToolSpecs P0 七工具 schema(顺序与 ToolNames 一致)。
|
||
func ToolSpecs() []ToolSpec {
|
||
connID := map[string]any{"type": "string", "description": "Saved connection id from opsxdb_list_connections"}
|
||
database := map[string]any{"type": "string", "description": "Database / schema / Redis DB index"}
|
||
return []ToolSpec{
|
||
{
|
||
Name: ToolListConnections,
|
||
Description: "List whitelisted OpsxDB connections (id/name/driver/host/port/database; never passwords).",
|
||
Properties: map[string]any{},
|
||
},
|
||
{
|
||
Name: ToolListDatabases,
|
||
Description: "List databases for a connection.",
|
||
Properties: map[string]any{"connection_id": connID},
|
||
Required: []string{"connection_id"},
|
||
},
|
||
{
|
||
Name: ToolListTables,
|
||
Description: "List tables/views (or engine equivalents) in a database.",
|
||
Properties: map[string]any{"connection_id": connID, "database": database},
|
||
Required: []string{"connection_id"},
|
||
},
|
||
{
|
||
Name: ToolDescribeTable,
|
||
Description: "Describe columns and metadata for a table.",
|
||
Properties: map[string]any{
|
||
"connection_id": connID,
|
||
"database": database,
|
||
"table": map[string]any{"type": "string", "description": "Table name"},
|
||
},
|
||
Required: []string{"connection_id", "table"},
|
||
},
|
||
{
|
||
Name: ToolGetSchemaContext,
|
||
Description: "Compact schema text for LLM context (capped ~4k chars).",
|
||
Properties: map[string]any{
|
||
"connection_id": connID,
|
||
"database": database,
|
||
"max_tables": map[string]any{"type": "integer", "description": "Max tables to include (default 40)"},
|
||
},
|
||
Required: []string{"connection_id"},
|
||
},
|
||
{
|
||
Name: ToolExecuteQuery,
|
||
Description: "Execute SQL. Default read-only (SELECT/SHOW/EXPLAIN/WITH…SELECT). Writes require mcp.json mode=read_write AND confirm_danger=true (never auto). Default limit 100, max 500.",
|
||
Properties: map[string]any{
|
||
"connection_id": connID,
|
||
"sql": map[string]any{"type": "string", "description": "SQL statement"},
|
||
"database": database,
|
||
"limit": map[string]any{"type": "integer", "description": "Row limit (default 100, max 500)"},
|
||
"confirm_danger": map[string]any{"type": "boolean", "description": "Required for writes when mode=read_write; Agent UI sets this only after user confirms"},
|
||
},
|
||
Required: []string{"connection_id", "sql"},
|
||
},
|
||
{
|
||
Name: ToolExecuteRedisCommand,
|
||
Description: "Execute Redis command. Default read-only whitelist. Writes require mode=read_write AND confirm_danger=true. FLUSH*/KEYS/CONFIG always denied.",
|
||
Properties: map[string]any{
|
||
"connection_id": connID,
|
||
"command": map[string]any{"type": "string", "description": "Single Redis command line"},
|
||
"database": database,
|
||
"confirm_danger": map[string]any{"type": "boolean", "description": "Required for writes when mode=read_write"},
|
||
},
|
||
Required: []string{"connection_id", "command"},
|
||
},
|
||
}
|
||
}
|
||
|
||
// InputSchema 返回 JSON Schema object(MCP raw schema / OpenAI parameters)。
|
||
func (t ToolSpec) InputSchema() map[string]any {
|
||
schema := map[string]any{
|
||
"type": "object",
|
||
"properties": t.Properties,
|
||
}
|
||
if len(t.Required) > 0 {
|
||
schema["required"] = t.Required
|
||
}
|
||
if t.Properties == nil {
|
||
schema["properties"] = map[string]any{}
|
||
}
|
||
return schema
|
||
}
|
||
|
||
// OpenAITool OpenAI chat.completions tools[] 一项。
|
||
type OpenAITool struct {
|
||
Type string `json:"type"`
|
||
Function struct {
|
||
Name string `json:"name"`
|
||
Description string `json:"description"`
|
||
Parameters map[string]any `json:"parameters"`
|
||
} `json:"function"`
|
||
}
|
||
|
||
// OpenAITools 供 Agent / DeepSeek 等 openai-chat 兼容协议挂载。
|
||
func OpenAITools() []OpenAITool {
|
||
specs := ToolSpecs()
|
||
out := make([]OpenAITool, 0, len(specs))
|
||
for _, s := range specs {
|
||
var t OpenAITool
|
||
t.Type = "function"
|
||
t.Function.Name = s.Name
|
||
t.Function.Description = s.Description
|
||
t.Function.Parameters = s.InputSchema()
|
||
out = append(out, t)
|
||
}
|
||
return out
|
||
}
|