xworkmate-bridge/internal/shared/rpc.go
2026-05-07 17:47:27 +08:00

118 lines
2.7 KiB
Go

package shared
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
)
type RPCRequest struct {
JSONRPC string `json:"jsonrpc,omitempty"`
Type string `json:"type,omitempty"`
ID any `json:"id,omitempty"`
Method string `json:"method,omitempty"`
Params map[string]any `json:"params,omitempty"`
}
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data any `json:"data,omitempty"`
}
type ToolCallParams struct {
Name string `json:"name"`
Arguments map[string]any `json:"arguments"`
}
func DecodeRPCRequest(payload []byte) (RPCRequest, error) {
var request RPCRequest
if err := json.Unmarshal(payload, &request); err != nil {
return RPCRequest{}, fmt.Errorf("invalid json: %w", err)
}
if strings.TrimSpace(request.Method) == "" {
return RPCRequest{}, errors.New("missing method")
}
if request.Params == nil {
request.Params = map[string]any{}
}
return request, nil
}
func WriteSSE(w http.ResponseWriter, payload map[string]any) error {
encoded, _ := json.Marshal(payload)
_, err := fmt.Fprintf(w, "data: %s\n\n", encoded)
return err
}
func ResultEnvelope(id any, result map[string]any) map[string]any {
return map[string]any{
"jsonrpc": "2.0",
"id": id,
"result": result,
// Backward compatibility with legacy GatewayRuntime
"type": "res",
"ok": true,
"payload": result,
"seq": 0,
}
}
func ErrorEnvelope(id any, code int, message string, data ...any) map[string]any {
errPayload := map[string]any{
"code": code,
"message": message,
}
if len(data) > 0 && data[0] != nil {
errPayload["data"] = data[0]
}
return map[string]any{
"jsonrpc": "2.0",
"id": id,
"error": errPayload,
// Backward compatibility with legacy GatewayRuntime
"type": "res",
"ok": false,
"payload": nil,
"seq": 0,
}
}
func NotificationEnvelope(method string, params map[string]any) map[string]any {
return map[string]any{
"jsonrpc": "2.0",
"method": method,
"params": params,
// Backward compatibility with legacy GatewayRuntime
"type": "event",
"event": method,
"payload": params,
"seq": 0,
}
}
func ErrorResponse(id any, code int, message string) map[string]any {
return ErrorEnvelope(id, code, message)
}
func ToolTextResult(id any, content string) map[string]any {
result := map[string]any{
"content": []map[string]any{
{"type": "text", "text": content},
},
}
return ResultEnvelope(id, result)
}
func ToolErrorResult(id any, err error) map[string]any {
result := map[string]any{
"content": []map[string]any{
{"type": "text", "text": fmt.Sprintf("Error: %v", err)},
},
"isError": true,
}
return ResultEnvelope(id, result)
}