bots

package
v0.21.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 5, 2026 License: AGPL-3.0 Imports: 20 Imported by: 0

Documentation

Index

Constants

View Source
const (
	PermissionChat           = "chat"
	PermissionWorkspaceRead  = "workspace_read"
	PermissionWorkspaceWrite = "workspace_write"
	PermissionWorkspaceExec  = "workspace_exec"
	PermissionManage         = "manage"
)

Grant permission scopes. manage implies every scoped permission; workspace_write implies workspace_read.

View Source
const (
	GrantSubjectUser     = "user"
	GrantSubjectEveryone = "everyone"
)

Grant subject types.

View Source
const (
	NameReasonInvalid  = "invalid"
	NameReasonReserved = "reserved"
	NameReasonTaken    = "taken"
)

reasons returned by ValidateName / CheckNameAvailability.

View Source
const (
	WorkspaceObservedAbsent  = "absent"
	WorkspaceObservedRunning = "running"
	WorkspaceObservedFailed  = "failed"
	WorkspacePhaseBootstrap  = "bootstrap"
)

Workspace observation values the bots service branches on.

View Source
const (
	BotStatusCreating = "creating"
	BotStatusReady    = "ready"
	BotStatusDeleting = "deleting"
	// BotStatusFailed marks a bot whose workspace never became ready. It is
	// derived by the workspace reconciler; the bot stays visible so the user
	// can retry the workspace or delete the bot.
	BotStatusFailed = "failed"
)
View Source
const (
	BotCheckStateOK      = "ok"
	BotCheckStateIssue   = "issue"
	BotCheckStateUnknown = "unknown"
)
View Source
const (
	BotCheckStatusOK      = "ok"
	BotCheckStatusWarn    = "warn"
	BotCheckStatusError   = "error"
	BotCheckStatusUnknown = "unknown"
)
View Source
const (
	BotCheckTypeContainerInit   = "container.init"
	BotCheckTypeContainerRecord = "container.record"
	BotCheckTypeContainerTask   = "container.task"
	BotCheckTypeContainerData   = "container.data_path"
	BotCheckTypeDelete          = "bot.delete"
	BotCheckTypeMCPConnection   = "mcp.connection"
	BotCheckTypeChannelConn     = "channel.connection"
)

Variables

View Source
var (
	// ErrGrantNotFound indicates the grant does not exist for the bot.
	ErrGrantNotFound = errors.New("bot user grant not found")
	// ErrInvalidPermission indicates an unknown or empty permission set.
	ErrInvalidPermission = errors.New("invalid permission")
	// ErrInvalidGrantSubject indicates an unknown subject type.
	ErrInvalidGrantSubject = errors.New("invalid grant subject")
	// ErrGrantUserRequired indicates a user grant is missing its user id.
	ErrGrantUserRequired = errors.New("user id is required for a user grant")
	// ErrGrantOwnerConflict indicates an attempt to grant access to the bot owner.
	ErrGrantOwnerConflict = errors.New("the bot owner already has full access")
	// ErrGrantExists indicates a grant for the subject already exists.
	ErrGrantExists = errors.New("a grant for this subject already exists")
)
View Source
var (
	ErrBotNotFound       = errors.New("bot not found")
	ErrBotAccessDenied   = errors.New("bot access denied")
	ErrOwnerUserNotFound = errors.New("owner user not found")
	ErrBotNameTaken      = errors.New("bot name already taken")
	ErrBotNameInvalid    = errors.New("bot name is invalid")
	ErrBotNameReserved   = errors.New("bot name is reserved")
	// ErrCreateRequestDeleted: the bot an Idempotency-Key created is being deleted.
	ErrCreateRequestDeleted = errors.New("the bot this create request made is being deleted")
)

Functions

func HasPermission

func HasPermission(granted []string, required string) bool

HasPermission reports whether the granted set satisfies the required scope.

Types

type Bot

type Bot struct {
	ID              string `json:"id"`
	OwnerUserID     string `json:"owner_user_id"`
	Name            string `json:"name"`
	DisplayName     string `json:"display_name"`
	AvatarURL       string `json:"avatar_url,omitempty"`
	Timezone        string `json:"timezone,omitempty"`
	IsActive        bool   `json:"is_active"`
	Status          string `json:"status"`
	CheckState      string `json:"check_state"`
	CheckIssueCount int32  `json:"check_issue_count"`
	// CurrentUserPermissions lists the effective access permissions of the
	// requesting user on this bot (e.g. "chat", "manage"). It is populated by
	// the API layer per request and is not persisted.
	CurrentUserPermissions []string       `json:"current_user_permissions,omitempty"`
	Metadata               map[string]any `json:"metadata,omitempty"`
	CreatedAt              time.Time      `json:"created_at"`
	UpdatedAt              time.Time      `json:"updated_at"`
}

