session

package
v0.16.0 Latest Latest
Warning

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

Go to latest
Published: May 8, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Author added in v0.16.0

type Author struct {
	UserID      types.UserID `firestore:"user_id" json:"user_id"`
	DisplayName string       `firestore:"display_name" json:"display_name"`
	// SlackUserID is set when the author is a Slack workspace member.
	SlackUserID *string `firestore:"slack_user_id,omitempty" json:"slack_user_id,omitempty"`
	Email       *string `firestore:"email,omitempty" json:"email,omitempty"`
}

Author identifies a human author of a user-type Message.

For AI-produced Messages (trace/plan/response/warning) the Message.Author field is nil. For user Messages, Author is required and contains the minimum information needed to render attribution across all channels.

type ChannelRef added in v0.16.0

type ChannelRef struct {
	SlackThread *slack.Thread `firestore:"slack_thread,omitempty" json:"slack_thread,omitempty"`
}

ChannelRef captures the external channel a Session is bound to.

For Slack Sessions, SlackThread is populated and identifies the specific channel+thread pair. For Web and CLI Sessions, ChannelRef is nil.

type Message

type Message struct {
	ID        types.MessageID `firestore:"id" json:"id"`
	SessionID types.SessionID `firestore:"session_id" json:"session_id"`
	Type      MessageType     `firestore:"type" json:"type"`       // Type only affects Slack display method
	Content   string          `firestore:"content" json:"content"` // All stored as plain text
	CreatedAt time.Time       `firestore:"created_at" json:"created_at"`
	UpdatedAt time.Time       `firestore:"updated_at" json:"updated_at"`

	// TicketID denormalizes Session.TicketID onto each Message so Ticket-
	// level timeline queries do not require a per-Message Session join.
	// nil when the owning Session is ticketless.
	TicketID *types.TicketID `firestore:"ticket_id,omitempty" json:"ticket_id,omitempty"`

	// TurnID identifies which Turn (req/res cycle) produced this Message.
	// nil when the Message is not tied to an AI work unit (e.g. Slack
	// thread messages that were not @warren mentions).
	TurnID *types.TurnID `firestore:"turn_id,omitempty" json:"turn_id,omitempty"`

	// Author is required for Type=user and nil otherwise.
	Author *Author `firestore:"author,omitempty" json:"author,omitempty"`

	// Revisions carries the historical content of an updatable Message.
	// The current Content field is always the latest revision; Revisions
	// is the chronologically-ordered list of prior values (oldest first).
	// Empty for messages that have never been updated in-place.
	//
	// Updatable messages are used by Web/CLI Sessions so that live task
	// progress and HITL prompts can replace the current display row
	// while preserving the full trace for later review. Slack Sessions
	// keep their own update history in the Slack thread and do not
	// populate this field.
	Revisions []MessageRevision `firestore:"revisions,omitempty" json:"revisions,omitempty"`
}

Message represents a message recorded during a chat session.

chat-session-redesign fields (TicketID / TurnID / Author) are added alongside the legacy fields. Existing writers that use NewMessage keep working; new writers should prefer NewMessageV2.

func NewMessage deprecated

func NewMessage(ctx context.Context, sessionID types.SessionID, msgType MessageType, content string) *Message

NewMessage creates a new session message using the legacy signature.

Deprecated: prefer NewMessageV2 for new code. This shim sets Type/Content only; TicketID, TurnID, and Author remain nil.

func NewMessageV2 added in v0.16.0

func NewMessageV2(
	ctx context.Context,
	sessionID types.SessionID,
	ticketID *types.TicketID,
	turnID *types.TurnID,
	msgType MessageType,
	content string,
	author *Author,
) *Message

NewMessageV2 creates a new Message with the chat-session-redesign fields.

For Type=user, author must not be nil. For AI-produced types (trace / plan / response / warning), author should be nil. turnID may be nil for messages that are not tied to a Turn (e.g. Slack non-mention messages).

func (*Message) AppendRevision added in v0.16.0

func (m *Message) AppendRevision(ctx context.Context, newContent string)

AppendRevision pushes the Message's current Content onto the Revisions slice and replaces Content with newContent. UpdatedAt is bumped to now. This is the single write path used by Web/CLI updatable messages so that the persisted history stays consistent across concurrent updates to the same Message.

type MessageRevision added in v0.16.0

type MessageRevision struct {
	Content   string    `firestore:"content" json:"content"`
	CreatedAt time.Time `firestore:"created_at" json:"created_at"`
}

MessageRevision records a single historical value of a Message.Content. Revisions are append-only: when Message.Content is replaced, the prior Content+UpdatedAt pair is pushed onto the Revisions slice before the new value is written.

type MessageType

type MessageType string

