Documentation
¶
Overview ¶
Package learning implements a lightweight learning-from-corrections system.
When the user corrects the assistant ("no, that's wrong", "actually, ..."), the correction is detected and stored in a PostgreSQL-backed store. Future agent runs query the store and inject relevant past corrections into the system prompt to improve responses.
Package learning's evolution.go implements PicoClaw's self-improvement pipeline: hot-path recording → cold-path pattern clustering → draft generation → review (with secret scanning) → apply (with rollback).
Stolen from PicoClaw's pkg/evolution/. Wires into Overkill's existing hooks system (§6.3) and self-learning loop (§6.2).
Index ¶
- Constants
- func ExtractCorrect(msg string) string
- func FormatPrompt(corrections []*Correction) string
- func IsCorrection(msg string) bool
- func WorkspaceScope(workspace string) string
- type AppliedGuidance
- type AttemptSnapshot
- type ChangeKind
- type ColdPathResult
- type Correction
- type DraftEvidence
- type DraftGenerator
- type DraftStatus
- type DraftType
- type Engine
- func (e *Engine) ApplyReviewedDraft(ctx context.Context, id string) (SkillDraft, error)
- func (e *Engine) ListDrafts(ctx context.Context) ([]SkillDraft, error)
- func (e *Engine) LoadAppliedGuidance(ctx context.Context) ([]AppliedGuidance, error)
- func (e *Engine) RecordTurn(ctx context.Context, record LearningRecord) error
- func (e *Engine) ReviewDraft(ctx context.Context, id string, approve bool) (SkillDraft, error)
- func (e *Engine) RollbackDraft(ctx context.Context, id string) (SkillDraft, error)
- func (e *Engine) RunColdPath(ctx context.Context, workspace string, applyMode bool) (*ColdPathResult, error)
- type EngineOptions
- type EvidenceAwareDraftGenerator
- type HeuristicClusterer
- type HeuristicJudge
- type LearningRecord
- type PatternClusterer
- type ProviderDraftGenerator
- type ProviderDraftOptions
- type SkillDraft
- type SkillLifecycle
- type SkillProfile
- type SkillVersion
- type Store
- type SuccessJudge
- type TaskSuccessDecision
- type ToolExecution
Constants ¶
const DefaultMaxCorrections = 1000
DefaultMaxCorrections is the maximum number of corrections to store before evicting the oldest (LRU).
const MaxAppliedGuidanceBytes = 32 * 1024
const MaxAppliedGuidanceItems = 8
const MaxDraftBytes = 64 * 1024
const MaxLearningFileBytes = 4 * 1024 * 1024
const MaxLearningRecordBytes = 16 * 1024
const MaxLearningRecords = 512
const MaxStoredDrafts = 256
Variables ¶
This section is empty.
Functions ¶
func ExtractCorrect ¶
ExtractCorrect extracts the substantive part of a correction message (strips the correction prefix/signal words). Returns the corrected instruction text.
func FormatPrompt ¶
func FormatPrompt(corrections []*Correction) string
FormatPrompt formats corrections into a prompt snippet for injection.
func IsCorrection ¶
IsCorrection returns true if the user message looks like a correction.
func WorkspaceScope ¶
Types ¶
type AppliedGuidance ¶
type AppliedGuidance struct {
ID string `json:"id"`
Name string `json:"name"`
Body string `json:"body"`
AppliedHash string `json:"appliedHash"`
}
AppliedGuidance is verified, explicitly installed project guidance. Drafts in any other state, stale content, or mismatched workspaces never become context.
type AttemptSnapshot ¶
type AttemptSnapshot struct {
Attempt int `json:"attempt"`
Skills []string `json:"skills"` // active skills at this point
Path []string `json:"path"` // tool names tried so far
Error string `json:"error,omitempty"`
}
AttemptSnapshot captures state at each retry attempt.
type ChangeKind ¶
type ChangeKind string
const ( ChangeCreate ChangeKind = "create" ChangeAppend ChangeKind = "append" ChangeReplace ChangeKind = "replace" ChangeMerge ChangeKind = "merge" )
type ColdPathResult ¶
type ColdPathResult struct {
RunAt time.Time `json:"runAt"`
RecordsLoaded int `json:"recordsLoaded"`
JudgedTurns int `json:"judgedTurns"`
SuccessfulTurns int `json:"successfulTurns"`
UnverifiedTurns int `json:"unverifiedTurns"`
JudgeErrors int `json:"judgeErrors"`
ClustersFound int `json:"clustersFound"`
ClusterReasons []string `json:"clusterReasons"`
CandidateDrafts int `json:"candidateDrafts"`
QuarantinedDrafts int `json:"quarantinedDrafts"`
AppliedDrafts int `json:"appliedDrafts"`
GenerationErrors int `json:"generationErrors"`
ApplyErrors int `json:"applyErrors"`
Drafts []SkillDraft `json:"drafts"`
}
type Correction ¶
type Correction struct {
Context string `json:"context"` // the user message that triggered the wrong response
Wrong string `json:"wrong"` // the assistant's incorrect response
Correct string `json:"correct"` // the user's correction message
Timestamp int64 `json:"timestamp"` // Unix nano timestamp
}
Correction represents a stored correction pair: what the assistant said that was wrong, and what the user corrected it to.
func NewCorrection ¶
func NewCorrection(context, wrong, correct string) *Correction
NewCorrection creates a Correction with the current timestamp.
func UnmarshalCorrection ¶
func UnmarshalCorrection(data []byte) (*Correction, error)
UnmarshalCorrection deserialises a correction from JSON bytes.
func (*Correction) Key ¶
func (c *Correction) Key() string
Key returns the hash key for this correction (sha256 of context + wrong).
func (*Correction) Marshal ¶
func (c *Correction) Marshal() ([]byte, error)
Marshal serialises the correction to JSON bytes.
func (*Correction) MatchScore ¶
func (c *Correction) MatchScore(queryTokens []string) float64
MatchScore returns the relevance score between a query and a correction. It scores against both the context and the wrong response.
type DraftEvidence ¶
type DraftEvidence struct {
SimilarRecords []LearningRecord `json:"similarRecords"`
PastCorrections []Correction `json:"pastCorrections"`
WorkspaceFiles []string `json:"workspaceFiles"`
}
DraftEvidence carries supporting context for draft generation.
type DraftGenerator ¶
type DraftGenerator interface {
GenerateDraft(ctx context.Context, rule LearningRecord, matches []SkillProfile) (SkillDraft, error)
}
DraftGenerator produces SkillDraft proposals from clustered patterns. The Evidence-aware variant receives supporting evidence (similar tasks, past corrections) for richer draft generation.
type DraftStatus ¶
type DraftStatus string
const ( DraftCandidate DraftStatus = "candidate" DraftQuarantined DraftStatus = "quarantined" DraftAccepted DraftStatus = "accepted" DraftRejected DraftStatus = "rejected" DraftApplying DraftStatus = "applying" DraftRollingBack DraftStatus = "rolling_back" DraftApplied DraftStatus = "applied" DraftRolledBack DraftStatus = "rolled_back" )
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine orchestrates the hot-path recording and cold-path batch processing for self-improvement.
func NewEngine ¶
func NewEngine(recordDir, skillDir string, clusterer PatternClusterer, generator DraftGenerator, judge SuccessJudge) *Engine
NewEngine creates an evolution engine.
func NewEngineWithOptions ¶
func NewEngineWithOptions(recordDir, skillDir string, clusterer PatternClusterer, generator DraftGenerator, judge SuccessJudge, options EngineOptions) *Engine
func (*Engine) ApplyReviewedDraft ¶
ApplyReviewedDraft durably records intent before mutation. Repeating it after a crash finalizes the same content, rather than appending a second time.
func (*Engine) ListDrafts ¶
func (e *Engine) ListDrafts(ctx context.Context) ([]SkillDraft, error)
ListDrafts returns bounded, persisted proposals for this explicit workspace.
func (*Engine) LoadAppliedGuidance ¶
func (e *Engine) LoadAppliedGuidance(ctx context.Context) ([]AppliedGuidance, error)
func (*Engine) RecordTurn ¶
func (e *Engine) RecordTurn(ctx context.Context, record LearningRecord) error
RecordTurn is called synchronously at the end of every agent turn (hot path). Appends a LearningRecord to JSONL.
func (*Engine) ReviewDraft ¶
ReviewDraft is a trusted operator API, intentionally absent from model tools.
func (*Engine) RollbackDraft ¶
RollbackDraft refuses to overwrite edits made after the generated skill was installed. Repeating an interrupted rollback finalizes the recorded base.
func (*Engine) RunColdPath ¶
func (e *Engine) RunColdPath(ctx context.Context, workspace string, applyMode bool) (*ColdPathResult, error)
RunColdPath is the batch job. It:
- Loads all task records
- Runs pattern clustering
- Generates draft skills for each cluster
- Reviews drafts (secret scanning)
- Applies accepted drafts (with rollback capability)
type EngineOptions ¶
type EvidenceAwareDraftGenerator ¶
type EvidenceAwareDraftGenerator interface {
DraftGenerator
GenerateDraftWithEvidence(ctx context.Context, rule LearningRecord,
matches []SkillProfile, evidence DraftEvidence) (SkillDraft, error)
}
EvidenceAwareDraftGenerator receives evidence context.
type HeuristicClusterer ¶
type HeuristicClusterer struct{}
HeuristicClusterer groups records by task hash similarity.
func (*HeuristicClusterer) BuildPatterns ¶
func (h *HeuristicClusterer) BuildPatterns(ctx context.Context, workspace string, tasks []LearningRecord, existing []LearningRecord) ([]LearningRecord, []string, error)
type HeuristicJudge ¶
type HeuristicJudge struct{}
HeuristicJudge classifies success by checking for error markers.
func (*HeuristicJudge) JudgeTaskRecord ¶
func (h *HeuristicJudge) JudgeTaskRecord(ctx context.Context, record LearningRecord) (TaskSuccessDecision, error)
type LearningRecord ¶
type LearningRecord struct {
WorkspaceHash string `json:"workspaceHash"`
TaskHash string `json:"taskHash"` // SHA256 of user input
ToolExecutions []ToolExecution `json:"toolExecutions"`
AttemptTrail []AttemptSnapshot `json:"attemptTrail"` // what was tried
FinalOutput string `json:"finalOutput"`
WinningPath []string `json:"winningPath"` // tool names that succeeded
LateAddedSkills []string `json:"lateAddedSkills"` // skills added mid-task
MaturityScore float64 `json:"maturityScore"`
SuccessRate float64 `json:"successRate"`
ClusterReason string `json:"clusterReason,omitempty"`
EventCount int `json:"eventCount"`
SessionID string `json:"sessionId"`
ModelID string `json:"modelId"`
RecordedAt time.Time `json:"recordedAt"`
}
LearningRecord captures one agent turn for later pattern clustering. Written synchronously after every turn into JSONL.
type PatternClusterer ¶
type PatternClusterer interface {
BuildPatterns(ctx context.Context, workspace string,
tasks []LearningRecord, existing []LearningRecord) ([]LearningRecord, []string, error)
}
PatternClusterer groups learning records into clusters that share common failure patterns or successful strategies.
type ProviderDraftGenerator ¶
type ProviderDraftGenerator struct {
// contains filtered or unexported fields
}
func NewProviderDraftGenerator ¶
func NewProviderDraftGenerator(options ProviderDraftOptions) (*ProviderDraftGenerator, error)
func (*ProviderDraftGenerator) GenerateDraft ¶
func (g *ProviderDraftGenerator) GenerateDraft(ctx context.Context, record LearningRecord, _ []SkillProfile) (SkillDraft, error)
type ProviderDraftOptions ¶
type ProviderDraftOptions struct {
Provider providers.Provider
Model string
MaxTokens int
Timeout time.Duration
BudgetGate func(context.Context) error
RecordUsage func(context.Context, providers.Usage) error
}
ProviderDraftOptions requires explicit budget admission and usage recording. Limits bound one request; Engine.RunColdPath permits at most eight requests. BudgetGate is checked before every call. It is not an invoice reservation.
type SkillDraft ¶
type SkillDraft struct {
BaseHash string `json:"baseHash,omitempty"`
OriginalExists bool `json:"originalExists"`
ID string `json:"id"`
WorkspaceHash string `json:"workspaceHash"`
ReviewedAt time.Time `json:"reviewedAt,omitempty"`
AppliedAt time.Time `json:"appliedAt,omitempty"`
BackupID string `json:"backupId,omitempty"`
AppliedHash string `json:"appliedHash,omitempty"`
TargetSkillName string `json:"targetSkillName"`
DraftType DraftType `json:"draftType"`
ChangeKind ChangeKind `json:"changeKind"`
BodyOrPatch string `json:"bodyOrPatch"`
Status DraftStatus `json:"status"`
ReviewNotes string `json:"reviewNotes,omitempty"`
ScanFindings []string `json:"scanFindings,omitempty"`
GeneratedAt time.Time `json:"generatedAt"`
}
SkillDraft is an AI-proposed skill change.
type SkillLifecycle ¶
type SkillLifecycle string
const ( SkillActive SkillLifecycle = "active" SkillCold SkillLifecycle = "cold" // 90d idle + retention < 0.3 SkillArchived SkillLifecycle = "archived" // 180d + < 0.2 SkillDeleted SkillLifecycle = "deleted" // 365d + < 0.1 )
type SkillProfile ¶
type SkillProfile struct {
Name string `json:"name"`
RetentionScore float64 `json:"retentionScore"`
UseCount int `json:"useCount"`
LastUsedAt time.Time `json:"lastUsedAt"`
CreatedAt time.Time `json:"createdAt"`
Status SkillLifecycle `json:"status"`
VersionHistory []SkillVersion `json:"versionHistory"`
}
SkillProfile tracks a skill's usage and retention across sessions.
type SkillVersion ¶
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store persists corrections using PostgreSQL and provides retrieval via case-insensitive keyword search.
func NewStore ¶
NewStore wraps a *sql.DB for PostgreSQL-backed correction storage. The caller owns the DB lifecycle — the store does not close it.
func (*Store) FindCorrections ¶
func (s *Store) FindCorrections(query string, topK int) ([]*Correction, error)
FindCorrections returns up to topK corrections matching the query. Matches are found via ILIKE on the context and wrong columns against each token in the query, ordered by timestamp DESC (most recent first). Query tokens are escaped to prevent % and _ being treated as wildcards.
func (*Store) Save ¶
func (s *Store) Save(c *Correction) error
Save stores a correction. If a correction with the same (context, wrong) already exists, it is overwritten (UPSERT via ON CONFLICT). Enforces maxItems by evicting the oldest corrections when full.
type SuccessJudge ¶
type SuccessJudge interface {
JudgeTaskRecord(ctx context.Context, record LearningRecord) (TaskSuccessDecision, error)
}
SuccessJudge evaluates whether a task record represents a success.