l-ai-chat-client-go/participants.go
Kaien ba2fa0aa2d feat: participant SDK APIs and bounded cache
Wrap Stage 7.1 participant RPCs and add a version-aware ParticipantCache
with batch hydration helpers for agents and services.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-10 13:49:19 +03:00

109 lines
3.6 KiB
Go

package chatclient
import (
"context"
"fmt"
pb "gitea.fe.kaien.ru/kaien/l-ai-chat-proto"
)
// GetParticipant returns one participant by author_id.
func (c *Client) GetParticipant(ctx context.Context, authorID string) (*pb.Participant, error) {
if err := c.checkOpen(); err != nil {
return nil, err
}
if authorID == "" {
return nil, fmt.Errorf("%w: author id is required", ErrInvalidConfig)
}
return c.api.GetParticipant(ctx, &pb.GetParticipantRequest{AuthorId: authorID})
}
// BatchGetParticipants fetches participants for the given author IDs
// (server deduplicates and bounds the batch).
func (c *Client) BatchGetParticipants(ctx context.Context, authorIDs []string) ([]*pb.Participant, error) {
if err := c.checkOpen(); err != nil {
return nil, err
}
resp, err := c.api.BatchGetParticipants(ctx, &pb.BatchGetParticipantsRequest{AuthorIds: authorIDs})
if err != nil {
return nil, err
}
return resp.GetParticipants(), nil
}
// ListTopicParticipants returns the durable topic membership roster.
func (c *Client) ListTopicParticipants(ctx context.Context, topicID string) ([]*pb.Participant, error) {
if err := c.checkOpen(); err != nil {
return nil, err
}
if topicID == "" {
return nil, fmt.Errorf("%w: topic id is required", ErrInvalidConfig)
}
resp, err := c.api.ListTopicParticipants(ctx, &pb.ListTopicParticipantsRequest{TopicId: topicID})
if err != nil {
return nil, err
}
return resp.GetParticipants(), nil
}
// GetMyParticipant returns the authenticated caller's participant profile.
func (c *Client) GetMyParticipant(ctx context.Context) (*pb.Participant, error) {
if err := c.checkOpen(); err != nil {
return nil, err
}
return c.api.GetMyParticipant(ctx, &pb.GetMyParticipantRequest{})
}
// RegisterSelfProfileRequest carries mutable public agent profile fields only.
// Identity (author_id / agent_id) is derived server-side from the service token.
type RegisterSelfProfileRequest struct {
DisplayName string
Aliases map[string]string
Role string
Bio string
StatusText string
}
// RegisterSelfProfile upserts the authenticated agent's public profile and
// returns the authoritative Participant (including canonical author_id).
func (c *Client) RegisterSelfProfile(ctx context.Context, req RegisterSelfProfileRequest) (*pb.Participant, error) {
if err := c.checkOpen(); err != nil {
return nil, err
}
return c.api.RegisterSelfProfile(ctx, &pb.RegisterSelfProfileRequest{
DisplayName: req.DisplayName,
Aliases: req.Aliases,
Role: req.Role,
Bio: req.Bio,
StatusText: req.StatusText,
})
}
// SyncMyTopicMemberships replaces the authenticated agent's durable topic
// memberships with the full desired set.
func (c *Client) SyncMyTopicMemberships(ctx context.Context, topicIDs []string) (*pb.SyncMyTopicMembershipsResponse, error) {
if err := c.checkOpen(); err != nil {
return nil, err
}
return c.api.SyncMyTopicMemberships(ctx, &pb.SyncMyTopicMembershipsRequest{TopicIds: topicIDs})
}
// UploadSelfAvatar replaces the authenticated agent's avatar bytes.
func (c *Client) UploadSelfAvatar(ctx context.Context, content []byte, contentType string) (*pb.Participant, error) {
if err := c.checkOpen(); err != nil {
return nil, err
}
return c.api.UploadSelfAvatar(ctx, &pb.UploadSelfAvatarRequest{
Content: content,
ContentType: contentType,
})
}
// DeleteSelfAvatar clears the authenticated agent's avatar.
func (c *Client) DeleteSelfAvatar(ctx context.Context) (*pb.Participant, error) {
if err := c.checkOpen(); err != nil {
return nil, err
}
return c.api.DeleteSelfAvatar(ctx, &pb.DeleteSelfAvatarRequest{})
}