MessageType represents the type of session message

const (
	MessageTypeUser     MessageType = "user"     // chat-session-redesign: human user input (Slack/Web/CLI)
	MessageTypeTrace    MessageType = "trace"    // Progress messages displayed in context block
	MessageTypePlan     MessageType = "plan"     // Plan messages displayed in context block
	MessageTypeResponse MessageType = "response" // Final response displayed in normal block
	MessageTypeWarning  MessageType = "warning"  // Warning messages displayed in normal block
)

func (MessageType) Valid added in v0.16.0

func (t MessageType) Valid() bool

Valid reports whether the MessageType is a known value.

type Session

type Session struct {
	ID        types.SessionID     `firestore:"id" json:"id"`
	TicketID  types.TicketID      `firestore:"ticket_id" json:"ticket_id"`
	RequestID string              `firestore:"request_id" json:"request_id"`
	Status    types.SessionStatus `firestore:"status" json:"status"`
	UserID    types.UserID        `firestore:"user_id" json:"user_id"`
	Query     string              `firestore:"query" json:"query"`
	SlackURL  string              `firestore:"slack_url" json:"slack_url"`
	Intent    string              `firestore:"intent" json:"intent"`
	CreatedAt time.Time           `firestore:"created_at" json:"created_at"`
	UpdatedAt time.Time           `firestore:"updated_at" json:"updated_at"`

	// Source identifies the channel the Session is bound to. Empty on data
	// written by pre-redesign code; readers should treat the empty value as
	// "unknown" and rely on migration to backfill.
	Source SessionSource `firestore:"source,omitempty" json:"source,omitempty"`

	// ChannelRef carries the external channel identifier for Slack
	// Sessions. nil for Web/CLI.
	ChannelRef *ChannelRef `firestore:"channel_ref,omitempty" json:"channel_ref,omitempty"`

	// TicketIDPtr allows nil (ticketless Slack Session). While the
	// non-nullable TicketID above remains for legacy writers, new code
	// should prefer reading/writing through TicketIDPtr. Phase 7 merges
	// these two into a single nullable field.
	TicketIDPtr *types.TicketID `firestore:"ticket_id_ptr,omitempty" json:"ticket_id_ptr,omitempty"`

	// Lock expresses the Slack Session's activity lock (nil = unlocked).
	// Always nil on Web and CLI Sessions, since those are born per-request.
	Lock *SessionLock `firestore:"lock,omitempty" json:"lock,omitempty"`

	// LastActiveAt records the moment the most recent Turn completed. Pure
	// informational; lock eligibility is judged from Lock.ExpiresAt, not
	// from this field.
	LastActiveAt time.Time `firestore:"last_active_at,omitzero" json:"last_active_at,omitzero"`
}

Session represents a chat session with its execution status.

Field evolution (chat-session-redesign spec): the following fields are retained for Phase 1-6 compatibility and will be removed in Phase 7:

RequestID, Status, Query, SlackURL, Intent, UpdatedAt

The authoritative fields for the new model are Source / ChannelRef / LastActiveAt / Lock / TicketIDPtr, plus the existing ID / UserID / CreatedAt.

func NewSession deprecated

func NewSession(ctx context.Context, ticketID types.TicketID, userID types.UserID, query string, slackURL string) *Session

NewSession creates a new session with running status.

Deprecated: this constructor is the pre-redesign signature retained for Phase 1-6 compatibility. New code should use NewSessionV2, which names the redesign fields (Source / ChannelRef / TicketIDPtr). Both APIs populate the same Session struct; the only difference is which fields are set.

func NewSessionV2 added in v0.16.0

func NewSessionV2(
	ctx context.Context,
	id types.SessionID,
	source SessionSource,
	ticketID *types.TicketID,
	channelRef *ChannelRef,
	userID types.UserID,
) *Session

NewSessionV2 constructs a Session using the chat-session-redesign model.

The legacy fields (RequestID / Status / Query / SlackURL / Intent / UpdatedAt) are set to their zero values. Callers should prefer this constructor for new code paths.

id may be empty, in which case a random SessionID is assigned. Providing id explicitly is how deterministic Slack Session IDs (see SessionResolver) are materialized.

func (*Session) TicketIDOrNil added in v0.16.0

func (s *Session) TicketIDOrNil() *types.TicketID

TicketIDOrNil returns the effective TicketID pointer, preferring TicketIDPtr but falling back to the legacy TicketID when TicketIDPtr is nil and TicketID is populated. This shim smooths the migration path.

func (*Session) TouchLastActive added in v0.16.0

func (s *Session) TouchLastActive(ctx context.Context)

TouchLastActive stamps LastActiveAt to the current clock.

func (*Session) UpdateIntent

