Documentation
¶
Overview ¶
Package chats is the chat business-logic layer: it owns the chat + message repositories and the model registry, and drives a turn end-to-end (demo interception, model resolution, the agentic turn loop, SSE streaming, and persistence). HTTP handlers stay dumb — they parse the request, call a method here, and map the result (or a sentinel error) to the API response.
Index ¶
- Constants
- Variables
- func ChatMCPServerToAPI(sv ChatMCPServer) api.ChatMCPServer
- func ChatSearch(search string) string
- func ChatSettingsToAPI(c *models.Chat) *api.ChatSettings
- func ChatSummaryToAPI(c *models.Chat) api.ChatSummary
- func MessageToAPI(m *models.Message) (api.Message, error)
- func PromptContextToAPI(context PromptContext) api.PromptContextPreview
- type ChatMCPServer
- type ListOptions
- type PromptContext
- type Service
- func (s *Service) Continue(ctx context.Context, chatID, userID uuid.UUID, message string, ...) (io.Reader, error)
- func (s *Service) Create(ctx context.Context, userID uuid.UUID, message, model string) (io.Reader, error)
- func (s *Service) Delete(ctx context.Context, chatID, userID uuid.UUID) error
- func (s *Service) Get(ctx context.Context, chatID, userID uuid.UUID) (*models.Chat, error)
- func (s *Service) GetOrCreateEmpty(ctx context.Context, userID uuid.UUID) (*models.Chat, error)
- func (s *Service) List(ctx context.Context, userID uuid.UUID, limit, offset int) ([]*models.Chat, int, error)
- func (s *Service) ListMCPServers(ctx context.Context, chatID, userID uuid.UUID) ([]ChatMCPServer, error)
- func (s *Service) ListMessages(ctx context.Context, chatID, userID uuid.UUID, limit, offset int) ([]*models.Message, int, error)
- func (s *Service) ListWithOptions(ctx context.Context, userID uuid.UUID, options ListOptions, limit, offset int) ([]*models.Chat, int, error)
- func (s *Service) PreviewContext(ctx context.Context, chatID, userID uuid.UUID, message string) (PromptContext, error)
- func (s *Service) Rename(ctx context.Context, chatID, userID uuid.UUID, title string) (*models.Chat, error)
- func (s *Service) SetMCPServerEnabled(ctx context.Context, chatID, userID, serverID uuid.UUID, enabled bool) (*ChatMCPServer, error)
- func (s *Service) SetPinned(ctx context.Context, chatID, userID uuid.UUID, pinned bool) (*models.Chat, error)
- func (s *Service) UpdateSettings(ctx context.Context, chatID, userID uuid.UUID, settings Settings) (*models.Chat, error)
- type Settings
Constants ¶
const (
MaxChatSearchRunes = 256
)
Variables ¶
var ( // ErrUnknownModel is returned when a real (non-demo) turn names a model no // configured upstream serves. Callers map it to a 400. ErrUnknownModel = errors.New("chats: unknown model") // ErrEmptyTitle is returned when a rename is given a blank title. Callers // map it to a 400. ErrEmptyTitle = errors.New("chats: title must not be empty") )
Functions ¶
func ChatMCPServerToAPI ¶
func ChatMCPServerToAPI(sv ChatMCPServer) api.ChatMCPServer
ChatMCPServerToAPI maps a chat's view of an MCP server to the wire shape.
func ChatSearch ¶
ChatSearch normalizes a title search before passing it into the generated parameterized query. A blank return means no search filter.
func ChatSettingsToAPI ¶
func ChatSettingsToAPI(c *models.Chat) *api.ChatSettings
ChatSettingsToAPI projects a chat's stored generation settings to the API shape. Unset numeric settings stay nil; an empty ReasoningEffort maps to a nil pointer (the wire omits it) rather than an invalid empty enum value.
func ChatSummaryToAPI ¶
func ChatSummaryToAPI(c *models.Chat) api.ChatSummary
ChatSummaryToAPI projects a stored chat row to the wire summary shape.
func MessageToAPI ¶
MessageToAPI projects a stored message row to the wire shape. Thinking, toolCallId, and isError are omitted (nil) when the row carries none of them, so a plain user/text-only row's JSON is unchanged from before these fields existed. ToolCalls is unmarshalled from the row's stored JSON; a decode failure returns an error rather than silently dropping the tool calls a reload is specifically trying to reconstruct.
func PromptContextToAPI ¶
func PromptContextToAPI(context PromptContext) api.PromptContextPreview
PromptContextToAPI projects the backend-authoritative prompt selection to the compact composer meter shape.
Types ¶
type ChatMCPServer ¶
ChatMCPServer is one MCP server as a chat sees it: identity, live global connection status, and whether its tools are enabled for this chat. Per-chat enablement is independent of the server's global enabled flag.
type ListOptions ¶
type ListOptions struct {
Search string
}
ListOptions narrows one caller's chat history without changing ownership. A blank Search matches every chat.
type PromptContext ¶
type PromptContext struct {
BudgetTokens int
SystemTokens int
HistoryTokens int
CurrentMessageTokens int
TotalTokens int
OmittedMessages int
OmittedTurns int
RetainedMessages int
RetainedTurns int
History []elelem.Message
}
PromptContext describes the exact history selection Chatz made before an outbound model request. Component counts use the same tiktoken codec as the total; TotalTokens is counted over the fully assembled prompt representation.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service coordinates the chat repositories, the model upstreams, and the MCP tool manager to fulfill the chat API operations.
func New ¶
func New( query *repositories.Query, models *upstreams.Registry, mcpMgr *mcp.Manager, showcaseMode bool, ) *Service
New builds the chat service over the given repositories, model registry, and MCP manager. Each outbound prompt has a 100000-token default cap; a chat may override it with max_history_tokens (see UpdateSettings).
func (*Service) Continue ¶
func (s *Service) Continue( ctx context.Context, chatID, userID uuid.UUID, message string, requestedModel *string, ) (io.Reader, error)
Continue continues an existing chat and returns a reader that streams the next assistant turn (SSE). requestedModel, when non-empty, switches the chat to that model (persisted so a reopened chat comes back to its last-used model); demo turns bypass the LLM and never change the chat's model. A chat with no title yet (its first real message — the composer creates the chat via GetOrCreateEmpty before the user types anything, so this is the only place a title gets set) is titled from this message, mirroring what the standalone Create() does for its one-shot create+message flow. Returns commerr.ErrNotFound if the chat is missing, or ErrUnknownModel for an unservable real-turn model.
func (*Service) Create ¶
func (s *Service) Create( ctx context.Context, userID uuid.UUID, message, model string, ) (io.Reader, error)
Create creates a chat for the user and returns a reader that streams the first assistant turn (SSE). A demo command works with any model id; a real turn returns ErrUnknownModel when no configured upstream serves model.
func (*Service) Delete ¶
Delete removes a caller-owned chat from normal reads through the existing soft-delete model. The durable message rows remain outside normal history.
func (*Service) Get ¶
Get returns a chat's metadata owned by userID (no messages — fetch those via ListMessages). Returns commerr.ErrNotFound when the chat does not exist or belongs to another user.
func (*Service) GetOrCreateEmpty ¶
GetOrCreateEmpty returns the caller's reusable "empty chat" — the chat a fresh "New chat" click lands on — creating one if none exists. At most one empty chat is ever kept per user: repeated "New chat" clicks before typing anything all resolve to the SAME chat instead of piling up unused rows.
A benign race exists: two concurrent calls (a double-click, two tabs) can both see zero existing empty chats and each create one. This is accepted rather than transaction-guarded — the worst case is a second, harmless empty row that gets reused (or ages out unused) rather than any data loss.
func (*Service) List ¶
func (s *Service) List( ctx context.Context, userID uuid.UUID, limit, offset int, ) ([]*models.Chat, int, error)
List returns a page of the user's non-empty chats (at least one user message), newest activity first, plus the scoped total count. A brand-new chat with no user message yet — see GetOrCreateEmpty — is hidden from history until the user actually sends something in it.
func (*Service) ListMCPServers ¶
func (s *Service) ListMCPServers( ctx context.Context, chatID, userID uuid.UUID, ) ([]ChatMCPServer, error)
ListMCPServers returns every MCP server with its live global status and whether it is enabled for this chat (ownership-checked). Returns commerr.ErrNotFound when the chat is missing or owned by another user.
func (*Service) ListMessages ¶
func (s *Service) ListMessages( ctx context.Context, chatID, userID uuid.UUID, limit, offset int, ) ([]*models.Message, int, error)
ListMessages returns a page of a chat's visible messages, oldest-first, plus the scoped total count (indexed by chat_id). A row is visible if it carries anything to render — content, a reasoning trace, or tool calls; a row with none of those is purely internal plumbing (e.g. a completed round whose only output was consumed elsewhere) and is omitted from both the page and the total. Rows are also restricted to the three durable roles (user/assistant/tool) — a role="system" tool-steering injection should never have been persisted (persistTurn skips it going forward), but this filters out any that slipped in before that fix rather than rendering as a stray fake user bubble. An incomplete user row is visible so a refresh after stopping a stream retains the submitted message; an incomplete assistant checkpoint is also visible, while incomplete tool rows remain hidden. Returns commerr.ErrNotFound when the chat does not exist or belongs to another user.
func (*Service) ListWithOptions ¶
func (s *Service) ListWithOptions( ctx context.Context, userID uuid.UUID, options ListOptions, limit, offset int, ) ([]*models.Chat, int, error)
ListWithOptions returns the requested page of the user's non-empty chats. A blank search has no filter.
func (*Service) PreviewContext ¶
func (s *Service) PreviewContext( ctx context.Context, chatID, userID uuid.UUID, message string, ) (PromptContext, error)
PreviewContext returns the exact prompt selection a turn would use for the caller's unsent message. It shares the production history loader, sticky system prompt, tiktoken counting, and complete-tool-turn selection logic.
func (*Service) Rename ¶
func (s *Service) Rename( ctx context.Context, chatID, userID uuid.UUID, title string, ) (*models.Chat, error)
Rename sets a chat's title (trimmed + capped to maxTitleRunes) and returns the updated chat. Returns ErrEmptyTitle for a blank title and commerr.ErrNotFound when the chat is missing or owned by another user.
func (*Service) SetMCPServerEnabled ¶
func (s *Service) SetMCPServerEnabled( ctx context.Context, chatID, userID, serverID uuid.UUID, enabled bool, ) (*ChatMCPServer, error)
SetMCPServerEnabled enables or disables one MCP server's tools for a chat (ownership-checked). Returns commerr.ErrNotFound when the chat or the server does not exist.
func (*Service) SetPinned ¶
func (s *Service) SetPinned( ctx context.Context, chatID, userID uuid.UUID, pinned bool, ) (*models.Chat, error)
SetPinned pins or unpins a chat for the caller. Pinned chats lead their active or archived list while retaining activity order within each group.
func (*Service) UpdateSettings ¶
func (s *Service) UpdateSettings( ctx context.Context, chatID, userID uuid.UUID, settings Settings, ) (*models.Chat, error)
UpdateSettings replaces the chat's generation settings and returns the updated chat. Full replacement: a field left unset clears that setting. Returns commerr.ErrNotFound when the chat is missing or owned by another user.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package fixedresponses maps exact, recording-ready chat prompts to canned assistant turns embedded at build time.
|
Package fixedresponses maps exact, recording-ready chat prompts to canned assistant turns embedded at build time. |
|
Package prompts holds generated, embedded LLM system-prompt fragments for the chat turn loop.
|
Package prompts holds generated, embedded LLM system-prompt fragments for the chat turn loop. |