Documentation
¶
Index ¶
- Constants
- Variables
- func GlossaryDifficultyTier(s string) int
- func NormalizeGlossaryCategory(s string) string
- func NormalizeGlossaryDifficulty(s string) string
- func NormalizeGlossaryKey(term string) string
- type AnalysisConfig
- type AnthropicModelsResponse
- type AnthropicRequest
- type AnthropicResponse
- type Article
- type ArticleAnalysis
- type ArticleCounts
- type ArticleFilter
- type ArticleInspection
- type ArticleUpdate
- type Category
- type CategoryDef
- type CodexCredential
- type Digest
- type DigestAnalysis
- type DigestArticle
- type DigestGlossary
- type DigestProviderResult
- type DiscordNotificationConfig
- type Feed
- type FeedConfig
- type FeedDiagnosis
- type FeedGroup
- type FeedItem
- type FeedRefreshResult
- type FeedRefreshRun
- type FeedResult
- type FeedTopic
- type FeedsFile
- type FetchResult
- type GenericLLMRequest
- type GitHubPagesNotificationConfig
- type GlossaryEntry
- type GlossaryKind
- type GlossaryTerm
- type HostTriggers
- type LLMCall
- type LLMRun
- type LinkListCandidate
- type LlamaCppModelsResponse
- type Message
- type ModelInfo
- type ModelsResponse
- type NotificationsConfig
- type OllamaModelDetails
- type OllamaModelsResponse
- type OllamaRequest
- type OllamaResponse
- type OpenAIModelsResponse
- type OpenAIRequest
- type OpenAIResponse
- type Profile
- type ProfileConfig
- type ProfileEditorial
- type ProfileSelection
- type ProfilesFile
- type PromptOverrides
- type ProviderConfig
- type ReferencedReport
- type RelatedArticle
- type RubricConfig
- type ScraperConfig
- type SelectorCandidate
- type Selectors
- type ServerConfig
- type StepProviderOverride
- type Tag
- type TierThresholds
- type WorkerPoolConfig
Constants ¶
const ( GlossaryCategoryCountry = "country" GlossaryCategoryCVE = "cve" )
GlossaryCategoryCountry and GlossaryCategoryCVE mark candidates that are deliberately excluded from the glossary (countries and CVE identifiers are not glossary-worthy named entities).
const GlossaryCategoryOther = "other"
GlossaryCategoryOther is the fallback category for unknown/empty values.
const GlossaryDifficultyDefault = "intermediate"
GlossaryDifficultyDefault is the fallback difficulty for unknown/empty values.
Variables ¶
var KnownPromptTaskNames = map[string]bool{ "categorize": true, "tldr": true, "plain_words": true, "key_points": true, "insights": true, "referenced_reports": true, "summaries": true, "glossary": true, "rubric": true, "importance": true, }
KnownPromptTaskNames is the set of analysis task names a profile may override via PromptOverrides.Tasks. "rubric" is the scoring task in default mode; "importance" is its legacy replacement, only run under vibe_score: true.
Functions ¶
func GlossaryDifficultyTier ¶ added in v0.4.0
GlossaryDifficultyTier maps a difficulty to the numeric tier used by the page's help-level filter: advanced=1 (shown first), intermediate=2, beginner=3 (shown only at the highest level). A term is shown when the selected help level >= its tier. Unknown/empty → 2.
func NormalizeGlossaryCategory ¶ added in v0.4.0
NormalizeGlossaryCategory lowercases/trims the value and returns it if it is in the fixed taxonomy, otherwise "other".
func NormalizeGlossaryDifficulty ¶ added in v0.4.0
NormalizeGlossaryDifficulty lowercases/trims the value and returns it if it is in the fixed taxonomy, otherwise the default ("intermediate").
func NormalizeGlossaryKey ¶ added in v0.4.0
NormalizeGlossaryKey produces the dedup/lookup identity for a term.
Types ¶
type AnalysisConfig ¶
type AnalysisConfig struct {
Provider string `json:"provider,omitempty"` // Name of the configured provider to use for analysis
Persona string `json:"persona,omitempty"` // Additional prompt prefix to customize the AI instructions
WritingStyle string `json:"writing_style,omitempty"` // Writing style guide injected into digest summary prompt
WorkerPool *WorkerPoolConfig `json:"worker_pool,omitempty"` // Configuration for the analysis worker pool
AutoAnalyze bool `json:"auto_analyze,omitempty"` // Automatically enqueue articles for analysis after each feed refresh
VibeScore bool `json:"vibe_score,omitempty"` // Use the legacy single-number LLM importance prompt instead of the rubric scoring system
Glossary bool `json:"glossary,omitempty"` // Generate glossary-mode content (plain-language explanation + jargon glossary) as an extra analysis task
StandardSynthesis bool `json:"standard_synthesis,omitempty"` // Generate the Standard article summary (brief overview is always generated)
ComprehensiveSynthesis bool `json:"comprehensive_synthesis,omitempty"` // Generate the Full (comprehensive) article summary
ExecutiveSummary bool `json:"executive_summary,omitempty"` // Generate the digest-level executive summary (title + thematic overview)
StepProviders map[string]StepProviderOverride `json:"step_providers,omitempty"` // Per-step provider/model overrides (step name -> override config)
}
AnalysisConfig represents the configuration for the analysis features
type AnthropicModelsResponse ¶
type AnthropicModelsResponse struct {
Data []struct {
Type string `json:"type"`
Id string `json:"id"`
DisplayName string `json:"display_name"`
CreatedAt string `json:"created_at"`
MaxInputTokens int `json:"max_input_tokens"`
MaxTokens int `json:"max_tokens"`
} `json:"data"`
HasMore bool `json:"has_more"`
FirstId string `json:"first_id"`
LastId string `json:"last_id"`
}
AnthropicModelsResponse represents the response from Anthropic's models endpoint
type AnthropicRequest ¶
type AnthropicRequest struct {
Model string `json:"model"`
Messages []Message `json:"messages"`
Temperature float64 `json:"temperature,omitempty"`
MaxTokens int `json:"max_tokens,omitempty"`
}
AnthropicRequest represents a request to the Anthropic API
type AnthropicResponse ¶
type AnthropicResponse struct {
Id string `json:"id"`
Type string `json:"type"`
Model string `json:"model"`
Content []struct {
Type string `json:"type"`
Text string `json:"text"`
} `json:"content"`
}
AnthropicResponse represents a response from the Anthropic API
type Article ¶
type Article struct {
Id string `gorm:"primaryKey" json:"id"`
FeedId string `gorm:"index" json:"feed_id"`
Title string `json:"title"`
Content string `gorm:"type:text" json:"content"`
Link string `json:"link"`
PublishedAt time.Time `gorm:"index" json:"published_at"`
FetchedAt time.Time `json:"fetched_at"`
Read *bool `gorm:"default:false" json:"read"`
Tags []Tag `gorm:"many2many:article_tags;" json:"tags"`
CategoryName *string `gorm:"index" json:"category_name,omitempty"`
Category *Category `gorm:"foreignKey:CategoryName;references:Name" json:"category,omitempty"`
HeroImage string `json:"hero_image,omitempty"`
Bookmarked *bool `gorm:"default:false" json:"bookmarked"`
RelatedArticles []RelatedArticle `gorm:"-" json:"related_articles,omitempty"` // Handled separately
// LatestImportanceScore is populated only by ListArticles (via JOIN on the latest analysis).
// Not persisted on the Article row.
LatestImportanceScore *int32 `gorm:"-" json:"latest_importance_score,omitempty"`
}
Article represents an article from a feed
func (*Article) BeforeCreate ¶
BeforeCreate ensures Id is set before creating a record
type ArticleAnalysis ¶
type ArticleAnalysis struct {
Id string `gorm:"primaryKey" json:"id"`
ArticleId string `gorm:"index:idx_analysis_article_profile" json:"article_id"`
ProfileId string `gorm:"index:idx_analysis_article_profile;index" json:"profile_id"`
ProviderType string `json:"provider_type"`
ModelName string `json:"model_name"`
ImportanceScore int `json:"importance_score"`
ScoreDimensionsJson string `gorm:"column:score_dimensions;type:text" json:"-"`
ScoreDimensions *scoring.Dimensions `gorm:"-" json:"score_dimensions,omitempty"`
KeyPointsJson string `gorm:"column:key_points;type:text" json:"-"`
InsightsJson string `gorm:"column:insights;type:text" json:"-"`
ReferencedReportsJson string `gorm:"column:referenced_reports;type:text" json:"-"`
VendorsJson string `gorm:"column:vendors;type:text" json:"-"`
TechnologiesJson string `gorm:"column:technologies;type:text" json:"-"`
KeyPoints []string `gorm:"-" json:"key_points"`
Insights []string `gorm:"-" json:"insights"`
Vendors []string `gorm:"-" json:"vendors"`
Technologies []string `gorm:"-" json:"technologies"`
ReferencedReports []ReferencedReport `gorm:"-" json:"referenced_reports"`
Tldr string `gorm:"type:text" json:"tldr"`
PlainWords string `gorm:"type:text" json:"plain_words"`
Justification string `gorm:"type:text" json:"justification"`
BriefOverview string `gorm:"serializer:zstd;type:blob" json:"brief_overview"`
StandardSynthesis string `gorm:"serializer:zstd;type:blob" json:"standard_synthesis"`
ComprehensiveSynthesis string `gorm:"serializer:zstd;type:blob" json:"comprehensive_synthesis"`
GlossaryTermsJson string `gorm:"column:glossary_terms;type:text" json:"-"`
GlossaryTerms []GlossaryTerm `gorm:"-" json:"glossary_terms"`
ThinkingProcess string `gorm:"serializer:zstd;type:blob" json:"thinking_process,omitempty"`
RawResponse string `gorm:"serializer:zstd;type:blob" json:"raw_response"`
CreatedAt time.Time `gorm:"index" json:"created_at"`
Article *Article `gorm:"foreignKey:ArticleId;references:Id" json:"-"`
}
ArticleAnalysis represents an analysis result from an LLM provider for an article
func (*ArticleAnalysis) AfterFind ¶
func (a *ArticleAnalysis) AfterFind(tx *gorm.DB) error
AfterFind converts JSON strings back to slices after querying
func (*ArticleAnalysis) BeforeCreate ¶
func (a *ArticleAnalysis) BeforeCreate(tx *gorm.DB) error
BeforeCreate ensures Id is set before creating a record
func (ArticleAnalysis) TableName ¶
func (ArticleAnalysis) TableName() string
TableName specifies the table name for ArticleAnalysis
type ArticleCounts ¶
type ArticleFilter ¶
type ArticleFilter struct {
UnreadOnly bool `json:"unread_only"`
CategoryName string `json:"category_name"`
TagId string `json:"tag_id"`
BookmarkedOnly bool `json:"bookmarked_only"`
RelatedToId string `json:"related_to_id"`
StartDate *time.Time `json:"start_date,omitempty"`
EndDate *time.Time `json:"end_date,omitempty"`
FeedId string `json:"feed_id"`
// ProfileId, when set, restricts results to the feeds in that profile's pool
// and scopes LatestImportanceScore to that profile's analyses. Empty means no
// profile restriction (latest analysis across all profiles), preserving the
// historical single-tenant behavior.
ProfileId string `json:"profile_id,omitempty"`
ExcludeDigested bool `json:"exclude_digested,omitempty"`
Offset int `json:"offset,omitempty"`
Limit int `json:"limit,omitempty"`
Query string `json:"query,omitempty"`
// Unbounded returns every matching row, bypassing the default page cap.
// Used by digest generation, which needs the full window, not a UI page.
Unbounded bool `json:"unbounded,omitempty"`
}
ArticleFilter represents filtering options for listing articles
type ArticleInspection ¶ added in v0.2.0
type ArticleInspection struct {
ModeUsed string `json:"mode_used"`
RawHTMLLen int `json:"raw_html_len"`
HTML string `json:"html"` // page HTML (capped) for selector inspection
Extracted string `json:"extracted"` // extracted markdown when selectors supplied
ExtractedLen int `json:"extracted_len"` // rune count of Extracted
SelectorMatched bool `json:"selector_matched"` // the article selector matched an element
Error string `json:"error"`
DurationMs int64 `json:"duration_ms"`
}
ArticleInspection is the result of scraping a single article URL in a given mode, used by the feed-config builder to inspect page HTML and test selectors.
type ArticleUpdate ¶
type ArticleUpdate struct {
Read *bool `json:"read,omitempty"`
TagIds *[]string `json:"tag_ids,omitempty"`
CategoryName *string `json:"category_name,omitempty"`
HeroImage *string `json:"hero_image,omitempty"`
Bookmarked *bool `json:"bookmarked,omitempty"`
RelatedArticles *[]RelatedArticle `json:"related_articles,omitempty"`
}
ArticleUpdate represents fields that can be updated for an article
type Category ¶
type Category struct {
Name string `gorm:"uniqueIndex,primaryKey" json:"name"`
Color string `json:"color"` // For UI display
Icon string `json:"icon"` // For UI display
Articles []Article `gorm:"foreignKey:CategoryName;references:Name" json:"-"` // One-to-many relationship with articles
}
Category represents an article category
type CategoryDef ¶ added in v0.4.0
type CategoryDef struct {
Name string `json:"name" yaml:"name"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
}
CategoryDef is one allowed category for a profile, with a short description the LLM is shown when classifying.
type CodexCredential ¶
type CodexCredential struct {
Id string `json:"id"` // short random ID
Label string `json:"label"` // email or fallback
Priority int `json:"priority"` // lower = preferred
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
LastRefresh time.Time `json:"last_refresh"`
AuthMode string `json:"auth_mode"` // "chatgpt" | "claude"
Source string `json:"source"` // "manual:device_code" | "manual:pkce"
ExpiresAt *time.Time `json:"expires_at,omitempty"` // OAuth absolute expiry (non-JWT tokens, e.g. claude-code)
LastStatus string `json:"last_status,omitempty"` // "ok" | "auth_failed" | "rate_limited"
LastStatusAt *time.Time `json:"last_status_at,omitempty"`
LastErrorReason string `json:"last_error_reason,omitempty"`
LastErrorResetAt *time.Time `json:"last_error_reset_at,omitempty"` // when rate_limited expires
}
CodexCredential holds OAuth state for a single ChatGPT/Codex account.
type Digest ¶
type Digest struct {
Id string `gorm:"primaryKey" json:"id"`
ProfileId string `gorm:"index" json:"profile_id"`
CreatedAt time.Time `gorm:"index" json:"created_at"`
Title string `gorm:"type:text" json:"title,omitempty"`
ArticleCount *int `gorm:"default:0" json:"article_count"`
TimeWindow time.Duration `json:"time_window"`
RawGroupingResponse string `gorm:"type:text" json:"raw_grouping_response,omitempty"`
DigestSummary string `gorm:"type:text" json:"digest_summary,omitempty"`
ProviderResults []DigestProviderResult `gorm:"-" json:"provider_results"` // Handled through separate table
DigestAnalyses []DigestAnalysis `gorm:"-" json:"digest_analyses,omitempty"` // Handled through separate table
DigestGlossary []DigestGlossary `gorm:"-" json:"digest_glossary,omitempty"` // Handled through separate table
Articles []Article `gorm:"many2many:digest_articles;" json:"-"`
AnalysisErrors map[string]string `gorm:"-" json:"-"` // transient: articleId → classified error, not persisted
}
Digest represents a generated digest of articles
type DigestAnalysis ¶
type DigestAnalysis struct {
DigestId string `gorm:"primaryKey;index" json:"digest_id"`
AnalysisId string `gorm:"primaryKey" json:"analysis_id"`
ArticleId string `gorm:"index" json:"article_id"`
DuplicateGroup string `json:"duplicate_group,omitempty"`
IsMostComprehensive bool `gorm:"default:false" json:"is_most_comprehensive"`
Analysis *ArticleAnalysis `gorm:"foreignKey:AnalysisId;references:Id" json:"analysis,omitempty"`
}
DigestAnalysis links an ArticleAnalysis to a Digest with duplicate-group metadata.
func (DigestAnalysis) TableName ¶
func (DigestAnalysis) TableName() string
type DigestArticle ¶
type DigestArticle struct {
DigestId string `json:"digest_id"`
ArticleId string `json:"article_id"`
}
DigestArticle represents an article included in a digest
type DigestGlossary ¶ added in v0.4.0
type DigestGlossary struct {
DigestId string `gorm:"primaryKey;index" json:"digest_id"`
EntryId string `gorm:"primaryKey" json:"entry_id"`
Entry *GlossaryEntry `gorm:"foreignKey:EntryId;references:Id" json:"entry,omitempty"`
}
DigestGlossary records which global glossary entries a digest references.
func (DigestGlossary) TableName ¶ added in v0.4.0
func (DigestGlossary) TableName() string
type DigestProviderResult ¶
type DigestProviderResult struct {
Id string `gorm:"primaryKey" json:"id"`
DigestId string `gorm:"index" json:"digest_id"`
ProviderType string `json:"provider_type"`
ModelName string `json:"model_name"`
BriefOverview string `gorm:"type:text" json:"brief_overview"`
StandardSynthesis string `gorm:"type:text" json:"standard_synthesis"`
ComprehensiveSynthesis string `gorm:"type:text" json:"comprehensive_synthesis"`
ProcessingTime float64 `json:"processing_time"`
Error string `json:"error"`
CreatedAt time.Time `gorm:"index" json:"created_at"`
Digest *Digest `gorm:"foreignKey:DigestId" json:"-"`
}
DigestProviderResult represents a provider's result for a digest
func (*DigestProviderResult) BeforeCreate ¶
func (d *DigestProviderResult) BeforeCreate(tx *gorm.DB) error
BeforeCreate ensures Id is set before creating a record
func (DigestProviderResult) TableName ¶
func (DigestProviderResult) TableName() string
TableName specifies the table name for DigestProviderResult
type DiscordNotificationConfig ¶
type DiscordNotificationConfig struct {
Enabled bool `json:"enabled"`
WebhookURL string `json:"webhook_url"`
}
DiscordNotificationConfig holds Discord-specific notification settings
type Feed ¶
type Feed struct {
Id string `gorm:"primaryKey" json:"id"`
URL string `gorm:"index" json:"url"`
Type string `json:"type"`
Title string `json:"title"`
LastFetch time.Time `json:"last_fetch"`
// Scraper map[string]any `gorm:"-" json:"scraper,omitempty"` // In-memory representation
Scraper datatypes.JSONMap `json:"scraper,omitempty"` // In-memory representation
Enabled *bool `gorm:"default:true" json:"enabled"`
GroupId *string `gorm:"default:'default'" json:"group_id"`
Articles []Article `gorm:"foreignKey:FeedId" json:"-"` // One-to-many relationship with articles
// Topics are the feed's labels (profiles select feeds by topic). Stored in the
// feed_topics table, not on this row; populated by ListFeeds for read paths.
Topics []string `gorm:"-" json:"topics,omitempty"`
}
Feed represents a feed with its metadata
func (*Feed) BeforeCreate ¶
BeforeCreate ensures Id is set and properly converts Params before creating a record
type FeedConfig ¶
type FeedConfig struct {
URL string `json:"url" yaml:"url"`
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Note string `json:"note,omitempty" yaml:"note,omitempty"`
Enabled bool `json:"enabled" yaml:"enabled"`
Topics []string `json:"topics,omitempty" yaml:"topics,omitempty"` // labels profiles select feeds by
Scraper ScraperConfig `json:"scraper" yaml:"scraper"`
}
FeedConfig represents the configuration for a feed. Everything scraping-related lives under the nested Scraper block; only identity fields stay at the top level.
func (FeedConfig) Validate ¶ added in v0.4.0
func (fc FeedConfig) Validate() error
Validate enforces the hard requirements every feed config must meet before it can be registered: a non-empty title, and — for the html scraper — a date_selector.
type FeedDiagnosis ¶ added in v0.2.0
type FeedDiagnosis struct {
URL string `json:"url"`
FinalURL string `json:"final_url"` // after redirects
HTTPStatus int `json:"http_status"` // 0 when the request never completed
ContentType string `json:"content_type"` // raw Content-Type header
ContentLength int `json:"content_length"` // bytes actually read
FeedTypeGuess string `json:"feed_type_guess"` // rss | atom | json-feed | html | empty | unknown
DeclaredCharset string `json:"declared_charset"` // from XML prolog or Content-Type, when present
ItemCount int `json:"item_count"` // parsed items when the feed is valid
ParseError string `json:"parse_error"` // gofeed parse error, empty when valid
InvalidUTF8At *int `json:"invalid_utf8_at"` // byte offset of first invalid UTF-8 byte, nil when valid
Verdict string `json:"verdict"` // one-line human summary
BodySnippet string `json:"body_snippet"` // first printable bytes of the body
HexDump string `json:"hex_dump"` // bytes around InvalidUTF8At, when relevant
RawBodyPath string `json:"raw_body_path"` // on-disk path to the saved raw body
FetchDurationMs int64 `json:"fetch_duration_ms"` // wall time of the fetch
// DiscoveredFeeds holds validated RSS/Atom/JSON feed URLs found on an HTML
// page (via <link> autodiscovery, anchor keywords, or common-path probing).
// Populated only when the fetched URL is itself an HTML page, so a caller can
// redirect autoconfig at the real feed instead of the landing page.
DiscoveredFeeds []string `json:"discovered_feeds,omitempty"`
}
FeedDiagnosis is the structured result of inspecting a single feed's raw HTTP response. It captures what actually came back over the wire so the two common failure modes — an unrecognizable body ("Failed to detect feed type") and raw non-UTF-8 bytes ("invalid utf-8 syntax") — can be diagnosed without re-running the server at trace log level.
type FeedGroup ¶
type FeedGroup struct {
Id string `gorm:"primaryKey" json:"id"`
Name string `gorm:"uniqueIndex" json:"name"`
Icon string `json:"icon"`
SortOrder *int `gorm:"default:0" json:"sort_order"`
Feeds []Feed `gorm:"foreignKey:GroupId" json:"-"` // One-to-many relationship with feeds
}
FeedGroup represents a group of feeds
type FeedItem ¶
type FeedItem struct {
Id string
Title string
Content string
Link string
PublishedAt time.Time
Tags []string
Category string
HeroImage string // New field for hero image URL
}
FeedItem represents a generic feed item returned by a scraper
type FeedRefreshResult ¶ added in v0.4.0
type FeedRefreshResult struct {
Id string `gorm:"primaryKey" json:"id"`
RunId string `gorm:"index" json:"run_id"`
FeedId string `gorm:"index" json:"feed_id"`
FeedTitle string `json:"feed_title"` // denormalized: the feed may be deleted later
FeedURL string `json:"feed_url"`
Success bool `json:"success"` // top-level fetch err == nil
TotalFetched int `json:"total_fetched"`
Stored int `json:"stored"`
Skipped int `json:"skipped"`
ErrorCount int `json:"error_count"` // number of item-level errors
WarningCount int `json:"warning_count"` // number of non-fatal notices (e.g. sanitized content)
FetchError string `gorm:"column:fetch_error;type:text" json:"fetch_error,omitempty"`
ErrorLog []byte `gorm:"type:blob" json:"-"` // gzip of joined item-level errors
WarningLog []byte `gorm:"type:blob" json:"-"` // gzip of joined item-level warnings
RawBody []byte `gorm:"type:blob" json:"-"` // gzip of the raw fetched feed body
RawStatus int `json:"raw_status,omitempty"`
RawType string `json:"raw_type,omitempty"` // raw response Content-Type
DurationMs int64 `json:"duration_ms"`
CreatedAt time.Time `gorm:"index" json:"created_at"`
}
FeedRefreshResult is the outcome of refreshing one feed during a run. Success reflects the top-level fetch (FetchError empty); item-level scrape/store failures are counted in ErrorCount and kept verbatim in ErrorLog. Non-fatal notices (e.g. content sanitized for invalid UTF-8, the article still stored) are counted in WarningCount and kept in WarningLog. Both logs are stored gzip-compressed (the store layer owns the codec).
func (FeedRefreshResult) TableName ¶ added in v0.4.0
func (FeedRefreshResult) TableName() string
type FeedRefreshRun ¶ added in v0.4.0
type FeedRefreshRun struct {
Id string `gorm:"primaryKey" json:"id"`
Trigger string `json:"trigger"` // "startup" | "manual-all" | "manual-single"
StartedAt time.Time `gorm:"index" json:"started_at"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
}
FeedRefreshRun is one feed-refresh cycle: a single feed refresh, a refresh of all feeds, or the startup refresh. Each enabled feed processed during the cycle has a child FeedRefreshResult correlated by the run Id.
func (FeedRefreshRun) TableName ¶ added in v0.4.0
func (FeedRefreshRun) TableName() string
type FeedResult ¶
type FeedResult struct {
Feed Feed
Items []FeedItem
Error error
FetchResult FetchResult
}
FeedResult represents the result of fetching a feed
type FeedTopic ¶ added in v0.4.0
type FeedTopic struct {
FeedId string `gorm:"primaryKey" json:"feed_id"`
Topic string `gorm:"primaryKey;index" json:"topic"`
}
FeedTopic is one (feed, topic) membership row. Topics are operator-assigned labels; a profile selects feeds by topic (see ProfileSelection). Distinct from the LLM-generated article entity tags (see Tag).
type FeedsFile ¶
type FeedsFile struct {
DefaultSelectors *Selectors `yaml:"default_selectors,omitempty"`
Feeds []FeedConfig `yaml:"feeds"`
}
FeedsFile is the top-level structure of feeds.yml
type FetchResult ¶
type FetchResult struct {
TotalFetched int
Stored int
Skipped int
Errors []string
Warnings []string // non-fatal notices (e.g. content sanitized); the article was still stored
StoredArticleIDs []string // IDs of articles successfully stored in this fetch
// Raw feed response captured for the refresh monitor, so the exact bytes a
// refresh saw (or failed to parse) stay inspectable. RawBody is nil when
// nothing was fetched (e.g. a network-level error before any response).
RawBody []byte
RawStatus int
RawContentType string
}
FetchResult holds statistics from a single feed fetch operation
type GenericLLMRequest ¶
type GenericLLMRequest struct {
Model string `json:"model,omitempty"` // Model name
Messages []Message `json:"messages,omitempty"` // For chat-based APIs (OpenAI, Anthropic)
Prompt string `json:"prompt,omitempty"` // For completion-based APIs (Ollama)
Temperature float64 `json:"temperature,omitempty"` // Optional
MaxTokens int `json:"max_tokens,omitempty"` // Optional
}
GenericLLMRequest represents a generic request to an LLM provider
type GitHubPagesNotificationConfig ¶
type GitHubPagesNotificationConfig struct {
Enabled bool `json:"enabled"`
RepoURL string `json:"repo_url"` // e.g. https://github.com/user/user.github.io.git
Branch string `json:"branch"` // default "main"
ConfigurePages bool `json:"configure_pages"` // configure GitHub Pages source to this branch
Token string `json:"token"` // GitHub PAT; prefer env DOWNLINK_GH_PAGES_TOKEN
OutputDir string `json:"output_dir"` // subdirectory inside repo (empty = repo root)
Layout string `json:"layout"` // layout (template set) for published pages; empty = "default"
BaseURL string `json:"base_url"` // public URL, e.g. https://user.github.io
CommitAuthor string `json:"commit_author"` // default "downlink-bot"
CommitEmail string `json:"commit_email"` // default "downlink-bot@users.noreply.github.com"
CloneDir string `json:"clone_dir"` // local working clone; default: os.TempDir()/downlink-ghpages
DiscordWebhookURL string `json:"discord_webhook_url"` // optional: notify this webhook when a page is published
PublishWindowDays int `json:"publish_window_days"` // days to retain in manifest/feeds; 0 = default (30)
SelfContained bool `json:"self_contained"` // inline CSS into every page instead of linking external .css files (default: external)
}
GitHubPagesNotificationConfig holds GitHub Pages publishing settings
type GlossaryEntry ¶ added in v0.4.0
type GlossaryEntry struct {
Id string `gorm:"primaryKey" json:"id"`
NormalizedKey string `gorm:"uniqueIndex" json:"normalized_key"` // dedup identity
Term string `json:"term"` // display form (first-seen)
Kind GlossaryKind `gorm:"index" json:"kind"` // provenance: jargon vs entity
Category string `gorm:"index" json:"category"` // semantic type (see NormalizeGlossaryCategory)
Difficulty string `gorm:"index" json:"difficulty"` // help tier (see NormalizeGlossaryDifficulty)
Definition string `gorm:"type:text" json:"definition"` // LLM-generated, current best
CuratedDefinition string `gorm:"type:text" json:"curated_definition"` // manual override text
ManualOverride bool `gorm:"default:false;index" json:"manual_override"`
TagId string `gorm:"index" json:"tag_id,omitempty"` // set when Kind==entity; == Tag.Id (slug)
Source string `json:"source"` // provenance
DefinitionModel string `json:"definition_model,omitempty"` // provider/model that produced Definition
CreatedAt time.Time `gorm:"index" json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
GlossaryEntry is one deduplicated term in the persistent global glossary. Identity is the normalized key; definitions are reused across digests and never re-queried once present. A manual override, once set, wins forever and is never overwritten by regeneration.
func (*GlossaryEntry) BeforeCreate ¶ added in v0.4.0
func (e *GlossaryEntry) BeforeCreate(tx *gorm.DB) error
BeforeCreate ensures Id is set before creating a record
func (*GlossaryEntry) EffectiveDefinition ¶ added in v0.4.0
func (e *GlossaryEntry) EffectiveDefinition() string
EffectiveDefinition returns the curated override when present, else the generated one.
func (GlossaryEntry) TableName ¶ added in v0.4.0
func (GlossaryEntry) TableName() string
TableName specifies the table name for GlossaryEntry
type GlossaryKind ¶ added in v0.4.0
type GlossaryKind string
GlossaryKind distinguishes the two provenance sources of a glossary entry.
const ( GlossaryKindJargon GlossaryKind = "jargon" // from ArticleAnalysis.GlossaryTerms GlossaryKindEntity GlossaryKind = "entity" // from a Tag (threat actor, malware, CVE, …) )
type GlossaryTerm ¶ added in v0.3.0
type GlossaryTerm struct {
Term string `json:"term"`
Aliases []string `json:"aliases,omitempty"`
Type string `json:"type"`
Definition string `json:"definition"`
Context string `json:"context"`
}
GlossaryTerm is a single jargon term and its plain-language definition, produced by the glossary-mode analysis task to help newcomers familiarize themselves with the terminology used in an article. Type is the semantic category (see the GlossaryCategory* constants); Context is a one-sentence explanation of why the term matters in this specific article (per-occurrence, not global). Aliases are other surface forms the article uses for the same thing (variant phrasings, abbreviations, expansions) so each resolves to the one definition when highlighted.
type HostTriggers ¶
type HostTriggers = smodels.HostTriggers
type LLMCall ¶ added in v0.4.0
type LLMCall struct {
Id string `gorm:"primaryKey" json:"id"`
RunId string `gorm:"index" json:"run_id"`
Label string `gorm:"index" json:"label"`
ProviderType string `json:"provider_type"`
ModelName string `json:"model_name"`
Prompt []byte `gorm:"type:blob" json:"-"` // gzip-compressed UTF-8
Response []byte `gorm:"type:blob" json:"-"` // gzip-compressed UTF-8
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
TokensKnown bool `json:"tokens_known"`
DurationMs int64 `json:"duration_ms"`
Err string `gorm:"column:error;type:text" json:"error,omitempty"`
CreatedAt time.Time `gorm:"index" json:"created_at"`
}
LLMCall is one prompt/response that passed through the gateway during a run. Prompt and Response are stored gzip-compressed (the store layer owns the codec); token counts are zero with TokensKnown=false for backends that do not report usage (e.g. OAuth subscription providers).
type LLMRun ¶ added in v0.4.0
type LLMRun struct {
Id string `gorm:"primaryKey" json:"id"`
ProfileId string `gorm:"index" json:"profile_id,omitempty"`
DigestId string `gorm:"index" json:"digest_id,omitempty"`
Title string `json:"title,omitempty"`
StartedAt time.Time `gorm:"index" json:"started_at"`
FinishedAt *time.Time `json:"finished_at,omitempty"`
}
LLMRun is one digest-generation run. Every LLM call made while generating a digest is correlated to a run via its Id (propagated through the call context by the gateway). DigestId/Title are filled in once the digest is created.
type LinkListCandidate ¶ added in v0.4.0
type LinkListCandidate struct {
LinksSelector string `json:"links_selector"`
Count int `json:"count"` // anchors the selector matched
SampleHrefs []string `json:"sample_hrefs"` // a few resolved post URLs
DateSelector string `json:"date_selector,omitempty"` // relative selector for the block's date
DateSample string `json:"date_sample,omitempty"` // raw text/attr of one matched date
URLFilter string `json:"url_filter,omitempty"` // shared path segment of the post URLs
}
LinkListCandidate is a ranked guess at the repeating post-link structure on an HTML index page: a links_selector scoping the post anchors, plus the relative date_selector and url_filter inferred from the repeating block. Mirrors scrapers.LinkListCandidate.
type LlamaCppModelsResponse ¶
type LlamaCppModelsResponse struct {
Object string `json:"object"`
// OpenAI-compatible data array (preferred)
Data []struct {
Id string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
OwnedBy string `json:"owned_by"`
} `json:"data"`
// llama.cpp native models array (fallback)
Models []struct {
Name string `json:"name"`
Model string `json:"model"`
} `json:"models"`
}
LlamaCppModelsResponse handles the hybrid response format from llama.cpp /models endpoint, which includes both a custom "models" array and an OpenAI-compatible "data" array.
type Message ¶
type Message struct {
Role string `json:"role"` // "system", "user", "assistant"
Content string `json:"content"` // Message content
}
Message represents a message in a chat-based LLM request
type ModelInfo ¶
type ModelInfo struct {
Id string `json:"id"`
Name string `json:"name"`
DisplayName string `json:"display_name,omitempty"`
Description string `json:"description,omitempty"`
ProviderType string `json:"provider_type"`
}
ModelInfo represents generic model information
type ModelsResponse ¶
type ModelsResponse struct {
Models []ModelInfo `json:"models"`
Error string `json:"error,omitempty"`
}
ModelsResponse represents the response structure for GetAvailableModels
type NotificationsConfig ¶
type NotificationsConfig struct {
Discord DiscordNotificationConfig `json:"discord"`
GitHubPages GitHubPagesNotificationConfig `json:"github_pages"`
}
NotificationsConfig holds notification platform configurations
type OllamaModelDetails ¶
type OllamaModelDetails struct {
ParentModel string `json:"parent_model"`
Format string `json:"format"`
Family string `json:"family"`
Families []string `json:"families"`
ParameterSize string `json:"parameter_size"`
QuantizationLevel string `json:"quantization_level"`
}
OllamaModelDetails represents the details of an Ollama model
type OllamaModelsResponse ¶
type OllamaModelsResponse struct {
Models []struct {
Name string `json:"name"`
Model string `json:"model"`
ModifiedAt string `json:"modified_at"`
Size int64 `json:"size"`
Digest string `json:"digest"`
Details OllamaModelDetails `json:"details"`
} `json:"models"`
}
OllamaModelsResponse represents the response from Ollama's models endpoint
type OllamaRequest ¶
type OllamaRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
Stream bool `json:"stream"`
}
OllamaRequest represents the request to the Ollama API
type OllamaResponse ¶
type OllamaResponse struct {
Model string `json:"model"`
Response string `json:"response"`
CreatedAt string `json:"created_at"`
}
OllamaResponse represents the response from the Ollama API
type OpenAIModelsResponse ¶
type OpenAIModelsResponse struct {
Object string `json:"object"`
Data []struct {
Id string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
OwnedBy string `json:"owned_by"`
} `json:"data"`
}
OpenAIModelsResponse represents the response from OpenAI's models endpoint
type OpenAIRequest ¶
type OpenAIRequest struct {
Model string `json:"model"`
Messages []Message `json:"messages"`
Temperature float64 `json:"temperature,omitempty"`
MaxTokens int `json:"max_tokens,omitempty"`
}
OpenAIRequest represents a request to the OpenAI API
type OpenAIResponse ¶
type OpenAIResponse struct {
Id string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
Model string `json:"model"`
Choices []struct {
Index int `json:"index"`
Message Message `json:"message"`
FinishReason string `json:"finish_reason"`
} `json:"choices"`
}
OpenAIResponse represents a response from the OpenAI API
type Profile ¶ added in v0.4.0
type Profile struct {
Id string `gorm:"primaryKey" json:"id"` // slug, e.g. "infosec"
Name string `gorm:"uniqueIndex" json:"name"`
Description string `json:"description,omitempty"`
Icon string `json:"icon,omitempty"`
Layout string `json:"layout,omitempty"` // digestlayouts template set; empty = "default"
Theme string `json:"theme,omitempty"` // digestthemes palette; empty = template default
Enabled *bool `gorm:"default:true" json:"enabled"`
SortOrder *int `gorm:"default:0" json:"sort_order"`
OutputSubdir string `json:"output_subdir,omitempty"` // GitHub Pages subdir; empty = slug
// Editorial is hydrated from EditorialJson on read and serialized back on
// save (same JSON-column pattern as ArticleAnalysis). A nil field inside it
// means "inherit the global/default behavior".
EditorialJson string `gorm:"column:editorial;type:text" json:"-"`
Editorial *ProfileEditorial `gorm:"-" json:"editorial,omitempty"`
// Selection is the feed-membership rule (topics + explicit overrides),
// persisted so feed-catalog changes can re-resolve profile_feeds without
// re-reading profiles.yml. The resolved membership lives in profile_feeds.
SelectionJson string `gorm:"column:selection;type:text" json:"-"`
Selection *ProfileSelection `gorm:"-" json:"selection,omitempty"`
Feeds []Feed `gorm:"many2many:profile_feeds;" json:"-"`
}
Profile is one curated, public view of the shared article pool. A profile selects a subset of feeds (many-to-many via profile_feeds, so pools may overlap between profiles), carries its own editorial config (how its articles are analyzed), and picks its own presentation (layout template set + default theme palette). Articles and feeds stay global; analyses and digests are scoped to a profile via their ProfileId.
func (*Profile) AfterFind ¶ added in v0.4.0
AfterFind hydrates Editorial and Selection from their JSON columns after a query.
func (*Profile) BeforeSave ¶ added in v0.4.0
BeforeSave serializes Editorial and Selection into their JSON columns before persisting.
type ProfileConfig ¶ added in v0.4.0
type ProfileConfig struct {
Slug string `yaml:"slug"`
Name string `yaml:"name"`
Description string `yaml:"description,omitempty"`
Icon string `yaml:"icon,omitempty"`
Layout string `yaml:"layout,omitempty"`
Theme string `yaml:"theme,omitempty"`
Enabled *bool `yaml:"enabled,omitempty"`
SortOrder *int `yaml:"sort_order,omitempty"`
OutputSubdir string `yaml:"output_subdir,omitempty"`
Topics []string `yaml:"topics,omitempty"` // feeds with ANY of these topics
Feeds []string `yaml:"feeds,omitempty"` // explicit include feed URLs
ExcludeFeeds []string `yaml:"exclude_feeds,omitempty"` // explicit exclude feed URLs
Editorial *ProfileEditorial `yaml:"editorial,omitempty"`
}
ProfileConfig is one profile definition in profiles.yml. Feeds are referenced by URL and resolved to feed ids at apply time.
type ProfileEditorial ¶ added in v0.4.0
type ProfileEditorial struct {
Provider string `json:"provider,omitempty" yaml:"provider,omitempty"` // configured provider name
Model string `json:"model,omitempty" yaml:"model,omitempty"` // optional model override
Persona string `json:"persona,omitempty" yaml:"persona,omitempty"` // analysis system-message prefix
WritingStyle string `json:"writing_style,omitempty" yaml:"writing_style,omitempty"` // digest-summary style guide
Audience string `json:"audience,omitempty" yaml:"audience,omitempty"` // target reader, injected into prompts
Glossary *bool `json:"glossary,omitempty" yaml:"glossary,omitempty"`
VibeScore *bool `json:"vibe_score,omitempty" yaml:"vibe_score,omitempty"` // legacy single-number scoring instead of the rubric
StandardSynthesis *bool `json:"standard_synthesis,omitempty" yaml:"standard_synthesis,omitempty"`
ComprehensiveSynthesis *bool `json:"comprehensive_synthesis,omitempty" yaml:"comprehensive_synthesis,omitempty"`
ExecutiveSummary *bool `json:"executive_summary,omitempty" yaml:"executive_summary,omitempty"`
Categories []CategoryDef `json:"categories,omitempty" yaml:"categories,omitempty"` // nil/empty = default category set
Rubric *RubricConfig `json:"rubric,omitempty" yaml:"rubric,omitempty"` // nil = default weights/thresholds
Prompts *PromptOverrides `json:"prompts,omitempty" yaml:"prompts,omitempty"` // nil = built-in task instructions
}
ProfileEditorial is a profile's editorial brain. Every field is optional; an empty/nil value inherits from the global AnalysisConfig + package defaults (resolved in services.ResolveEditorial). It mirrors AnalysisConfig and adds per-profile taxonomy, rubric, and raw prompt overrides.
type ProfileSelection ¶ added in v0.4.0
type ProfileSelection struct {
Topics []string `json:"topics,omitempty"`
IncludeFeedIds []string `json:"include_feed_ids,omitempty"`
ExcludeFeedIds []string `json:"exclude_feed_ids,omitempty"`
}
ProfileSelection is how a profile chooses its feeds. Membership is the feeds whose topics intersect Topics, plus IncludeFeedIds, minus ExcludeFeedIds, restricted to enabled feeds. An empty selection (no topics, no includes) means "all enabled feeds". Include/exclude are stored as feed ids (resolved at apply time) so re-resolution does not need the original URLs.
type ProfilesFile ¶ added in v0.4.0
type ProfilesFile struct {
Profiles []ProfileConfig `yaml:"profiles"`
}
ProfilesFile is the YAML catalog of profiles (profiles.yml), mirroring FeedsFile. It is applied to the database at server startup: each entry is upserted and its feed pool (referenced by URL) is reconciled.
type PromptOverrides ¶ added in v0.4.0
type PromptOverrides struct {
Tasks map[string]string `json:"tasks,omitempty" yaml:"tasks,omitempty"`
DigestSummary string `json:"digest_summary,omitempty" yaml:"digest_summary,omitempty"`
Dedupe string `json:"dedupe,omitempty" yaml:"dedupe,omitempty"`
}
PromptOverrides lets a profile replace task instructions verbatim. Tasks is keyed by analysis task name (see KnownPromptTaskNames; the scoring task is "rubric" in default mode, "importance" only under vibe_score: true). Output schema and required keys are NOT overridable, so validation still applies.
type ProviderConfig ¶
type ProviderConfig struct {
Name string `json:"name"` // User-defined name for this provider configuration (required)
ProviderType string `json:"provider_type"`
ModelName string `json:"model_name"`
Enabled bool `json:"enabled"`
BaseURL string `json:"base_url,omitempty"` // Used for Ollama and other local providers
MaxRetries *int `json:"max_retries,omitempty"` // Using pointer type for zero values (GORM best practice)
TimeoutMinutes *int `json:"timeout_minutes,omitempty"` // Using pointer type for zero values (GORM best practice)
APIKey string `json:"api_key,omitempty"` // Per-provider API key; overrides the global key when set
Credentials []CodexCredential `json:"credentials,omitempty"` // openai-codex OAuth credential pool
}
ProviderConfig represents configuration for a specific LLM provider used for digest generation
type ReferencedReport ¶
type ReferencedReport struct {
Title string `json:"title"`
URL string `json:"url"`
Publisher string `json:"publisher"`
Context string `json:"context"`
Category string `json:"category"`
Primary bool `json:"primary"`
}
ReferencedReport is an explicit third-party report, research item, advisory, whitepaper, or technical analysis linked from an article.
type RelatedArticle ¶
type RelatedArticle struct {
ArticleId string `gorm:"primaryKey;column:article_id" json:"article_id"`
RelatedArticleId string `gorm:"primaryKey;column:related_article_id" json:"related_article_id"`
RelationType string `gorm:"column:relation_type" json:"relation_type"` // e.g., "similar", "continuation", "response"
SimilarityScore float64 `gorm:"column:similarity_score" json:"similarity_score"`
}
RelatedArticle represents a relationship between two articles
func (RelatedArticle) TableName ¶
func (RelatedArticle) TableName() string
TableName specifies the table name for RelatedArticle
type RubricConfig ¶ added in v0.4.0
type RubricConfig struct {
Weights map[string]float64 `json:"weights,omitempty" yaml:"weights,omitempty"`
Tiers *TierThresholds `json:"tiers,omitempty" yaml:"tiers,omitempty"`
AggregatorScore *int `json:"aggregator_score,omitempty" yaml:"aggregator_score,omitempty"`
EvergreenCap *int `json:"evergreen_cap,omitempty" yaml:"evergreen_cap,omitempty"`
PromoCap *int `json:"promo_cap,omitempty" yaml:"promo_cap,omitempty"`
}
RubricConfig overrides the importance model for a profile. Weights keys are the six rubric dimensions (specificity, severity, breadth, novelty, actionability, credibility); nil sub-fields fall back to scoring.DefaultConfig().
type ScraperConfig ¶ added in v0.4.0
type ScraperConfig struct {
Type string `json:"type" yaml:"type"`
Scraping string `json:"scraping,omitempty" yaml:"scraping,omitempty"` // "dynamic", "full_browser", "none" (use feed content, no fetch), or "" (static)
Selectors *Selectors `json:"selectors,omitempty" yaml:"selectors,omitempty"`
Headers map[string]string `json:"headers,omitempty" yaml:"headers,omitempty"` // custom HTTP headers applied to all requests for this feed
Triggers *HostTriggers `json:"triggers,omitempty" yaml:"triggers,omitempty"`
Options map[string]any `json:"-" yaml:",inline"` // type-specific flat keys (links_selector, url_filter, ...)
}
ScraperConfig holds all scraping configuration for a feed: the scraper type, render mode, content selectors, custom headers, full_browser triggers, and any type-specific options. Type-specific keys (e.g. the html scraper's links_selector / url_filter) are captured by the inline Options map so adding a new scraper type needs no struct change here.
type SelectorCandidate ¶ added in v0.2.0
type SelectorCandidate struct {
Selector string `json:"selector"`
Chars int `json:"chars"`
LinkDensity float64 `json:"link_density"`
Snippet string `json:"snippet"`
}
SelectorCandidate is a ranked guess at the CSS selector wrapping an article body, produced by inspecting a scraped page. Mirrors scrapers.SelectorCandidate.
type Selectors ¶
type Selectors struct {
Article string `json:"article,omitempty" yaml:"article,omitempty"` // Selector to find the article content
Cutoff string `json:"cutoff,omitempty" yaml:"cutoff,omitempty"` // Selector to mark where to cutoff the article
Blacklist string `json:"blacklist,omitempty" yaml:"blacklist,omitempty"` // Elements to exclude from the article
}
Selectors defines CSS selectors for content extraction
func GetEffectiveSelectors ¶
GetEffectiveSelectors returns the effective selectors to use for a feed It prioritizes feed-specific selectors, then falls back to config defaults, then to system defaults
type ServerConfig ¶
type ServerConfig struct {
Feeds []FeedConfig `json:"feeds"`
DbPath string `json:"db_path"`
Providers []ProviderConfig `json:"providers"`
Analysis AnalysisConfig `json:"analysis"`
Notifications NotificationsConfig `json:"notifications"`
DefaultSelectors *Selectors `json:"-" yaml:"-"` // Loaded from feeds.yml, not config.json
SolimenAddr string `json:"solimen_addr"`
}
ServerConfig represents application configuration
type StepProviderOverride ¶ added in v0.4.0
type StepProviderOverride struct {
Provider string `json:"provider,omitempty"` // Name of configured provider to use for this step
Model string `json:"model,omitempty"` // Model name override for this step (uses provider's model if empty)
}
StepProviderOverride specifies a provider and/or model override for a single pipeline step
type Tag ¶
type Tag struct {
Id string `gorm:"primaryKey" json:"id"`
Name string `gorm:"uniqueIndex" json:"name"`
Color string `json:"color"`
Articles []Article `gorm:"many2many:article_tags;" json:"-"` // Many-to-many relationship with articles
}
Tag represents an article tag
type TierThresholds ¶ added in v0.4.0
type TierThresholds struct {
Must int `json:"must" yaml:"must"`
Should int `json:"should" yaml:"should"`
May int `json:"may" yaml:"may"`
}
TierThresholds are the inclusive lower bounds for the read tiers on a 0-100 score.
type WorkerPoolConfig ¶
type WorkerPoolConfig struct {
MaxWorkers *int `json:"max_workers,omitempty"` // Maximum number of concurrent workers (default: 3)
}
WorkerPoolConfig contains the configuration for the worker pool