func (s *Session) UpdateIntent(ctx context.Context, intent string)

UpdateIntent updates the session intent

func (*Session) UpdateStatus

func (s *Session) UpdateStatus(ctx context.Context, status types.SessionStatus)

UpdateStatus updates the session status

type SessionLock added in v0.16.0

type SessionLock struct {
	// HolderID is the request_id of the goroutine holding the lock.
	HolderID string `firestore:"holder_id" json:"holder_id"`
	// AcquiredAt is the instant the lock was first granted.
	AcquiredAt time.Time `firestore:"acquired_at" json:"acquired_at"`
	// ExpiresAt is AcquiredAt + TTL (default 3 minutes). The lock is
	// considered stale once ExpiresAt <= now, at which point another
	// holder may take over.
	ExpiresAt time.Time `firestore:"expires_at" json:"expires_at"`
}

SessionLock is embedded in a Session.Lock field to express ownership of a Slack Session by a specific in-flight request. When Lock is nil the Session is unlocked.

SessionLock is the persistent state; the runtime "Lock" handle returned by the LockService (see pkg/service/session) is a separate type that holds unexported dependencies (repo client, clock) and exposes Refresh/Release.

func (*SessionLock) IsExpired added in v0.16.0

func (l *SessionLock) IsExpired(now time.Time) bool

IsExpired reports whether the lock has passed its TTL relative to now.

type SessionSource added in v0.16.0

type SessionSource string

SessionSource identifies the channel that a Session is bound to. A Session is tied to exactly one source for its lifetime.

const (
	// SessionSourceSlack indicates the Session represents a Slack thread
	// conversation. Slack Sessions are resolved from (ticket_id, thread) and
	// persist across multiple @warren mentions.
	SessionSourceSlack SessionSource = "slack"

	// SessionSourceWeb indicates the Session was started from the Web UI via
	// a WebSocket connection. A new Web Session is created for each
	// connection / Start-Chat action.
	SessionSourceWeb SessionSource = "web"

	// SessionSourceCLI indicates the Session was started from the `warren
	// chat` CLI command. A new CLI Session is created per invocation; an
	// interactive session may contain multiple Turns within it.
	SessionSourceCLI SessionSource = "cli"
)

func (SessionSource) Valid added in v0.16.0

func (s SessionSource) Valid() bool

Valid reports whether the SessionSource is one of the known values.

type Turn added in v0.16.0

type Turn struct {
	ID        types.TurnID    `firestore:"id" json:"id"`
	SessionID types.SessionID `firestore:"session_id" json:"session_id"`
	RequestID string          `firestore:"request_id" json:"request_id"`
	Status    TurnStatus      `firestore:"status" json:"status"`
	Intent    string          `firestore:"intent" json:"intent"`
	StartedAt time.Time       `firestore:"started_at" json:"started_at"`
	EndedAt   *time.Time      `firestore:"ended_at,omitempty" json:"ended_at,omitempty"`
}

Turn represents a single AI request/response cycle inside a Session. A Session may contain many Turns (each Slack mention, each WebSocket chat_message, each CLI line in interactive mode).

Messages that are produced as part of the AI work belonging to this Turn carry its TurnID. Messages that are not AI-driven (e.g. Slack thread messages that were not @warren mentions) carry a nil TurnID.

func NewTurn added in v0.16.0

func NewTurn(ctx context.Context, sessionID types.SessionID) *Turn

NewTurn constructs a running Turn. RequestID is taken from ctx so log correlation works out of the box.

func (*Turn) Close added in v0.16.0

func (t *Turn) Close(ctx context.Context, status TurnStatus)

Close transitions the Turn to the given terminal status and sets EndedAt.

Calling Close on an already-closed Turn is a no-op so that defer-based cleanup paths can safely call Close even when the success path has already closed the Turn.

func (*Turn) UpdateIntent added in v0.16.0

func (t *Turn) UpdateIntent(intent string)

UpdateIntent sets the AI-judged intent for this Turn. Can be called multiple times; the latest value wins.

type TurnStatus added in v0.16.0

type TurnStatus string

TurnStatus enumerates the lifecycle states of a Turn.

const (
	// TurnStatusRunning means the AI is currently processing the request.
	TurnStatusRunning TurnStatus = "running"
	// TurnStatusCompleted means the Turn ended normally.
	TurnStatusCompleted TurnStatus = "completed"
	// TurnStatusAborted means the Turn ended abnormally (panic, cancellation,
	// lock release on crash recovery, etc.).
	TurnStatusAborted TurnStatus = "aborted"
)

func (TurnStatus) Valid added in v0.16.0

func (s TurnStatus) Valid() bool

Valid reports whether the TurnStatus is a known value.

Jump to

Keyboard shortcuts

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