Documentation
¶
Index ¶
- Constants
- Variables
- func AllSessionTypes() []string
- func ApplyExternalMetadataDefaults(meta map[string]any) map[string]any
- func DescriptorFromLegacyType(typ string) (string, string)
- func IsACPRuntime(thread Thread) bool
- func IsExternalRuntime(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 RuntimeTypeOf(thread Thread) string
- func SupportsSkillActivation(sessionMode, legacyType, runtimeType string) bool
- func UserFacingSessionTypes() []string
- func UsesDecisionWaiter(thread Thread) bool
- type ACPSetupValidation
- type ACPSetupValidator
- type CreateInput
- type CreateSubagentInput
- type Cursor
- type DescriptorError
- type ExternalIdentity
- 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) ExternalIdentity(ctx context.Context, thread Thread) (ExternalIdentity, 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) LatestModelPreferenceSeed(ctx context.Context, botID, userID string) (string, string, 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) MergeRuntimeMetadata(ctx context.Context, sessionID, runtimeType string, delta map[string]any) (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 = string(runtimekind.Model) RuntimeACPAgent = string(runtimekind.ACPAgent) DefaultACPProjectPath = "/data" )
The runtime vocabulary is owned by runtimekind (a leaf package shared with consumers that cannot import this one); these constants are pinned aliases so the session domain keeps its established names.
Variables ¶
var ( ErrACPAgentIDRequired = errors.New("acp_agent_id is required for acp_agent sessions") ErrACPAgentNotEnabled = errors.New("ACP agent is not enabled for this bot") ErrACPUnknownAgent = errors.New("unknown ACP agent") ErrACPAgentNotConfigured = errors.New("ACP agent is not configured for this bot") ErrRuntimeOwnerMissing = errors.New("runtime_owner_account_id is required for external agent sessions") 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") )
var ErrRuntimeMetadataStale = errors.New("session runtime changed; runtime metadata merge skipped")
ErrRuntimeMetadataStale reports that a runtime-metadata merge was skipped because the session no longer runs the expected runtime.
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 ApplyExternalMetadataDefaults ¶ added in v0.20.0
ApplyExternalMetadataDefaults fills an external agent session's project with the default, the workspace root.
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 IsExternalRuntime ¶ added in v1.0.0
IsExternalRuntime reports whether a session runs on an external agent (an ACP agent or a direct runtime) rather than Memoh's own model loop.
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 RuntimeTypeOf ¶ added in v1.0.0
RuntimeTypeOf is the runtime a session runs on. Legacy rows (type acp_agent with no runtime type) are mapped here, the one place that does.
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.
func UsesDecisionWaiter ¶ added in v0.20.0
UsesDecisionWaiter reports whether tool-approval and user-input decisions for this session are answered by waking an in-process runtime waiter (the ACP pool or a direct external runtime) instead of resuming the native agent loop with a tool result.
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 {
// InstanceACPAgent is the ACP agent profile a Bot Agent instance runs.
InstanceACPAgent(ctx context.Context, botID, botAgentID string) (string, error)
// ACPInstanceFor is the instance a session that names only an ACP agent
// profile runs as: the bot's oldest active instance of it. Empty when the
// bot has none, as bots configured before instances do.
ACPInstanceFor(ctx context.Context, botID, agentID string) (string, error)
KnownACPAgent(agentID string) bool
ValidateACPSetup(ctx context.Context, botID, botAgentID, agentID string, botMetadata map[string]any) (ACPSetupValidation, error)
}
ACPSetupValidator is implemented by an Agent adapter. Thread owns this port so chat persistence never imports an Agent runtime implementation. The adapter resolves which Agent instance's setup applies: botAgentID when the thread is bound to one, otherwise the instance the provider falls back to.
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
// PreferredChatModelID / PreferredReasoningEffort are the first-message
// pair written at INSERT time (issue #879, spec §3.3-D) so the
// session_created broadcast never precedes the value. Empty = NULL.
// Non-UUID model references degrade to NULL; the steady-state
// write-back completes the pair on the same turn.
PreferredChatModelID string
PreferredReasoningEffort 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 DescriptorError ¶ added in v0.22.0
DescriptorError is a session descriptor the caller can fix by changing the request field named Field (wire name).
func (*DescriptorError) Error ¶ added in v0.22.0
func (e *DescriptorError) Error() string
func (*DescriptorError) Unwrap ¶ added in v0.22.0
func (e *DescriptorError) Unwrap() error
type ExternalIdentity ¶ added in v1.0.0
type ExternalIdentity struct {
BotAgentID string
ACPAgentID string
ProjectPath string
RuntimeOwnerAccountID string
}
ExternalIdentity is what an external agent session is: the Bot Agent it runs as, the agent profile that instance runs (ACP only), its project and the account its turns run as.
func ExternalIdentityOf ¶ added in v1.0.0
func ExternalIdentityOf(thread Thread) ExternalIdentity
ExternalIdentityOf reads the identity a session stores itself: everything but its ACP agent profile, which ExternalIdentity resolves.
type ForkFromAssistantInput ¶
type ForkFromAssistantInput struct {
BotID string
ThreadID string
// RuntimeMetadataOverride replaces the clone's runtime metadata. External
// runtime forks must pass it carrying the driver's freshly forked session
// keys; without it the two Memoh sessions would share one runtime session.
RuntimeMetadataOverride map[string]any
// RuntimeForkRequired marks a source whose runtime keeps its native
// session in runtime metadata with no owner: a copy without the runtime's
// own fork would share that session, so the fork is refused.
RuntimeForkRequired bool
// 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
// HideScheduleRuns drops the sessions schedule fires created, which the
// sidebar shows under their schedule instead. A schedule-created session
// that a schedule still runs in (its existing_session target) stays.
HideScheduleRuns bool
}
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)
GetLatestSessionModelPreference(context.Context, sqlc.GetLatestSessionModelPreferenceParams) (sqlc.GetLatestSessionModelPreferenceRow, 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)
UpdateSessionRuntimeMetadata(context.Context, sqlc.UpdateSessionRuntimeMetadataParams) (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) ExternalIdentity ¶ added in v1.0.0
ExternalIdentity is the one read of a session's external identity. An ACP session's agent profile is its Bot Agent instance's; a session from before instances has none and keeps the profile it named.
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, with the history checkpoint that holds for it, so the fork's first request reads what the source read at that turn without compacting it again.
func (*Service) GetSubagentConfig ¶
func (*Service) LatestModelPreferenceSeed ¶ added in v0.20.0
func (s *Service) LatestModelPreferenceSeed(ctx context.Context, botID, userID string) (string, string, error)
Get returns a session by ID. LatestModelPreferenceSeed is the welcome composer seed (issue #879, spec §3.4): the bot's most recent native user-facing session with a persisted pair, scoped to the calling user. Empty pair + nil error = no seed; welcome falls back to the bot default.
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) MergeRuntimeMetadata ¶ added in v0.20.0
func (s *Service) MergeRuntimeMetadata(ctx context.Context, sessionID, runtimeType string, delta map[string]any) (Thread, error)
MergeRuntimeMetadata merges driver-owned keys into a session's runtime metadata; a nil value deletes the key. The write is guarded on runtimeType so a concurrent runtime switch turns the merge into ErrRuntimeMetadataStale instead of polluting another runtime's metadata, and on the caller's runtime fencing token so a superseded owner's late write after a cluster ownership handoff cannot clobber the new owner's runtime thread id. Under a history reset, like every reset write, it checks the reset lease in the same transaction.
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, and runtime-fence bump. 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 External Agent 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"`
// TeamID is the team that owns the thread's bot. Server-owned work that
// outlives the request (queued follow-ups) records it because admission
// requires a team and nothing else can supply one later. It is internal
// state, not part of the session API resource.
TeamID string `json:"-"`
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"`
// Preferred* is the session's persisted (model, effort) pair (issue #879).
// Empty means "no memory"; the composer reseeds from it on open/repoint.
PreferredExternalModelID string `json:"preferred_external_model_id,omitempty"`
ModelPreferenceRevision string `json:"model_preference_revision,omitempty"`
PreferredChatModelID string `json:"preferred_chat_model_id,omitempty"`
PreferredReasoningEffort string `json:"preferred_reasoning_effort,omitempty"`
RouteMetadata map[string]any `json:"route_metadata,omitempty"`
RouteConversationType string `json:"route_conversation_type,omitempty"`
// AttentionKind and Unread describe the requesting user's unread state.
// They are filled by the attention service for list responses only.
AttentionKind string `json:"attention_kind,omitempty"`
AttentionAt *time.Time `json:"attention_at,omitempty"`
Unread bool `json:"unread,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.