Bot represents a bot entity.

type BotCheck

type BotCheck struct {
	ID       string         `json:"id"`
	Type     string         `json:"type"`
	TitleKey string         `json:"title_key"`
	Subtitle string         `json:"subtitle,omitempty"`
	Status   string         `json:"status"`
	Summary  string         `json:"summary"`
	Detail   string         `json:"detail,omitempty"`
	Metadata map[string]any `json:"metadata,omitempty"`
}

BotCheck represents one resource check row for a bot.

type ConnectorLifecycle

type ConnectorLifecycle interface {
	CleanupBotConnectors(ctx context.Context, botID string) error
}

ConnectorLifecycle removes external connector credentials before the local bot row and its bindings are deleted.

type CreateBotRequest

type CreateBotRequest struct {
	Name         string         `json:"name,omitempty"`
	DisplayName  string         `json:"display_name,omitempty"`
	AvatarURL    string         `json:"avatar_url,omitempty"`
	Timezone     *string        `json:"timezone,omitempty"`
	IsActive     *bool          `json:"is_active,omitempty"`
	AclPreset    string         `json:"acl_preset,omitempty"`
	Metadata     map[string]any `json:"metadata,omitempty"`
	WaitForReady bool           `json:"wait_for_ready,omitempty"`
	// DeferWake leaves Wake to the caller (the create stream subscribes first).
	DeferWake bool `json:"-"`
	// RequestKey is the request's Idempotency-Key; see Service.FindCreated.
	RequestKey string `json:"-"`
}

CreateBotRequest is the input for creating a bot.

type CreateUserGrantRequest

type CreateUserGrantRequest struct {
	SubjectType string   `json:"subject_type"`
	UserID      string   `json:"user_id,omitempty"`
	Permissions []string `json:"permissions"`
}

CreateUserGrantRequest is the input for adding a user access grant.

type ListBotsResponse

type ListBotsResponse struct {
	Items []Bot `json:"items"`
}

ListBotsResponse wraps a list of bots.

type ListChecksResponse

type ListChecksResponse struct {
	Items []BotCheck `json:"items"`
}

ListChecksResponse wraps a list of bot checks.

type NameAvailability

type NameAvailability struct {
	Available bool   `json:"available"`
	Reason    string `json:"reason,omitempty"`
}

NameAvailability describes whether a bot name can be used.

type RuntimeChecker

type RuntimeChecker interface {
	// ListChecks evaluates dynamic runtime checks for a bot.
	ListChecks(ctx context.Context, botID string) []BotCheck
}

RuntimeChecker produces runtime check items for a bot.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides bot CRUD and membership management.

func NewService

func NewService(log *slog.Logger, queries dbstore.Queries) *Service

NewService creates a new bot service.

func (*Service) AddRuntimeChecker

func (s *Service) AddRuntimeChecker(c RuntimeChecker)

AddRuntimeChecker registers an additional runtime checker.

func (*Service) AuthorizeAccess

func (s *Service) AuthorizeAccess(ctx context.Context, userID, botID string, isAdmin bool) (Bot, error)

AuthorizeAccess checks whether userID may access the given bot (owner or admin only).

func (*Service) AuthorizeAccessWithPermission

func (s *Service) AuthorizeAccessWithPermission(ctx context.Context, userID, botID string, isAdmin bool, required string) (Bot, error)

AuthorizeAccessWithPermission checks whether userID may access the bot with the required permission scope (owner, admin, or a matching grant).

func (*Service) AwaitCreated added in v0.21.0

func (s *Service) AwaitCreated(ctx context.Context, bot Bot, req CreateBotRequest) (Bot, error)

AwaitCreated answers a create, first attempt or resend, with its bot: with WaitForReady, once the workspace has settled.

func (*Service) CheckNameAvailability

func (s *Service) CheckNameAvailability(ctx context.Context, name, excludeBotID string) (NameAvailability, error)

CheckNameAvailability validates a candidate name and reports whether it can be used for a new bot. excludeBotID, when non-empty, allows the bot currently owning the name (e.g. during rename) to be ignored.

func (*Service) ClearContainerSetupFailure

