This repository has been archived on 2026-08-12. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Cyrene/backend/ai-core/internal/tools/gateway_client.go
T
AskaEth fea67d05eb fix: reminder工具401认证 — 路由从JWT组迁到internal组
- Gateway新增 /api/v1/internal/reminders (GET/POST/DELETE)
- 使用 X-Internal-Token 认证,不再需要JWT
- GatewayClient URL改为 /api/v1/internal/reminders

Co-Authored-By: Claude <noreply@anthropic.com>
2026-06-23 20:19:23 +08:00

124 lines
3.6 KiB
Go

package tools
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// GatewayClient is a lightweight HTTP client for calling Gateway internal APIs
// (reminders, schedules, etc.) from ai-core tools.
type GatewayClient struct {
baseURL string
internalToken string
httpClient *http.Client
}
// NewGatewayClient creates a new Gateway API client.
func NewGatewayClient(baseURL, internalToken string) *GatewayClient {
return &GatewayClient{
baseURL: baseURL,
internalToken: internalToken,
httpClient: &http.Client{Timeout: 10 * time.Second},
}
}
// Reminder represents a reminder from the Gateway API.
type Reminder struct {
ID string `json:"id"`
Title string `json:"title"`
Description string `json:"description"`
RemindAt string `json:"remind_at"`
Status string `json:"status"`
RepeatType string `json:"repeat_type"`
}
// CreateReminder calls POST /api/v1/internal/reminders on the Gateway.
func (c *GatewayClient) CreateReminder(ctx context.Context, userID, title, description, remindAt, repeatType, sessionID string) (*Reminder, error) {
body := map[string]interface{}{
"user_id": userID,
"title": title,
"description": description,
"remind_at": remindAt,
"repeat_type": repeatType,
"session_id": sessionID,
}
reqBody, _ := json.Marshal(body)
req, err := http.NewRequestWithContext(ctx, "POST", c.baseURL+"/api/v1/internal/reminders", bytes.NewReader(reqBody))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-Internal-Token", c.internalToken)
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("gateway request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
bodyBytes, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("gateway returned %d: %s", resp.StatusCode, string(bodyBytes))
}
var reminder Reminder
if err := json.NewDecoder(resp.Body).Decode(&reminder); err != nil {
return nil, fmt.Errorf("decode response: %w", err)
}
return &reminder, nil
}
// ListReminders calls GET /api/v1/internal/reminders on the Gateway.
func (c *GatewayClient) ListReminders(ctx context.Context, userID, status string, limit int) ([]Reminder, error) {
url := fmt.Sprintf("%s/api/v1/internal/reminders?user_id=%s&status=%s&limit=%d", c.baseURL, userID, status, limit)
req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil {
return nil, err
}
req.Header.Set("X-Internal-Token", c.internalToken)
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("gateway request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
bodyBytes, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("gateway returned %d: %s", resp.StatusCode, string(bodyBytes))
}
var reminders []Reminder
if err := json.NewDecoder(resp.Body).Decode(&reminders); err != nil {
return nil, fmt.Errorf("decode response: %w", err)
}
return reminders, nil
}
// DeleteReminder calls DELETE /api/v1/internal/reminders/:id on the Gateway.
func (c *GatewayClient) DeleteReminder(ctx context.Context, reminderID string) error {
req, err := http.NewRequestWithContext(ctx, "DELETE", c.baseURL+"/api/v1/internal/reminders/"+reminderID, nil)
if err != nil {
return err
}
req.Header.Set("X-Internal-Token", c.internalToken)
resp, err := c.httpClient.Do(req)
if err != nil {
return fmt.Errorf("gateway request failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode >= 400 {
bodyBytes, _ := io.ReadAll(resp.Body)
return fmt.Errorf("gateway returned %d: %s", resp.StatusCode, string(bodyBytes))
}
return nil
}