Documentation
¶
Index ¶
- Variables
- func ExtractDisplayData(message llm.Message) interface{}
- func GenerateSubagentSystemPrompt(workingDir string) (string, error)
- func GenerateSystemPrompt(workingDir string) (string, error)
- func IsAutogeneratedFile(path string, content []byte) bool
- func IsAutogeneratedPath(path string) bool
- func LoggerMiddleware(logger *slog.Logger) func(http.Handler) http.Handler
- func RequireHeaderMiddleware(headerName string) func(http.Handler) http.Handler
- type APIMessage
- type ChannelTypeInfo
- type ChatRequest
- type CodebaseInfo
- type CommitInfo
- type ConfigField
- type ContinueConversationRequest
- type ConversationListUpdate
- type ConversationManager
- func (cm *ConversationManager) AcceptUserMessage(ctx context.Context, service llm.Service, modelID string, message llm.Message) (bool, error)
- func (cm *ConversationManager) CancelConversation(ctx context.Context) error
- func (cm *ConversationManager) GetModel() string
- func (cm *ConversationManager) Hydrate(ctx context.Context) error
- func (cm *ConversationManager) IsAgentWorking() bool
- func (cm *ConversationManager) ResetLoop()
- func (cm *ConversationManager) SetAgentWorking(working bool)
- func (cm *ConversationManager) SwitchModel(ctx context.Context, service llm.Service, modelID string, ...) error
- func (cm *ConversationManager) Touch()
- type ConversationState
- type ConversationWithState
- type CreateModelRequest
- type CreateNotificationChannelRequest
- type DirectoryEntry
- type DuplicateModelRequest
- type EditMessageRequest
- type ExecMessage
- type ForkConversationRequest
- type GitDiffInfo
- type GitFileDiff
- type GitFileInfo
- type GitInfo
- type GitInfoUserData
- type LLMConfig
- type LLMProvider
- type Link
- type ListDirectoryResponse
- type ModelAPI
- type ModelInfo
- type NotificationChannelAPI
- type ReleaseInfo
- type RenameRequest
- type Server
- func (s *Server) Cleanup()
- func (s *Server) EnqueueIndex(conversationID string)
- func (s *Server) IsAgentWorking(conversationID string) bool
- func (s *Server) RegisterNotificationChannel(ch notifications.Channel)
- func (s *Server) RegisterRoutes(mux *http.ServeMux)
- func (s *Server) ReloadNotificationChannels()
- func (s *Server) SeedNotificationChannelsFromConfig(configs []map[string]any)
- func (s *Server) SetClusterNode(node *cluster.Node)
- func (s *Server) SetEmbedder(e memory.Embedder)
- func (s *Server) SetMemoryDB(mdb *memory.DB)
- func (s *Server) SetMuninnSink(sink *muninn.Sink)
- func (s *Server) Start(port string) error
- func (s *Server) StartWithListener(listener net.Listener) error
- type StaticCommitInfo
- type StreamResponse
- type SubagentRunner
- type SubagentSystemPromptData
- type SwitchModelRequest
- type SystemPromptData
- type TestModelRequest
- type TouchedFile
- type UpdateModelRequest
- type UpdateNotificationChannelRequest
- type VersionChecker
- type VersionInfo
Constants ¶
This section is empty.
Variables ¶
var DBPath string
DBPath is the path to the percy database, set at startup
Functions ¶
func ExtractDisplayData ¶
ExtractDisplayData extracts display data from message content for storage
func GenerateSubagentSystemPrompt ¶
GenerateSubagentSystemPrompt generates a minimal system prompt for subagent conversations.
func GenerateSystemPrompt ¶
GenerateSystemPrompt generates the system prompt using the embedded template. If workingDir is empty, it uses the current working directory.
func IsAutogeneratedFile ¶
IsAutogeneratedFile reports whether a file is autogenerated based on its path and content. For Go files, it also analyzes the content for autogeneration markers.
func IsAutogeneratedPath ¶
IsAutogeneratedPath reports whether a file path suggests it's autogenerated. This checks for common autogenerated file patterns based on path alone.
func LoggerMiddleware ¶
LoggerMiddleware adds request logging using slog-http
Types ¶
type APIMessage ¶
type APIMessage struct {
MessageID string `json:"message_id"`
ConversationID string `json:"conversation_id"`
SequenceID int64 `json:"sequence_id"`
Type string `json:"type"`
LlmData *string `json:"llm_data,omitempty"`
UserData *string `json:"user_data,omitempty"`
UsageData *string `json:"usage_data,omitempty"`
CreatedAt time.Time `json:"created_at"`
DisplayData *string `json:"display_data,omitempty"`
EndOfTurn *bool `json:"end_of_turn,omitempty"`
}
APIMessage is the message format sent to clients TODO: We could maybe omit llm_data when display_data is available
type ChannelTypeInfo ¶
type ChannelTypeInfo struct {
Type string `json:"type"`
Label string `json:"label"`
ConfigFields []ConfigField `json:"config_fields"`
}
type ChatRequest ¶
type ChatRequest struct {
Message string `json:"message"`
Model string `json:"model,omitempty"`
Cwd string `json:"cwd,omitempty"`
}
ChatRequest represents a chat message from the user
type CodebaseInfo ¶
type CommitInfo ¶
type CommitInfo struct {
SHA string `json:"sha"`
Message string `json:"message"`
Author string `json:"author"`
Date time.Time `json:"date"`
}
CommitInfo represents a commit in the changelog.
type ConfigField ¶
type ContinueConversationRequest ¶
type ContinueConversationRequest struct {
SourceConversationID string `json:"source_conversation_id"`
Model string `json:"model,omitempty"`
Cwd string `json:"cwd,omitempty"`
}
ContinueConversationRequest represents the request to continue a conversation in a new one
type ConversationListUpdate ¶
type ConversationListUpdate struct {
Type string `json:"type"` // "update", "delete"
Conversation *generated.Conversation `json:"conversation,omitempty"`
ConversationID string `json:"conversation_id,omitempty"` // For deletes
}
ConversationListUpdate represents an update to the conversation list
type ConversationManager ¶
type ConversationManager struct {
// contains filtered or unexported fields
}
ConversationManager manages a single active conversation
func NewConversationManager ¶
func NewConversationManager(conversationID string, database *db.DB, memoryDB *memory.DB, embedder memory.Embedder, baseLogger *slog.Logger, toolSetConfig claudetool.ToolSetConfig, recordMessage loop.MessageRecordFunc, onStateChange func(ConversationState), onConversationDone func(string)) *ConversationManager
NewConversationManager constructs a manager with dependencies but defers hydration until needed.
func (*ConversationManager) AcceptUserMessage ¶
func (cm *ConversationManager) AcceptUserMessage(ctx context.Context, service llm.Service, modelID string, message llm.Message) (bool, error)
AcceptUserMessage enqueues a user message, ensuring the loop is ready first. The message is recorded to the database immediately so it appears in the UI, even if the loop is busy processing a previous request.
func (*ConversationManager) CancelConversation ¶
func (cm *ConversationManager) CancelConversation(ctx context.Context) error
CancelConversation cancels the current conversation loop and records a cancelled tool result if a tool was in progress
func (*ConversationManager) GetModel ¶
func (cm *ConversationManager) GetModel() string
GetModel returns the model ID used by this conversation.
func (*ConversationManager) Hydrate ¶
func (cm *ConversationManager) Hydrate(ctx context.Context) error
Hydrate loads conversation metadata from the database and generates a system prompt if one doesn't exist yet. It does NOT cache the message history; ensureLoop reads messages fresh from the DB when creating a loop so that any messages added asynchronously (e.g. distillation) are always included.
func (*ConversationManager) IsAgentWorking ¶
func (cm *ConversationManager) IsAgentWorking() bool
IsAgentWorking returns the current agent working state.
func (*ConversationManager) ResetLoop ¶ added in v0.347.976101525
func (cm *ConversationManager) ResetLoop()
ResetLoop nils out the loop so the next AcceptUserMessage recreates it with fresh history from the database. Use after deleting messages.
func (*ConversationManager) SetAgentWorking ¶
func (cm *ConversationManager) SetAgentWorking(working bool)
SetAgentWorking updates the agent working state and notifies the server to broadcast.
func (*ConversationManager) SwitchModel ¶ added in v0.381.91062602
func (*ConversationManager) Touch ¶
func (cm *ConversationManager) Touch()
Touch updates last activity timestamp.
type ConversationState ¶
type ConversationState struct {
ConversationID string `json:"conversation_id"`
Working bool `json:"working"`
Model string `json:"model,omitempty"`
}
ConversationState represents the current state of a conversation. This is broadcast to all subscribers whenever the state changes.
type ConversationWithState ¶
type ConversationWithState struct {
generated.Conversation
Working bool `json:"working"`
}
ConversationWithState combines a conversation with its working state.
type CreateModelRequest ¶
type CreateModelRequest struct {
DisplayName string `json:"display_name"`
ProviderType string `json:"provider_type"`
Endpoint string `json:"endpoint"`
APIKey string `json:"api_key"`
ModelName string `json:"model_name"`
MaxTokens int64 `json:"max_tokens"`
Tags string `json:"tags"` // Comma-separated tags
}
CreateModelRequest is the request body for creating a model
type DirectoryEntry ¶
type DirectoryEntry struct {
Name string `json:"name"`
IsDir bool `json:"is_dir"`
GitHeadSubject string `json:"git_head_subject,omitempty"`
}
DirectoryEntry represents a single directory entry for the directory picker
type DuplicateModelRequest ¶
type DuplicateModelRequest struct {
DisplayName string `json:"display_name,omitempty"`
}
DuplicateModelRequest allows overriding fields when duplicating
type EditMessageRequest ¶ added in v0.347.976101525
type EditMessageRequest struct {
SequenceID int64 `json:"sequence_id"`
Message string `json:"message"`
}
EditMessageRequest is the request body for editing a message.
type ExecMessage ¶
type ExecMessage struct {
Type string `json:"type"`
Data string `json:"data,omitempty"`
Cols uint16 `json:"cols,omitempty"`
Rows uint16 `json:"rows,omitempty"`
}
ExecMessage is the message format for terminal websocket communication
type ForkConversationRequest ¶ added in v0.347.976101525
type ForkConversationRequest struct {
SourceConversationID string `json:"source_conversation_id"`
AtSequenceID int64 `json:"at_sequence_id"`
Model string `json:"model,omitempty"`
}
ForkConversationRequest is the request body for forking a conversation.
type GitDiffInfo ¶
type GitDiffInfo struct {
ID string `json:"id"`
Message string `json:"message"`
Author string `json:"author"`
Timestamp time.Time `json:"timestamp"`
FilesCount int `json:"filesCount"`
Additions int `json:"additions"`
Deletions int `json:"deletions"`
}
GitDiffInfo represents a commit or working changes
type GitFileDiff ¶
type GitFileDiff struct {
Path string `json:"path"`
OldContent string `json:"oldContent"`
NewContent string `json:"newContent"`
}
GitFileDiff represents the content of a file diff
type GitFileInfo ¶
type GitFileInfo struct {
Path string `json:"path"`
Status string `json:"status"` // added, modified, deleted
Additions int `json:"additions"`
Deletions int `json:"deletions"`
IsGenerated bool `json:"isGenerated"`
}
GitFileInfo represents a file in a diff
type GitInfoUserData ¶
type GitInfoUserData struct {
Worktree string `json:"worktree"`
Branch string `json:"branch"`
Commit string `json:"commit"`
Subject string `json:"subject"`
Text string `json:"text"` // Human-readable description
}
GitInfoUserData is the structured data stored in user_data for gitinfo messages.
type LLMConfig ¶
type LLMConfig struct {
// API keys for each provider
AnthropicAPIKey string
OpenAIAPIKey string
GeminiAPIKey string
FireworksAPIKey string
// Gateway is the base URL of the LLM gateway (optional)
Gateway string
// TerminalURL is the URL to the terminal interface (optional)
TerminalURL string
// DefaultModel is the default model to use (optional, defaults to models.Default())
DefaultModel string
// Links are custom links to be displayed in the UI (optional)
Links []Link
// NotificationChannels is a list of notification channel configs from percy.json.
// Each entry is a map with at least a "type" key, plus channel-specific fields.
NotificationChannels []map[string]any
// OllamaURL is the base URL of a local Ollama instance for auto-discovery.
// Default: "http://localhost:11434". Set to "" to disable.
OllamaURL string
// DB is the database for recording LLM requests (optional)
DB *db.DB
Logger *slog.Logger
}
LLMConfig holds all configuration for LLM services
type LLMProvider ¶
type LLMProvider interface {
GetService(modelID string) (llm.Service, error)
GetAvailableModels() []string
HasModel(modelID string) bool
GetModelInfo(modelID string) *models.ModelInfo
RefreshCustomModels() error
}
LLMProvider is an interface for getting LLM services
func NewLLMServiceManager ¶
func NewLLMServiceManager(cfg *LLMConfig) LLMProvider
NewLLMServiceManager creates a new LLM service manager from config
type Link ¶
type Link struct {
Title string `json:"title"`
IconSVG string `json:"icon_svg,omitempty"` // SVG path data for the icon
URL string `json:"url"`
}
Link represents a custom link to be displayed in the UI
type ListDirectoryResponse ¶
type ListDirectoryResponse struct {
Path string `json:"path"`
Parent string `json:"parent"`
Entries []DirectoryEntry `json:"entries"`
GitHeadSubject string `json:"git_head_subject,omitempty"`
GitWorktreeRoot string `json:"git_worktree_root,omitempty"`
}
ListDirectoryResponse is the response from the list-directory endpoint
type ModelAPI ¶
type ModelAPI struct {
ModelID string `json:"model_id"`
DisplayName string `json:"display_name"`
ProviderType string `json:"provider_type"`
Endpoint string `json:"endpoint"`
APIKey string `json:"api_key"`
ModelName string `json:"model_name"`
MaxTokens int64 `json:"max_tokens"`
Tags string `json:"tags"` // Comma-separated tags (e.g., "slug" for slug generation)
}
ModelAPI is the API representation of a model
type ModelInfo ¶
type ModelInfo struct {
ID string `json:"id"`
DisplayName string `json:"display_name,omitempty"`
Source string `json:"source,omitempty"` // Human-readable source (e.g., "exe.dev gateway", "$ANTHROPIC_API_KEY")
Ready bool `json:"ready"`
MaxContextTokens int `json:"max_context_tokens,omitempty"`
}
ModelInfo represents a model in the API response
type NotificationChannelAPI ¶
type ReleaseInfo ¶
type ReleaseInfo struct {
TagName string `json:"tag_name"`
Version string `json:"version"`
Commit string `json:"commit"`
CommitFull string `json:"commit_full"`
CommitTime string `json:"commit_time"`
PublishedAt string `json:"published_at"`
DownloadURLs map[string]string `json:"download_urls"`
ChecksumsURL string `json:"checksums_url"`
}
ReleaseInfo represents release metadata.
type RenameRequest ¶
type RenameRequest struct {
Slug string `json:"slug"`
}
RenameRequest represents a request to rename a conversation
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server manages the HTTP API and active conversations
func NewServer ¶
func NewServer(database *db.DB, llmManager LLMProvider, toolSetConfig claudetool.ToolSetConfig, logger *slog.Logger, predictableOnly bool, terminalURL, defaultModel, requireHeader string, links []Link) *Server
NewServer creates a new server instance
func (*Server) EnqueueIndex ¶
EnqueueIndex enqueues a conversation ID for memory indexing. Non-blocking: drops the request if the queue is full.
func (*Server) IsAgentWorking ¶
IsAgentWorking returns whether the agent is currently working on the given conversation. Returns false if the conversation doesn't have an active manager.
func (*Server) RegisterNotificationChannel ¶
func (s *Server) RegisterNotificationChannel(ch notifications.Channel)
RegisterNotificationChannel adds a backend notification channel to the dispatcher.
func (*Server) RegisterRoutes ¶
RegisterRoutes registers HTTP routes on the given mux
func (*Server) ReloadNotificationChannels ¶
func (s *Server) ReloadNotificationChannels()
ReloadNotificationChannels reads enabled channels from DB and replaces the dispatcher's channel set.
func (*Server) SeedNotificationChannelsFromConfig ¶
SeedNotificationChannelsFromConfig seeds the DB with notification channels from percy.json config if the DB table is empty. One-time migration for backwards compatibility.
func (*Server) SetClusterNode ¶ added in v0.306.970370273
SetClusterNode sets the cluster node for multi-agent coordination. If nil, cluster features are disabled.
func (*Server) SetEmbedder ¶
SetEmbedder sets the embedding provider for vector search and indexing. If nil, vector search is disabled (FTS-only).
func (*Server) SetMemoryDB ¶
SetMemoryDB sets the memory database for post-conversation indexing. If nil, memory indexing is silently skipped.
func (*Server) SetMuninnSink ¶ added in v0.365.963511
SetMuninnSink sets the MuninnDB sink for dual-writing memory cells.
type StaticCommitInfo ¶
StaticCommitInfo represents a commit from commits.json.
type StreamResponse ¶
type StreamResponse struct {
Messages []APIMessage `json:"messages"`
Conversation generated.Conversation `json:"conversation"`
ConversationState *ConversationState `json:"conversation_state,omitempty"`
ContextWindowSize uint64 `json:"context_window_size,omitempty"`
// ConversationListUpdate is set when another conversation in the list changed
ConversationListUpdate *ConversationListUpdate `json:"conversation_list_update,omitempty"`
// Heartbeat indicates this is a heartbeat message (no new data, just keeping connection alive)
Heartbeat bool `json:"heartbeat,omitempty"`
// NotificationEvent is set when a notification-worthy event occurs (e.g. agent finished).
NotificationEvent *notifications.Event `json:"notification_event,omitempty"`
}
StreamResponse represents the response format for conversation streaming
type SubagentRunner ¶
type SubagentRunner struct {
// contains filtered or unexported fields
}
SubagentRunner implements claudetool.SubagentRunner.
func NewSubagentRunner ¶
func NewSubagentRunner(s *Server) *SubagentRunner
NewSubagentRunner creates a new SubagentRunner.
type SubagentSystemPromptData ¶
type SubagentSystemPromptData struct {
WorkingDirectory string
CurrentDate string // Today's date in YYYY-MM-DD format
GitInfo *GitInfo
}
SubagentSystemPromptData contains data for subagent system prompts (minimal subset)
type SwitchModelRequest ¶ added in v0.381.91062602
type SystemPromptData ¶
type SystemPromptData struct {
WorkingDirectory string
CurrentDate string // Today's date in YYYY-MM-DD format
GitInfo *GitInfo
Codebase *CodebaseInfo
IsExeDev bool
IsSudoAvailable bool
Hostname string // For exe.dev, the public hostname (e.g., "vmname.exe.xyz")
PercyDBPath string // Path to the percy database
SkillsXML string // XML block for available skills
}
SystemPromptData contains all the data needed to render the system prompt template
type TestModelRequest ¶
type TestModelRequest struct {
ModelID string `json:"model_id,omitempty"` // If provided, use stored API key
ProviderType string `json:"provider_type"`
Endpoint string `json:"endpoint"`
APIKey string `json:"api_key"`
ModelName string `json:"model_name"`
}
TestModelRequest is the request body for testing a model
type TouchedFile ¶ added in v0.347.976101525
type TouchedFile struct {
Path string `json:"path"`
Operation string `json:"operation"` // "read", "write", "patch", "navigate"
Count int `json:"count"` // number of interactions
}
TouchedFile represents a file the agent interacted with.
type UpdateModelRequest ¶
type UpdateModelRequest struct {
DisplayName string `json:"display_name"`
ProviderType string `json:"provider_type"`
Endpoint string `json:"endpoint"`
APIKey string `json:"api_key"` // Empty string means keep existing
ModelName string `json:"model_name"`
MaxTokens int64 `json:"max_tokens"`
Tags string `json:"tags"` // Comma-separated tags
}
UpdateModelRequest is the request body for updating a model
type VersionChecker ¶
type VersionChecker struct {
// contains filtered or unexported fields
}
VersionChecker checks for new versions of Percy from GitHub releases.
func NewVersionChecker ¶
func NewVersionChecker() *VersionChecker
NewVersionChecker creates a new version checker.
func (*VersionChecker) Check ¶
func (vc *VersionChecker) Check(ctx context.Context, forceRefresh bool) (*VersionInfo, error)
Check checks for a new version, using the cache if still valid.
func (*VersionChecker) DoUpgrade ¶
func (vc *VersionChecker) DoUpgrade(ctx context.Context) error
DoUpgrade downloads and applies the update with checksum verification.
func (*VersionChecker) FetchChangelog ¶
func (vc *VersionChecker) FetchChangelog(ctx context.Context, currentTag, latestTag string) ([]CommitInfo, error)
FetchChangelog fetches the commits between current and latest versions.
type VersionInfo ¶
type VersionInfo struct {
CurrentVersion string `json:"current_version"`
CurrentTag string `json:"current_tag,omitempty"`
CurrentCommit string `json:"current_commit,omitempty"`
CurrentCommitTime string `json:"current_commit_time,omitempty"`
LatestVersion string `json:"latest_version,omitempty"`
LatestTag string `json:"latest_tag,omitempty"`
PublishedAt time.Time `json:"published_at,omitempty"`
HasUpdate bool `json:"has_update"` // True if minor version is newer (for showing upgrade button)
ShouldNotify bool `json:"should_notify"` // True if should show red dot (newer + 5 days old)
DownloadURL string `json:"download_url,omitempty"`
ExecutablePath string `json:"executable_path,omitempty"`
Commits []CommitInfo `json:"commits,omitempty"`
CheckedAt time.Time `json:"checked_at"`
Error string `json:"error,omitempty"`
RunningUnderSystemd bool `json:"running_under_systemd"` // True if INVOCATION_ID env var is set (systemd)
ReleaseInfo *ReleaseInfo `json:"-"` // Internal, not exposed to JSON
}
VersionInfo contains version check results.
Source Files
¶
- autogenerated.go
- cluster_monitor.go
- cluster_worker.go
- convo.go
- custom_models.go
- debug_handlers.go
- distill.go
- edit_handlers.go
- exec_terminal.go
- export_handlers.go
- filetree.go
- fork_handlers.go
- git_handlers.go
- handlers.go
- llmconfig.go
- middleware.go
- notification_channels.go
- path_normalization.go
- server.go
- subagent.go
- system_prompt.go
- usage_handlers.go
- versioncheck.go