func (s *Service) ClearContainerSetupFailure(ctx context.Context, botID string) error

ClearContainerSetupFailure removes stale setup failure diagnostics after a successful workspace setup or manual workspace creation.

func (*Service) Create

func (s *Service) Create(ctx context.Context, ownerUserID string, req CreateBotRequest) (Bot, error)

Create creates a new bot owned by owner user.

func (*Service) CreateUserGrant

func (s *Service) CreateUserGrant(ctx context.Context, botID, createdByUserID string, req CreateUserGrantRequest) (UserGrant, error)

CreateUserGrant adds a new workspace user (or everyone) access grant.

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, botID string) error

Delete removes a bot and its associated resources.

func (*Service) DeleteUserGrant

func (s *Service) DeleteUserGrant(ctx context.Context, botID, grantID string) error

DeleteUserGrant removes a grant from a bot.

func (*Service) FindCreated added in v0.21.0

func (s *Service) FindCreated(ctx context.Context, ownerUserID, requestKey string) (Bot, bool, error)

FindCreated returns the bot an earlier create with this Idempotency-Key made for the owner; ok is false when there is none.

func (*Service) Get

func (s *Service) Get(ctx context.Context, identifier string) (Bot, error)

Get returns a bot by its identifier, which may be either a UUID or a name slug. This allows name-oriented URLs (/bot/:name) to resolve through the same path as UUID-based lookups.

func (*Service) GetForAccess

func (s *Service) GetForAccess(ctx context.Context, identifier string) (Bot, error)

GetForAccess returns a bot row for hot authorization paths without attaching runtime check summaries.

func (*Service) ListAccessible

func (s *Service) ListAccessible(ctx context.Context, channelIdentityID string) ([]Bot, error)

ListAccessible returns all bots owned by the user.

func (*Service) ListByOwner

func (s *Service) ListByOwner(ctx context.Context, ownerUserID string) ([]Bot, error)

ListByOwner returns bots owned by the given user.

func (*Service) ListChecks

func (s *Service) ListChecks(ctx context.Context, botID string) ([]BotCheck, error)

ListChecks evaluates runtime resource checks for a bot.

func (*Service) ListUserGrants

func (s *Service) ListUserGrants(ctx context.Context, botID string) ([]UserGrant, error)

ListUserGrants returns all workspace user access grants for a bot, with the owner prepended as an implicit full-access entry.

func (*Service) MarkReady

func (s *Service) MarkReady(ctx context.Context, botID string) (Bot, error)

MarkReady marks a bot lifecycle transition as complete and returns the fresh row.

func (*Service) PublishRuntimeConfig

func (s *Service) PublishRuntimeConfig(ctx context.Context, botID string, publish func(context.Context) error) error

PublishRuntimeConfig invalidates the old runtime epoch before publishing bot-scoped workspace files, then holds the reset parent lock for the whole external write. Callers must first acquire a bot-scoped reset lease.

func (*Service) RecordContainerSetupFailure

func (s *Service) RecordContainerSetupFailure(ctx context.Context, botID, phase string, setupErr error) error

RecordContainerSetupFailure persists a sanitized workspace setup failure so runtime diagnostics can explain why a ready bot is unhealthy.

func (*Service) ResolveUserPermissions

func (s *Service) ResolveUserPermissions(ctx context.Context, botID, userID string, isAdmin bool) ([]string, error)

ResolveUserPermissions returns the effective permissions for userID on botID. Owners and admins always receive the full permission set; other users receive the union of their direct grant and any everyone grant.

func (*Service) ResolveUserPermissionsForBot

func (s *Service) ResolveUserPermissionsForBot(ctx context.Context, bot Bot, userID string, isAdmin bool) ([]string, error)

ResolveUserPermissionsForBot resolves permissions using an already-loaded bot row. Hot read paths use this to avoid loading the same bot twice.

func (*Service) SetBotStatusFromWorkspace added in v0.21.0

func (s *Service) SetBotStatusFromWorkspace(ctx context.Context, botID, status string) error

SetBotStatusFromWorkspace lets the workspace reconciler derive bots.status. A bot that is being deleted keeps that status; the delete lifecycle owns it.

func (*Service) SetConnectorLifecycle

func (s *Service) SetConnectorLifecycle(lc ConnectorLifecycle)

SetConnectorLifecycle registers connector cleanup for bot deletion.

func (*Service) SetContainerReachability

func (s *Service) SetContainerReachability(fn func(ctx context.Context, botID string) error)

