Documentation
¶
Index ¶
- Variables
- func AtomicWriteFile(path string, data []byte, mode os.FileMode) error
- func SortRoles(roles []*model.Role)
- func SortUsers(users []*model.User)
- type ACPProbeCacheRepo
- type AgentCatalogRepo
- type AuthRepo
- func (r *AuthRepo) ConfigEntriesExist() (bool, error)
- func (r *AuthRepo) DeleteRole(id string) error
- func (r *AuthRepo) DeleteSession(hash string) error
- func (r *AuthRepo) ListRoles() ([]*model.Role, error)
- func (r *AuthRepo) ListSessions() ([]*model.AuthSession, error)
- func (r *AuthRepo) ListUsers() ([]*model.User, error)
- func (r *AuthRepo) LoadSession(hash string) (*model.AuthSession, error)
- func (r *AuthRepo) LoadSystem() (*model.AuthSystem, error)
- func (r *AuthRepo) SaveRole(value *model.Role) error
- func (r *AuthRepo) SaveSession(value *model.AuthSession) error
- func (r *AuthRepo) SaveSystem(value *model.AuthSystem) error
- func (r *AuthRepo) SaveUser(value *model.User) error
- type ChatContextRepo
- type CodexAccountBackup
- type CodexAccountFiles
- type CodexAccountRepo
- func (r *CodexAccountRepo) Load() (*CodexAccountStore, error)
- func (r *CodexAccountRepo) PrepareLoginHome(id string) (string, error)
- func (r *CodexAccountRepo) ReadFiles(home string) (CodexAccountFiles, error)
- func (r *CodexAccountRepo) RemoveLoginHome(id string) error
- func (r *CodexAccountRepo) ReplaceFiles(before, after CodexAccountFiles) error
- func (r *CodexAccountRepo) Rollback(transaction *CodexAccountTransaction) error
- func (r *CodexAccountRepo) Save(state *CodexAccountStore) error
- type CodexAccountStore
- type CodexAccountTransaction
- type FileShareRepo
- type GraphRunRepo
- type GraphWorkflowRepo
- type IMJobMappingRepo
- type IMMessageRepo
- type JobRepo
- type LockedRepo
- type MessagePage
- type MessagePresetRepo
- type MessagesFingerprint
- type PagedChatContextRepo
- type PromptRepo
- type RecentDirs
- type RecentDirsRepo
- type ScheduleRepo
- type SessionRepo
- type SettingsRepo
- type StoredCodexAccount
- type StoredMessagePresetConfig
- type UserInputRepo
- type WeChatOutboxRepo
- type WorkspaceRepo
Constants ¶
This section is empty.
Variables ¶
var ErrGraphWorkflowVersionConflict = errors.New("graph workflow version conflict")
var ErrMessagePageChanged = errors.New("message history changed while paging")
var ErrMessagePresetConflict = errors.New("message preset configuration conflict")
Functions ¶
func AtomicWriteFile ¶
AtomicWriteFile writes data to path using the canonical temp-file + rename dance so a concurrent reader never observes a half-written file and a crash cannot leave a truncated file behind.
Algorithm:
- mkdir -p the parent directory (matching the previous sandbox behaviour).
- Create a temp file in the same directory (so the final rename is atomic on POSIX — rename(2) across directories may not be).
- Write, fsync the file, and close it.
- Rename the temp file over the destination.
- Best-effort fsync of the parent directory so the rename itself is durable.
The signature matches the standard library's WriteFile to make callers interchangeable; `mode` is applied to the final file.
Types ¶
type ACPProbeCacheRepo ¶
type ACPProbeCacheRepo interface {
Load(ctx context.Context) (*model.ACPProbeCacheSnapshot, error)
Save(ctx context.Context, snapshot *model.ACPProbeCacheSnapshot) error
}
func NewACPProbeCacheRepo ¶
func NewACPProbeCacheRepo() (ACPProbeCacheRepo, error)
type AgentCatalogRepo ¶
type AgentCatalogRepo interface {
Load(ctx context.Context) (*model.AgentCatalogSnapshot, error)
Save(ctx context.Context, snapshot *model.AgentCatalogSnapshot) error
}
func NewAgentCatalogRepo ¶
func NewAgentCatalogRepo() (AgentCatalogRepo, error)
type AuthRepo ¶
type AuthRepo struct {
// contains filtered or unexported fields
}
func NewAuthRepo ¶
func (*AuthRepo) ConfigEntriesExist ¶
func (*AuthRepo) DeleteRole ¶
func (*AuthRepo) DeleteSession ¶
func (*AuthRepo) ListSessions ¶
func (r *AuthRepo) ListSessions() ([]*model.AuthSession, error)
func (*AuthRepo) LoadSession ¶
func (r *AuthRepo) LoadSession(hash string) (*model.AuthSession, error)
func (*AuthRepo) LoadSystem ¶
func (r *AuthRepo) LoadSystem() (*model.AuthSystem, error)
func (*AuthRepo) SaveSession ¶
func (r *AuthRepo) SaveSession(value *model.AuthSession) error
func (*AuthRepo) SaveSystem ¶
func (r *AuthRepo) SaveSystem(value *model.AuthSystem) error
type ChatContextRepo ¶
type ChatContextRepo interface {
LoadAllMessages(ctx context.Context) ([]*schema.Message, error)
CountMessage(ctx context.Context) (int, error)
// MessagesFingerprint returns a content-aware identifier for the
// current state of messages.jsonl. Used by the ACP drift check to
// detect cross-path mutations that count alone misses (in-place row
// rewrites — e.g. ReplacePlaceholderToolResult — or hand edits that
// keep the row count stable but change content). The returned hash
// is FNV-64 over the on-disk file contents, which is reproducible
// when nothing has changed and changes whenever any byte does. Empty
// / missing file yields a zero-valued fingerprint.
MessagesFingerprint(ctx context.Context) (MessagesFingerprint, error)
// AppendMessages appends the chat messages to the file.
AppendMessages(ctx context.Context, msgs []*schema.Message) error
// ReplaceMessages rewrites the full message history.
ReplaceMessages(ctx context.Context, msgs []*schema.Message) error
// ReplacePlaceholderToolResult swaps a previously-persisted placeholder
// tool_result (matching toolCallID and carrying the placeholder flag)
// with the real tool result. Used by the round builder when a terminal
// event arrives AFTER an eager-flush already wrote a [placeholder]
// superseded row: without this stitch, the placeholder would stay on
// disk forever and pollute both the history view and the next round's
// LLM context.
//
// Returns stitched=true iff a matching placeholder row was found and
// replaced. Returns stitched=false (no error) when the placeholder is
// gone — e.g. a concurrent orphan-tail truncate already cut the row.
// Errors surface I/O failures only.
ReplacePlaceholderToolResult(ctx context.Context, toolCallID string, real *schema.Message) (bool, error)
// WithLock acquires the per-session write lock and runs fn with a
// LockedRepo handle whose methods bypass the per-call locking. Used
// by callers that need a multi-step compound operation (e.g.
// BeginRun's truncate-then-append) to be atomic across other
// ChatContextRepo instances pointed at the same session directory.
// Calling the regular ChatContextRepo methods inside fn would
// deadlock — use the LockedRepo handle.
//
// ctx gates the lock acquisition: a Run whose persist deadline has
// already expired observes ctx.Err() instead of blocking on a
// contended lock. Once fn starts running, ctx cancellation no
// longer interrupts the in-flight critical section — fn is
// expected to honour ctx itself for its own per-step IO.
WithLock(ctx context.Context, fn func(tx LockedRepo) error) error
}
type CodexAccountBackup ¶
type CodexAccountBackup struct {
Files CodexAccountFiles `json:"files"`
ManagedID string `json:"managed_id"`
ConfigApplied bool `json:"config_applied"`
}
type CodexAccountFiles ¶
type CodexAccountFiles struct {
Home string `json:"home"`
Auth *string `json:"auth"`
Config *string `json:"config"`
}
func (CodexAccountFiles) Revision ¶
func (f CodexAccountFiles) Revision() string
type CodexAccountRepo ¶
type CodexAccountRepo struct {
// contains filtered or unexported fields
}
func NewCodexAccountRepo ¶
func NewCodexAccountRepo() (*CodexAccountRepo, error)
func (*CodexAccountRepo) Load ¶
func (r *CodexAccountRepo) Load() (*CodexAccountStore, error)
func (*CodexAccountRepo) PrepareLoginHome ¶
func (r *CodexAccountRepo) PrepareLoginHome(id string) (string, error)
func (*CodexAccountRepo) ReadFiles ¶
func (r *CodexAccountRepo) ReadFiles(home string) (CodexAccountFiles, error)
func (*CodexAccountRepo) RemoveLoginHome ¶
func (r *CodexAccountRepo) RemoveLoginHome(id string) error
func (*CodexAccountRepo) ReplaceFiles ¶
func (r *CodexAccountRepo) ReplaceFiles(before, after CodexAccountFiles) error
ReplaceFiles compares each file immediately before replacement. Restoration accepts either side of an interrupted transaction and refuses external edits.
func (*CodexAccountRepo) Rollback ¶
func (r *CodexAccountRepo) Rollback(transaction *CodexAccountTransaction) error
func (*CodexAccountRepo) Save ¶
func (r *CodexAccountRepo) Save(state *CodexAccountStore) error
type CodexAccountStore ¶
type CodexAccountStore struct {
Version int `json:"version"`
Revision uint64 `json:"revision"`
Accounts []StoredCodexAccount `json:"accounts"`
ActiveID string `json:"active_id"`
ActiveHome string `json:"active_home"`
ConfigApplied bool `json:"config_applied"`
Backup *CodexAccountBackup `json:"backup,omitempty"`
Pending *CodexAccountTransaction `json:"pending,omitempty"`
Operations []model.CodexAccountOperation `json:"operations"`
OperationHashes map[string]string `json:"operation_hashes,omitempty"`
}
type CodexAccountTransaction ¶
type CodexAccountTransaction struct {
Before CodexAccountBackup `json:"before"`
After CodexAccountFiles `json:"after"`
Operation model.CodexAccountOperation `json:"operation"`
}
type FileShareRepo ¶
type FileShareRepo interface {
}
func GetFileShareRepo ¶
func GetFileShareRepo() FileShareRepo
type GraphRunRepo ¶
type GraphRunRepo interface {
RegisterRun(ctx context.Context, run *model.GraphRun) error
RegisterRunLocation(ctx context.Context, runID, workspaceID, jobID string) error
SaveRun(ctx context.Context, run *model.GraphRun) error
GetRun(ctx context.Context, runID string) (*model.GraphRun, error)
SaveInstances(ctx context.Context, runID string, instances map[string]model.GraphInstanceState) error
GetInstances(ctx context.Context, runID string) (map[string]model.GraphInstanceState, error)
SaveEdges(ctx context.Context, runID string, edges map[string]model.GraphEdgeState) error
GetEdges(ctx context.Context, runID string) (map[string]model.GraphEdgeState, error)
SaveVariables(ctx context.Context, runID string, variables map[string]map[string]string) error
GetVariables(ctx context.Context, runID string) (map[string]map[string]string, error)
SaveSessionLineage(ctx context.Context, runID string, lineage map[string]model.GraphSessionLineage) error
GetSessionLineage(ctx context.Context, runID string) (map[string]model.GraphSessionLineage, error)
SaveProgress(ctx context.Context, runID string, progress *model.GraphProgress) error
GetProgress(ctx context.Context, runID string) (*model.GraphProgress, error)
SaveResume(ctx context.Context, runID string, resume *model.GraphResumeState) error
GetResume(ctx context.Context, runID string) (*model.GraphResumeState, error)
AppendEvent(ctx context.Context, runID string, event *model.GraphEvent) error
ListEvents(ctx context.Context, runID string, startLine int, count *int) ([]model.GraphEvent, error)
// CountEvents returns the number of persisted event lines without reading
// their content. Used by GetRunStatus to expose an event count (the SSE
// resume cursor seed) without serialising the whole event log into the
// status response. A missing events file yields (0, nil).
CountEvents(ctx context.Context, runID string) (int, error)
DeleteRun(ctx context.Context, runID string) error
}
GraphRunRepo owns GraphRun runtime artifacts. A run is stored as a directory under its bound Job directory so deleting a Job can keep its graph runtime artifacts colocated with sessions and metadata.
func NewGraphRunRepo ¶
func NewGraphRunRepo() (GraphRunRepo, error)
type GraphWorkflowRepo ¶
type GraphWorkflowRepo interface {
Save(ctx context.Context, wf *model.GraphWorkflow) error
Get(ctx context.Context, id string) (*model.GraphWorkflow, error)
List(ctx context.Context) ([]*model.GraphWorkflow, []model.GraphWorkflowWarning, error)
Update(ctx context.Context, id string, wf *model.GraphWorkflow) error
UpdateIfUnchanged(ctx context.Context, id string, wf *model.GraphWorkflow, expectedUpdatedAt *time.Time) error
Delete(ctx context.Context, id string, expectedUpdatedAt *time.Time) error
}
GraphWorkflowRepo persists editable/saved Graph workflow configs, one JSON file per workflow keyed by ID.
func NewGraphWorkflowRepo ¶
func NewGraphWorkflowRepo() (GraphWorkflowRepo, error)
type IMJobMappingRepo ¶
type IMJobMappingRepo interface {
Get(platform, chatID string) (*model.IMJobMapping, error)
Save(m *model.IMJobMapping) error
}
func NewIMJobMappingRepo ¶
func NewIMJobMappingRepo() (IMJobMappingRepo, error)
type IMMessageRepo ¶
func NewIMMessageRepo ¶
func NewIMMessageRepo() IMMessageRepo
type JobRepo ¶
type JobRepo interface {
Save(jobID string, job *model.Job) error
Load(jobID string) (*model.Job, error)
ListIDs() ([]string, error)
LoadAll() ([]*model.Job, error)
// SweepDeleted removes complete on-disk job directories whose durable job
// metadata is marked Deleted. It is the startup recovery half of the
// two-phase Job deletion protocol.
SweepDeleted() error
}
func NewJobRepo ¶
NewJobRepo creates a JobRepo. Root dir: {LOCAL_MEMORY}/quartet/data/workspaces/{wsID}/jobs/.
type LockedRepo ¶
type LockedRepo interface {
LoadAllMessages(ctx context.Context) ([]*schema.Message, error)
AppendMessages(ctx context.Context, msgs []*schema.Message) error
ReplaceMessages(ctx context.Context, msgs []*schema.Message) error
}
LockedRepo exposes the unlocked variants of the repo's read/write methods. Returned exclusively through ChatContextRepo.WithLock so the caller already holds the per-session write lock; the methods here must NEVER take the lock themselves or the WithLock holder would deadlock against itself.
ctx is threaded for parity with ChatContextRepo so an inner operation can cooperate with cancellation (e.g. log breadcrumbs, future ctx-aware fileserver calls). The lock itself stays held for the full WithLock body — fn is the natural cancellation boundary.
type MessagePage ¶
type MessagePresetRepo ¶
type MessagePresetRepo interface {
GetGlobal() (*StoredMessagePresetConfig, error)
GetWorkspace(workspaceID string) (*StoredMessagePresetConfig, error)
ListWorkspaceFiles() ([]string, error)
SaveGlobal(expectedRevision string, config *model.MessagePresetConfig) (*StoredMessagePresetConfig, error)
SaveWorkspace(workspaceID, expectedRevision string, config *model.MessagePresetConfig) (*StoredMessagePresetConfig, error)
DeleteWorkspace(workspaceID, expectedRevision string) error
RebindWorkspace(sourceID, targetID, expectedRevision string, config *model.MessagePresetConfig) error
}
func NewMessagePresetRepo ¶
func NewMessagePresetRepo() (MessagePresetRepo, error)
type MessagesFingerprint ¶
type MessagesFingerprint struct {
Count int `json:"count,omitempty"`
Hash string `json:"hash,omitempty"`
}
MessagesFingerprint identifies the state of messages.jsonl for drift detection. Count alone is insufficient — ReplacePlaceholderToolResult rewrites a row in place without changing the count, so two distinct on-disk states can share the same Count. The Hash captures the full byte content so any mutation (in-place rewrite, hand edit, append + truncate that nets to the same count) trips the drift check.
The zero value (Count=0, Hash="") represents "no messages on disk" and is returned for missing or empty files. Two zero values compare equal, so an empty session is correctly diagnosed as "no drift".
func (MessagesFingerprint) Equal ¶
func (f MessagesFingerprint) Equal(other MessagesFingerprint) bool
Equal reports whether two fingerprints describe the same on-disk state. Used by the ACP drift check.
type PagedChatContextRepo ¶
type PagedChatContextRepo interface {
ChatContextRepo
// LoadMessagePage reads a reverse page ending immediately before
// beforeOffset. A zero beforeOffset starts at the current end of file.
// boundaryEndOffset and boundaryHash validate the first row of the page
// already returned to the client while still allowing tail appends.
LoadMessagePage(ctx context.Context, beforeOffset, boundaryEndOffset int64, boundaryHash string, limit int) (*MessagePage, error)
}
PagedChatContextRepo adds UI-oriented reverse paging without forcing Agent context test doubles, which only need the full-history contract, to implement presentation-specific reads.
func NewChatContextRepo ¶
func NewChatContextRepo(wsID, jobID, sessionID string) (PagedChatContextRepo, error)
NewChatContextRepo creates a ChatContextRepo. Root dir: {LOCAL_MEMORY}/quartet/data/workspaces/{wsID}/jobs/{jobID}/sessions/{sessionID}/.
Concurrency: every method serialises against other ChatContextRepo instances pointed at the same sessionDir via the process-wide lock registry in session_locks.go. Per-instance mutexes can't help here because acp / shell-persist / web-reload each construct their own instance for the same session.
type PromptRepo ¶
type PromptRepo interface {
Get(ctx context.Context, key string) (string, error)
Save(ctx context.Context, key string, content string) error
}
func NewPromptRepo ¶
func NewPromptRepo() (PromptRepo, error)
type RecentDirs ¶
type RecentDirs struct {
Dirs []string `json:"dirs"`
}
type RecentDirsRepo ¶
type RecentDirsRepo interface {
Get() (*RecentDirs, error)
Add(ctx context.Context, dir string) error
}
func NewRecentDirsRepo ¶
func NewRecentDirsRepo() (RecentDirsRepo, error)
type ScheduleRepo ¶
type ScheduleRepo interface {
Create(ctx context.Context, task *model.ScheduledTask) error
SaveDefinition(ctx context.Context, task *model.ScheduledTask) error
SaveState(ctx context.Context, task *model.ScheduledTask) error
UpdateActivation(ctx context.Context, id string, enabled *bool, nextRunAt *time.Time) error
ToggleEnabled(ctx context.Context, id string, nextRunAt *time.Time) error
Get(ctx context.Context, id string) (*model.ScheduledTask, error)
List(ctx context.Context) ([]*model.ScheduledTask, error)
Delete(ctx context.Context, id string) error
}
func NewScheduleRepo ¶
func NewScheduleRepo() (ScheduleRepo, error)
type SessionRepo ¶
type SessionRepo interface {
Save(sessionID string, meta *model.Session) error
Load(sessionID string) (*model.Session, error)
ListIDs() ([]string, error)
LoadAll() ([]*model.Session, error)
}
func NewSessionRepo ¶
func NewSessionRepo(wsID, jobID string) (SessionRepo, error)
NewSessionRepo creates a SessionRepo. Root dir: {LOCAL_MEMORY}/quartet/data/workspaces/{wsID}/jobs/{jobID}/sessions/.
type SettingsRepo ¶
func NewSettingsRepo ¶
func NewSettingsRepo() (SettingsRepo, error)
type StoredCodexAccount ¶
type StoredCodexAccount struct {
Info model.CodexAccount `json:"info"`
Identity string `json:"identity"`
Auth string `json:"auth"`
Config *string `json:"config,omitempty"`
}
type StoredMessagePresetConfig ¶
type StoredMessagePresetConfig struct {
Config *model.MessagePresetConfig
Revision string
File string
}
type UserInputRepo ¶
UserInputRepo appends "真实用户输入" entries — the narrow-spec stream that covers IM admin private chat + Web, flat-dated under {LOCAL_MEMORY}/quartet/data/user-input/YYYY-MM-DD.jsonl. Coexists with IMMessageRepo: the two feeds have different intakes and different consumers (see docs/feature-2026-05-03-user-input-logging.md §4).
func NewUserInputRepo ¶
func NewUserInputRepo() UserInputRepo
type WeChatOutboxRepo ¶
type WeChatOutboxRepo interface {
Save(ctx context.Context, task *model.WeChatOutboxTask) error
Get(ctx context.Context, id string) (*model.WeChatOutboxTask, error)
List(ctx context.Context) ([]*model.WeChatOutboxTask, error)
}
func NewWeChatOutboxRepo ¶
func NewWeChatOutboxRepo() (WeChatOutboxRepo, error)
type WorkspaceRepo ¶
type WorkspaceRepo interface {
Save(id string, ws *model.Workspace) error
Load(id string) (*model.Workspace, error)
ListIDs() ([]string, error)
LoadAll() ([]*model.Workspace, error)
// SweepDeleted removes on-disk directories for workspaces marked as
// deleted. Split from LoadAll so the read path has no write side effects.
SweepDeleted() error
RemoveDir(id string) error
}
func NewWorkspaceRepo ¶
func NewWorkspaceRepo() (WorkspaceRepo, error)
Source Files
¶
- acp_probe_cache.go
- agent_catalog.go
- atomic.go
- auth.go
- chat_context.go
- chat_context_cache.go
- codex_account.go
- corrupt.go
- file_share.go
- graph_run.go
- graph_workflow.go
- ids.go
- im_job_mapping.go
- im_message.go
- job.go
- message_preset.go
- prompt.go
- recent_dirs.go
- schedule.go
- session.go
- session_locks.go
- settings.go
- user_input.go
- wechat_outbox.go
- workspace.go