Documentation
¶
Index ¶
- Constants
- Variables
- func AllSessionTypes() []string
- func ApplyACPMetadataDefaults(meta map[string]any) map[string]any
- func DescriptorFromLegacyType(typ string) (string, string)
- func IsACPRuntime(thread Thread) bool
- func IsKnownRuntimeType(runtimeType string) bool
- func IsKnownSessionMode(mode string) bool
- func IsKnownType(typ string) bool
- func IsUserFacingType(typ string) bool
- func LegacyTypeForDescriptor(sessionMode, runtimeType string) string
- func ResolveDescriptor(legacyType, sessionMode, runtimeType string) (string, string, string, error)
- func SupportsSkillActivation(sessionMode, legacyType, runtimeType string) bool
- func UserFacingSessionTypes() []string
- type ACPSetupValidation
- type ACPSetupValidator
- type CreateInput
- type CreateSubagentInput
- type Cursor
- type ForkFromAssistantInput
- type ListFilter
- type Queries
- type Service
- func (s *Service) Create(ctx context.Context, input CreateInput) (Thread, error)
- func (s *Service) CreateSubagent(ctx context.Context, input CreateSubagentInput) (Thread, SubagentConfig, error)
- func (s *Service) ForkFromAssistantTurn(ctx context.Context, input ForkFromAssistantInput) (Thread, error)
- func (s *Service) Get(ctx context.Context, sessionID string) (Thread, error)
- func (s *Service) GetSubagentConfig(ctx context.Context, sessionID string) (SubagentConfig, error)
- func (s *Service) ListByBot(ctx context.Context, botID string) ([]Thread, error)
- func (s *Service) ListByBotAndCreatedByUser(ctx context.Context, botID, userID string) ([]Thread, error)
- func (s *Service) ListByBotAndCreatedByUserPaged(ctx context.Context, botID, userID string, types []string, cursor Cursor, ...) ([]Thread, error)
- func (s *Service) ListByBotAndCreatedByUserPagedWithFilter(ctx context.Context, botID, userID string, types []string, cursor Cursor, ...) ([]Thread, error)
- func (s *Service) ListByBotPaged(ctx context.Context, botID string, types []string, cursor Cursor, limit int64) ([]Thread, error)
- func (s *Service) ListByBotPagedWithFilter(ctx context.Context, botID string, types []string, cursor Cursor, limit int64, ...) ([]Thread, error)
- func (s *Service) ListByRoute(ctx context.Context, routeID string) ([]Thread, error)
- func (s *Service) ListSubagentForkContext(ctx context.Context, sessionID string) ([]SubagentForkContextMessage, error)
- func (s *Service) ListSubagentsByParent(ctx context.Context, parentSessionID string) ([]Thread, error)
- func (s *Service) MessageCount(ctx context.Context, sessionID string) (int64, error)
- func (s *Service) SetACPSetupValidator(validator ACPSetupValidator)
- func (s *Service) SetHookService(h *hooks.Service)
- func (s *Service) SoftDelete(ctx context.Context, sessionID string) error
- func (s *Service) Touch(ctx context.Context, sessionID string) error
- func (s *Service) UpdateDescriptorAndMetadataWithOwner(ctx context.Context, sessionID, typ, sessionMode, runtimeType string, ...) (Thread, error)
- func (s *Service) UpdateEmptyDescriptorAndMetadataWithOwner(ctx context.Context, sessionID, typ, sessionMode, runtimeType string, ...) (Thread, error)
- func (s *Service) UpdateMetadata(ctx context.Context, sessionID string, metadata map[string]any) (Thread, error)
- func (s *Service) UpdateTitle(ctx context.Context, sessionID, title string) (Thread, error)
- func (s *Service) UpdateTypeAndMetadata(ctx context.Context, sessionID, typ string, metadata map[string]any) (Thread, error)
- func (s *Service) UpdateTypeAndMetadataWithOwner(ctx context.Context, sessionID, typ string, metadata map[string]any, ...) (Thread, error)
- type SubagentConfig
- type SubagentForkContextMessage
- type Thread
- type Visibility
Constants ¶
const ( TypeChat = "chat" TypeSchedule = "schedule" TypeSubagent = "subagent" TypeDiscuss = "discuss" TypeACPAgent = "acp_agent" RuntimeModel = "model" RuntimeACPAgent = "acp_agent" DefaultACPProjectMode = "project" DefaultACPProjectPath = "/data" )
Variables ¶
var ( ErrACPAgentIDRequired = errors.New("acp_agent_id is required for acp_agent sessions") ErrACPProjectPathMissing = errors.New("project_path is required for acp_agent sessions") ErrACPUnknownAgent = errors.New("unknown ACP agent") ErrACPAgentNotEnabled = errors.New("ACP agent is not enabled for this bot") ErrACPAgentNotConfigured = errors.New("ACP agent is not configured for this bot") ErrACPRuntimeOwnerMissing = errors.New("runtime_owner_account_id is required for acp_agent sessions") ErrACPProjectModeInvalid = errors.New("unknown ACP project mode") ErrForkSourceNotFound = errors.New("fork source session not found") ErrForkSourceNotReply = errors.New("fork source must be a visible assistant reply") ErrForkSourceNotChat = errors.New("fork source must be a chat session") ErrSessionHasMessages = errors.New("session has visible messages") )
Functions ¶
func AllSessionTypes ¶
func AllSessionTypes() []string
AllSessionTypes returns every known session type. The paged list queries always demand an explicit type filter; callers that filter by visibility instead pass this list to make the type predicate a no-op.
func ApplyACPMetadataDefaults ¶
ApplyACPMetadataDefaults fills omitted ACP session project fields.
func DescriptorFromLegacyType ¶
DescriptorFromLegacyType maps the legacy single type column to the split session mode/runtime descriptor used by new code paths.
func IsACPRuntime ¶
IsACPRuntime reports whether a session is backed by an ACP runtime. It keeps legacy chat ACP sessions (`type=acp_agent`) working while allowing newer descriptors such as `session_mode=discuss` + `runtime_type=acp_agent`.
func IsKnownRuntimeType ¶
func IsKnownSessionMode ¶
func IsKnownType ¶
func IsUserFacingType ¶
IsUserFacingType reports whether a session type is one that user-facing session list endpoints should return by default.
func LegacyTypeForDescriptor ¶
LegacyTypeForDescriptor returns the compatibility type value for a split session descriptor.
func ResolveDescriptor ¶
ResolveDescriptor returns the normalized compatibility type plus split session-mode/runtime descriptor without applying metadata side effects.
func SupportsSkillActivation ¶
SupportsSkillActivation reports whether a session shape can accept user-requested skill activation: chat mode (with the usual legacy-type fallback) on the built-in model runtime. This is the single definition for the rule — the web WS pre-check, the channel inbound gate, and the flow resolver's final guard all call it, so the three surfaces cannot drift.
func UserFacingSessionTypes ¶
func UserFacingSessionTypes() []string
UserFacingSessionTypes returns a fresh copy of the user-facing session type list so callers can read or mutate it without disturbing the package-level source of truth.
Types ¶
type ACPSetupValidation ¶
ACPSetupValidation is the channel- and runtime-independent policy result needed before a thread can persist an ACP runtime descriptor.
type ACPSetupValidator ¶
type ACPSetupValidator interface {
ValidateACPSetup(agentID string, botMetadata map[string]any) ACPSetupValidation
}
ACPSetupValidator is implemented by an Agent adapter. Thread owns this port so chat persistence never imports an Agent runtime implementation.
type CreateInput ¶
type CreateInput struct {
BotID string
BotAgentID string
RouteID string
ChannelType string
Type string
SessionMode string
RuntimeType string
Title string
Metadata map[string]any
RuntimeMetadata map[string]any
ParentThreadID string
CreatedByUserID string
// WorkdirID immutably binds the thread to a bot workdir. The caller
// (handler layer) validates the workdir; thread persistence only stores
// the reference so this package never imports the workdir domain.
WorkdirID string
// WorkdirPath is the resolved workdir directory, set if and only if
// WorkdirID is set. For ACP threads it overrides the metadata
// project_path so the runtime works in that directory; it also
// leaves a creation-time path snapshot in the metadata for history.
WorkdirPath string
// Visibility overrides the default visibility derived from the session
// mode. Schedule-created sessions use this to surface in user-facing
// session lists while keeping session_mode='schedule' for prompt and
// tool gating. Empty means "derive from mode".
Visibility Visibility
}
CreateInput holds input for creating a new thread.
type CreateSubagentInput ¶
type CreateSubagentInput struct {
Thread CreateInput
ModelUUID string
ModelID string
ProviderName string
Forked bool
ForkContext []SubagentForkContextMessage
}
type Cursor ¶
Cursor identifies the position in a thread listing for keyset pagination. The zero value means "start from the head".
func (Cursor) IsZero ¶
IsZero reports whether the cursor carries neither half — the start-of-list signal that pagedCursorParams maps to "no cursor predicate". A partially-populated cursor (only the timestamp or only the id) is not zero; pagedCursorParams rejects it as a programmer error so we never send malformed bindings down to SQL.
type ForkFromAssistantInput ¶
type ForkFromAssistantInput struct {
BotID string
ThreadID string
// TurnID names the round the fork inherits through. A turn is the identity
// a client holds while the round is still live, and the cut is turn-level
// anyway, so the fork point is named by turn rather than by stored message.
TurnID string
// MessageID is the pre-turn spelling of TurnID.
//
// Deprecated: accepted so a client shipped against the message-id contract
// keeps working after a server upgrade. It is resolved to the round that
// contains it. Remove once the compatibility window closes.
MessageID string
Title string
CreatedByUserID string
}
ForkFromAssistantInput creates a new chat thread from the source thread's visible history through the assistant message's turn.
type ListFilter ¶
type ListFilter struct {
ParentThreadID string
// WorkdirID filters to sessions bound to one workdir. Mutually
// exclusive with WorkdirUnassigned.
WorkdirID string
// WorkdirUnassigned filters to sessions with no workdir binding — the
// sidebar's ungrouped bucket.
WorkdirUnassigned bool
// Visibility filters to sessions with the given stored visibility.
// Empty means no visibility predicate. The default session listing
// passes VisibilityUser so schedule-created sessions surface by
// visibility rather than by widening the legacy type filter.
Visibility Visibility
}
type Queries ¶
type Queries interface {
CountMessagesBySession(context.Context, pgtype.UUID) (int64, error)
CreateSession(context.Context, sqlc.CreateSessionParams) (sqlc.BotSession, error)
CreateSubagentConfig(context.Context, sqlc.CreateSubagentConfigParams) (sqlc.SubagentConfig, error)
CreateSubagentForkContext(context.Context, sqlc.CreateSubagentForkContextParams) (sqlc.CreateSubagentForkContextRow, error)
ForkSessionFromAssistantTurn(context.Context, sqlc.ForkSessionFromAssistantTurnParams) (sqlc.ForkSessionFromAssistantTurnRow, error)
GetVisibleHistoryTurnByMessage(context.Context, sqlc.GetVisibleHistoryTurnByMessageParams) (dbstore.HistoryTurn, error)
GetBotByID(context.Context, pgtype.UUID) (sqlc.GetBotByIDRow, error)
GetSessionByID(context.Context, pgtype.UUID) (sqlc.BotSession, error)
GetSubagentConfig(context.Context, pgtype.UUID) (sqlc.SubagentConfig, error)
ListSessionsByBot(context.Context, pgtype.UUID) ([]sqlc.ListSessionsByBotRow, error)
ListSessionsByBotAndCreatedByUser(context.Context, sqlc.ListSessionsByBotAndCreatedByUserParams) ([]sqlc.ListSessionsByBotAndCreatedByUserRow, error)
ListSessionsByBotAndCreatedByUserPaged(context.Context, sqlc.ListSessionsByBotAndCreatedByUserPagedParams) ([]sqlc.ListSessionsByBotAndCreatedByUserPagedRow, error)
ListSessionsByBotPaged(context.Context, sqlc.ListSessionsByBotPagedParams) ([]sqlc.ListSessionsByBotPagedRow, error)
ListSessionsByRoute(context.Context, pgtype.UUID) ([]sqlc.BotSession, error)
ListSubagentForkContext(context.Context, pgtype.UUID) ([]sqlc.ListSubagentForkContextRow, error)
ListSubagentSessionsByParent(context.Context, pgtype.UUID) ([]sqlc.BotSession, error)
SoftDeleteSession(context.Context, pgtype.UUID) error
TouchSession(context.Context, pgtype.UUID) error
UpdateSessionMetadata(context.Context, sqlc.UpdateSessionMetadataParams) (sqlc.BotSession, error)
UpdateSessionTitle(context.Context, sqlc.UpdateSessionTitleParams) (sqlc.BotSession, error)
UpdateSessionTypeAndMetadata(context.Context, sqlc.UpdateSessionTypeAndMetadataParams) (sqlc.BotSession, error)
}
Queries is the storage surface owned by the Thread domain. Route lookup and route activation intentionally stay outside this contract.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service manages bot chat threads.
func NewService ¶
NewService creates a thread service. publisher may be nil — thread creation still succeeds when there is no event hub wired in (tests, or any caller that doesn't surface activity events).
func (*Service) CreateSubagent ¶
func (s *Service) CreateSubagent(ctx context.Context, input CreateSubagentInput) (Thread, SubagentConfig, error)
CreateSubagent atomically creates the hidden child thread and its pinned model/fork configuration when the backing store supports transactions.
func (*Service) ForkFromAssistantTurn ¶
func (s *Service) ForkFromAssistantTurn(ctx context.Context, input ForkFromAssistantInput) (Thread, error)
ForkFromAssistantTurn creates a new chat thread containing the source thread's visible linear history through the selected assistant turn.
func (*Service) GetSubagentConfig ¶
func (*Service) ListByBotAndCreatedByUser ¶
func (s *Service) ListByBotAndCreatedByUser(ctx context.Context, botID, userID string) ([]Thread, error)
ListByBotAndCreatedByUser returns all active sessions for a bot created by a user.
func (*Service) ListByBotAndCreatedByUserPaged ¶
func (s *Service) ListByBotAndCreatedByUserPaged(ctx context.Context, botID, userID string, types []string, cursor Cursor, limit int64) ([]Thread, error)
ListByBotAndCreatedByUserPaged is the paged variant scoped to a single user.
func (*Service) ListByBotAndCreatedByUserPagedWithFilter ¶
func (*Service) ListByBotPaged ¶
func (s *Service) ListByBotPaged(ctx context.Context, botID string, types []string, cursor Cursor, limit int64) ([]Thread, error)
ListByBotPaged returns one page of sessions for a bot, filtered to the given types and starting after the given cursor. Callers that want a "has more" signal pass limit+1 and look for an extra row.
func (*Service) ListByBotPagedWithFilter ¶
func (*Service) ListByRoute ¶
ListByRoute returns all active sessions for a route.
func (*Service) ListSubagentForkContext ¶
func (s *Service) ListSubagentForkContext(ctx context.Context, sessionID string) ([]SubagentForkContextMessage, error)
ListSubagentForkContext loads only the hidden rows reserved for a forked subagent's inherited model context. Other invisible history rows are ignored.
func (*Service) ListSubagentsByParent ¶
func (s *Service) ListSubagentsByParent(ctx context.Context, parentSessionID string) ([]Thread, error)
ListSubagentsByParent returns active subagent sessions created under a parent session.
func (*Service) MessageCount ¶
func (*Service) SetACPSetupValidator ¶
func (s *Service) SetACPSetupValidator(validator ACPSetupValidator)
func (*Service) SetHookService ¶
func (*Service) SoftDelete ¶
SoftDelete marks a session as deleted.
func (*Service) UpdateDescriptorAndMetadataWithOwner ¶
func (s *Service) UpdateDescriptorAndMetadataWithOwner(ctx context.Context, sessionID, typ, sessionMode, runtimeType string, metadata, runtimeMetadata map[string]any, botAgentID *string, runtimeOwnerUserID string) (Thread, error)
UpdateDescriptorAndMetadataWithOwner updates the session mode/runtime descriptor directly. Callers that only patch metadata for a Phase 3 session must pass the existing descriptor so discuss+ACP sessions keep their runtime.
func (*Service) UpdateEmptyDescriptorAndMetadataWithOwner ¶
func (s *Service) UpdateEmptyDescriptorAndMetadataWithOwner(ctx context.Context, sessionID, typ, sessionMode, runtimeType string, metadata, runtimeMetadata map[string]any, botAgentID *string, runtimeOwnerUserID string) (Thread, error)
UpdateEmptyDescriptorAndMetadataWithOwner updates a session runtime identity only while its visible history is still empty. PostgreSQL-backed stores lock the bot and session in the same transaction as the message check, descriptor update, runtime-fence bump, and ACP snapshot invalidation. The lock ordering matches runtime activation, so an already-running turn linearizes before the empty-history check and an old runtime token cannot write after the update.
func (*Service) UpdateMetadata ¶
func (s *Service) UpdateMetadata(ctx context.Context, sessionID string, metadata map[string]any) (Thread, error)
UpdateMetadata updates a session's metadata.
func (*Service) UpdateTitle ¶
UpdateTitle updates a session's title.
func (*Service) UpdateTypeAndMetadata ¶
func (s *Service) UpdateTypeAndMetadata(ctx context.Context, sessionID, typ string, metadata map[string]any) (Thread, error)
UpdateTypeAndMetadata updates a session's runtime type and metadata in one statement so callers don't expose a half-updated agent selection.
func (*Service) UpdateTypeAndMetadataWithOwner ¶
func (s *Service) UpdateTypeAndMetadataWithOwner(ctx context.Context, sessionID, typ string, metadata map[string]any, runtimeOwnerUserID string) (Thread, error)
UpdateTypeAndMetadataWithOwner updates a session descriptor and binds any ACP runtime ownership to a server-confirmed account id. The metadata owner field is never trusted from callers.
type SubagentConfig ¶
type SubagentConfig struct {
ThreadID string `json:"session_id"`
ModelUUID string `json:"model_uuid,omitempty"`
ModelID string `json:"model_id"`
ProviderName string `json:"provider"`
Forked bool `json:"fork"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
SubagentConfig is the persisted runtime selection for a managed subagent.
type SubagentForkContextMessage ¶
type SubagentForkContextMessage struct {
SourceMessageID string `json:"source_message_id,omitempty"`
Role string `json:"role"`
Message json.RawMessage `json:"message"`
}
SubagentForkContextMessage is one hidden history message copied or materialized into a forked subagent session.
type Thread ¶
type Thread struct {
ID string `json:"id"`
BotID string `json:"bot_id"`
BotAgentID string `json:"bot_agent_id,omitempty"`
RouteID string `json:"route_id,omitempty"`
ChannelType string `json:"channel_type,omitempty"`
Type string `json:"type"`
SessionMode string `json:"session_mode"`
RuntimeType string `json:"runtime_type"`
RuntimeMetadata map[string]any `json:"runtime_metadata,omitempty"`
Title string `json:"title"`
Metadata map[string]any `json:"metadata,omitempty"`
ParentThreadID string `json:"parent_session_id,omitempty"`
CreatedByUserID string `json:"created_by_user_id,omitempty"`
WorkdirID string `json:"workdir_id,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
RouteMetadata map[string]any `json:"route_metadata,omitempty"`
RouteConversationType string `json:"route_conversation_type,omitempty"`
Visibility Visibility `json:"-"`
} // @name session.Session
Thread represents a chat thread within a bot.
type Visibility ¶
type Visibility string
Visibility describes whether a thread belongs in user-facing history or is reserved for an internal agent workflow.
const ( VisibilityUser Visibility = "user" VisibilityInternal Visibility = "internal" )
func NormalizeVisibility ¶
func NormalizeVisibility(stored string, mode string) Visibility
NormalizeVisibility resolves a possibly-absent stored visibility value against the session mode's default. Exported for restore paths that replay archived session rows which may predate the visibility column.