SetContainerReachability registers a function that checks whether a bot's container is reachable via gRPC. Returns nil on success, error otherwise.

func (*Service) SetWorkspaceIntents added in v0.21.0

func (s *Service) SetWorkspaceIntents(intents WorkspaceIntents)

SetWorkspaceIntents registers the workspace intent recorder (the botworkspace reconciler) for bot creation and deletion.

func (*Service) TransferOwner

func (s *Service) TransferOwner(ctx context.Context, botID string, ownerUserID string) (Bot, error)

TransferOwner transfers bot ownership to another user.

func (*Service) Update

func (s *Service) Update(ctx context.Context, botID string, req UpdateBotRequest) (Bot, error)

Update updates bot profile fields.

func (*Service) UpdateReplacingMetadata

func (s *Service) UpdateReplacingMetadata(ctx context.Context, botID string, req UpdateBotRequest) (Bot, error)

UpdateReplacingMetadata updates bot profile fields and writes metadata exactly as supplied. It is intended for restore/import paths where scrubbed metadata must not preserve existing sensitive fields.

func (*Service) UpdateUserGrant

func (s *Service) UpdateUserGrant(ctx context.Context, botID, grantID string, req UpdateUserGrantRequest) (UserGrant, error)

UpdateUserGrant updates the permission set of an existing grant.

func (*Service) ValidateUpdate

func (s *Service) ValidateUpdate(ctx context.Context, botID string, req UpdateBotRequest) error

ValidateUpdate validates bot profile updates without persisting them.

type TransferBotRequest

type TransferBotRequest struct {
	OwnerUserID string `json:"owner_user_id"`
}

TransferBotRequest is the input for transferring bot ownership.

type UpdateBotRequest

type UpdateBotRequest struct {
	Name        *string        `json:"name,omitempty"`
	DisplayName *string        `json:"display_name,omitempty"`
	AvatarURL   *string        `json:"avatar_url,omitempty"`
	Timezone    *string        `json:"timezone,omitempty"`
	IsActive    *bool          `json:"is_active,omitempty"`
	Metadata    map[string]any `json:"metadata,omitempty"`
}

UpdateBotRequest is the input for updating a bot.

type UpdateUserGrantRequest

type UpdateUserGrantRequest struct {
	Permissions []string `json:"permissions"`
}

UpdateUserGrantRequest is the input for updating a grant's permissions.

type UserGrant

type UserGrant struct {
	ID              string    `json:"id"`
	BotID           string    `json:"bot_id"`
	SubjectType     string    `json:"subject_type"`
	UserID          string    `json:"user_id,omitempty"`
	UserUsername    string    `json:"user_username,omitempty"`
	UserDisplayName string    `json:"user_display_name,omitempty"`
	UserAvatarURL   string    `json:"user_avatar_url,omitempty"`
	Permissions     []string  `json:"permissions"`
	IsOwner         bool      `json:"is_owner,omitempty"`
	CreatedAt       time.Time `json:"created_at"`
	UpdatedAt       time.Time `json:"updated_at"`
}

UserGrant represents a workspace user (or everyone) access grant for a bot.

type WorkspaceIntents added in v0.21.0

type WorkspaceIntents interface {
	// RecordPresent records, through the create's transaction q, that a new
	// bot should have a running workspace built from image.
	RecordPresent(ctx context.Context, q dbstore.Queries, botID, image string) error
	// Wake starts the reconciler on intents that have committed.
	Wake(ctx context.Context)
	// RequestAbsent asks for the workspace to be removed, optionally exporting
	// its data first, and returns the intent generation.
	RequestAbsent(ctx context.Context, botID string, preserve bool) (int64, error)
	// AwaitSettled blocks until the workspace has answered the given intent
	// generation (running, stopped, failed, or absent).
	AwaitSettled(ctx context.Context, botID string, generation int64) (WorkspaceOutcome, error)
	// Current returns the latest observation; ok is false when the bot has no
	// workspace row.
	Current(ctx context.Context, botID string) (WorkspaceOutcome, bool, error)
}

WorkspaceIntents records the desired workspace state of a bot; the botworkspace reconciler converges the actual workspace toward it and derives bots.status. The bots service never drives provisioning itself.

type WorkspaceOutcome added in v0.21.0

type WorkspaceOutcome struct {
	Desired        string
	Observed       string
	LastError      string
	LastErrorPhase string
	EverReady      bool
}

WorkspaceOutcome is the bots-facing projection of a workspace observation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL