Files
ai-agent/backend/schemas/users.py
Gabriel Vidal a76cce0c71 feat(users): guest defaults — starting shortcuts + skills shared with guest runs
The owner sets, for every guest at once (users.json guestDefaults):
- promptShortcuts: what a guest's composer starts with. A guest who never
  saved settings gets them as the seed of their ai-agent-settings ui-state.
- sharedSkills: lab/project skills handed to every guest run. The scope
  carries them to the host sidecar, which symlinks them into a generated
  plugin and passes --plugin-dir: they show up as shared:<name>.

GET/PUT /api/guest-defaults (owner), GET /api/guest-skills (the composer's
mentions: shared + granted projects' skills), shareRef/sharedWithGuests on
the skills catalog.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 20:20:10 +02:00

117 lines
3.0 KiB
Python

"""Guests: ``/api/me``, the owner's user admin, conversation sharing."""
from __future__ import annotations
from typing import Optional
from .base import Schema
__all__ = [
"ProjectGrant", "NotifyPrefs", "Me", "GuestUser", "UsersResponse",
"LoginLink", "ShareCandidate", "ConversationShare", "GuestShortcut",
"GuestDefaults", "GuestSkill", "GuestSkillsResponse",
]
class ProjectGrant(Schema):
slug: str
level: str # "view" | "chat" | "ship"
class NotifyPrefs(Schema):
channels: list[str] # "in_app" | "email" | "webpush"
class Me(Schema):
"""Who the browser is: the owner, or a guest with their grants."""
id: str
role: str # "owner" | "guest"
name: str
email: Optional[str] = None
readonly: bool = False
projects: list[ProjectGrant]
models: list[str]
budgetUsd: Optional[float] = None
spentUsd: Optional[float] = None
notify: Optional[NotifyPrefs] = None
mail: bool = False # outbound mail configured (login links can be mailed)
surface: Optional[str] = None # "admin" | "guest"
# A guest's starting prompt shortcuts (what Reset goes back to); None for
# the owner, whose defaults are built into the frontend.
defaultShortcuts: Optional[list["GuestShortcut"]] = None
class GuestUser(Schema):
id: str
email: str
name: str
role: str
projects: dict[str, str]
models: list[str]
budgetUsd: float
notify: NotifyPrefs
disabled: bool
createdAt: str
lastLoginAt: Optional[str] = None
sessions: int = 0
class UsersResponse(Schema):
users: list[GuestUser]
levels: list[str]
channels: list[str]
defaultModels: list[str]
mail: bool
guestUrl: Optional[str] = None
class LoginLink(Schema):
url: str
sent: bool
expiresInS: int
class ShareCandidate(Schema):
id: str
name: str
level: Optional[str] = None
class ConversationShare(Schema):
sessionId: str
owner: Optional[str] = None
project: Optional[str] = None
participants: list[str]
candidates: list[ShareCandidate]
class GuestShortcut(Schema):
"""A prompt shortcut in the frontend's ``PromptShortcut`` shape."""
id: str
label: str
icon: str = "Sparkles"
guideline: str = ""
defaultOn: bool = False
labelOff: Optional[str] = None
guidelineOff: Optional[str] = None
children: Optional[list[str]] = None
triggers: Optional[list[str]] = None
shared: Optional[bool] = None
class GuestDefaults(Schema):
"""What the owner sets for every guest at once (Settings → Users)."""
promptShortcuts: list[GuestShortcut]
sharedSkills: list[str] # `name` (repo) | `<project>/<name>`
class GuestSkill(Schema):
"""A skill a guest's run can use — the composer's `/` mentions."""
name: str # the invocation name (`shared:<name>` when shared)
description: str = ""
triggerWords: list[str] = []
source: str # "shared" | <project slug>
class GuestSkillsResponse(Schema):
skills: list[GuestSkill]