core

package
v1.4.3 Latest Latest
Warning

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

Go to latest
Published: May 31, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var CreateOnCallProvider func(cfg *config.Config, awsClient *ssmincidents.Client) (OnCallProvider, error)

Function that will be implemented in the common package to avoid circular imports

Functions

func InitOnCallWorkflow

func InitOnCallWorkflow(awsClient *ssmincidents.Client, redisClient *redis.Client)

InitOnCallWorkflow initializes the global singleton instance This is called once from main.go with the Redis client and AWS client

Types

type AIAgent added in v1.4.3

type AIAgent interface {
	Name() string
	Kind() AITaskKind
	Run(ctx context.Context, task AITask) (*AICallResult, error)
}

AIAgent is one concrete model + prompt + (optional) tool wiring, dedicated to a single AITaskKind. Implementations live under pkg/agent/ai (e.g. detect, analyze).

Run is expected to be self-contained: it owns the model call, but the router handles cache / rate-limit / persistence around it.

type AICallResult added in v1.4.0

type AICallResult struct {
	Finding     *AIFinding
	UserPrompt  string
	RawResponse string
	DurationMs  int64
	Model       string

	// ToolCalls is populated by tool-using agents (analyze). It is
	// nil for tool-free agents (detect).
	ToolCalls []ToolCallTrace
}

AICallResult bundles the parsed finding with the inputs and outputs of the underlying model call. The trace fields (UserPrompt, RawResponse, DurationMs, Model) are persisted into the detect log so operators can audit what was sent to the model and what came back.

SystemPrompt is intentionally omitted — it is a constant per build and would bloat every record. Operators can fetch the current assembled system prompt via the agent admin API.

type AIFinding added in v1.3.9

type AIFinding struct {
	Title       string
	Summary     string
	Severity    string  // critical|high|medium|low
	Category    string  // e.g. "database", "auth", "deploy"
	Confidence  float64 // 0..1
	Suggestions []string
	SampleIDs   []string // signal IDs / pattern IDs for traceability

	// Analyze-mode fields. All optional; omitempty so detect-mode
	// payloads stay byte-compatible with the pre-E1 shape.
	RootCauseHypotheses []RootCauseHypothesis `json:"root_cause_hypotheses,omitempty"`
	Evidence            []EvidenceItem        `json:"evidence,omitempty"`
	RelatedPatternIDs   []string              `json:"related_pattern_ids,omitempty"`
	NextSteps           []string              `json:"next_steps,omitempty"`
}

AIFinding is the structured response returned by an AISRE for an unknown / spiking pattern. Used by detect mode.

Detect mode populates Title, Summary, Severity, Category, Confidence, Suggestions, SampleIDs. The lower block (RootCauseHypotheses, Evidence, RelatedPatternIDs, NextSteps) is populated by analyze mode only; detect leaves them empty and they marshal as omitempty.

type AITask added in v1.4.3

type AITask interface {
	Kind() AITaskKind
	CacheKey() string
}

AITask is the input to an AIAgent.Run call. Each concrete task type carries the inputs needed by its kind and exposes a CacheKey() the router uses for memoisation. An empty CacheKey disables caching for that call.

type AITaskKind added in v1.4.3

type AITaskKind string

AITaskKind identifies what an AIAgent is being asked to do.

The dispatcher uses the kind to pick the right agent, cache, and rate limiter. New kinds are added by extending this enum and the router's wiring.

const (
	// AITaskDetect is a cheap, tool-free, single-call classification of
	// an unknown or spiking log pattern. The output is an AIFinding
	// emitted as an incident through services.CreateIncidentFromFinding.
	AITaskDetect AITaskKind = "detect"

	// AITaskAnalyze is an operator-triggered, tool-using investigation
	// of a single incident. The output is an AIFinding persisted to the
	// analyses storage blob. Analyze NEVER fans out to notification
	// channels.
	AITaskAnalyze AITaskKind = "analyze"
)

type AgentResult added in v1.3.9

type AgentResult struct {
	Verdict       AgentVerdict
	PatternID     string   // empty when VerdictUnknown and pattern not yet stored
	Template      string   // human-readable pattern template ("Failed to ... at <*>:<*>")
	SampleSignals []Signal // representative signals (capped, post-redaction)
	Frequency     int      // matches in the current tick / window
	Baseline      float64  // EWMA baseline for the pattern (0 when unknown)
}

AgentResult is the output of a Detector for one batch of signals that share the same fingerprint.

type AgentVerdict added in v1.3.9

type AgentVerdict int

AgentVerdict is the classification a Detector pipeline assigns to a batch of signals that share a fingerprint.

const (
	// VerdictKnownPattern means the pattern is in the catalog and current
	// frequency is within baseline — suppress (no AI, no incident).
	VerdictKnownPattern AgentVerdict = iota
	// VerdictUnknown means the pattern was never seen during training —
	// forward to AI for analysis.
	VerdictUnknown
	// VerdictSpike means the pattern is known but frequency exceeds the
	// baseline by more than the configured threshold — forward to AI.
	VerdictSpike
)

func (AgentVerdict) String added in v1.3.9

func (v AgentVerdict) String() string

String renders an AgentVerdict for logging.

type Alert

type Alert struct {
	// contains filtered or unexported fields
}

func NewAlert

func NewAlert(providers ...AlertProvider) *Alert

func (*Alert) SendAlert

func (a *Alert) SendAlert(incident *m.Incident) error

SendAlert is the legacy "first error wins" API. New code should use SendAllAlerts so a flaky Slack does not silently mute Telegram and Email. Kept here so external callers (and existing tests) compile without churn; internally we now delegate to SendAllAlerts and surface only the joined error.

func (*Alert) SendAllAlerts added in v1.4.0

func (a *Alert) SendAllAlerts(incident *m.Incident) AlertResult

SendAllAlerts tries every configured provider regardless of earlier failures. A single broken channel never prevents the others from firing — this is the multi-channel promise. The returned Err is non-nil iff at least one provider failed.

type AlertProvider

type AlertProvider interface {
	Name() string
	SendAlert(incident *m.Incident) error
}

AlertProvider is implemented by every notification channel (Slack, Telegram, MS Teams, Lark, Viber, Email, …). Name() identifies the channel in failure reports so operators can tell which one failed without parsing the wrapped error.

type AlertResult added in v1.4.0

type AlertResult struct {
	Succeeded []string
	Failed    map[string]error
	Err       error // joined errors from Failed, nil when none
}

AlertResult captures the outcome of SendAllAlerts: which providers succeeded, which failed (with their error), and a joined error containing all failures (nil when every provider succeeded). The list of Succeeded channel names is what the incident persistence layer should store as ChannelsNotified — it is the truth about what actually reached its destination, not a list of what was enabled in config.

type AnalyzeIncidentSnapshot added in v1.4.3

type AnalyzeIncidentSnapshot struct {
	IncidentID string     `json:"incident_id"`
	Title      string     `json:"title,omitempty"`
	Service    string     `json:"service,omitempty"`
	Source     string     `json:"source,omitempty"`
	Severity   string     `json:"severity,omitempty"`
	Resolved   bool       `json:"resolved,omitempty"`
	CreatedAt  time.Time  `json:"created_at,omitempty"`
	AckedAt    *time.Time `json:"acked_at,omitempty"`
	ResolvedAt *time.Time `json:"resolved_at,omitempty"`

	// Content is the alert payload (the same map persisted on the
	// incident record). Operators see this verbatim in the UI.
	Content map[string]any `json:"content,omitempty"`

	// RequestedBy identifies the operator that triggered the analysis
	// (gateway-authenticated, so today this is just a free-form label
	// like "admin"). Stored on the AnalysisRecord for audit.
	RequestedBy string `json:"requested_by,omitempty"`
}

AnalyzeIncidentSnapshot is the input payload handed to the analyze-kind AIAgent. It captures the minimal incident metadata the agent needs to plan its tool calls; richer context (related logs, nearby incidents, pattern history) is fetched on demand via the agent's read-only tools, not pre-loaded into the snapshot.

The struct deliberately does not import pkg/storage — `pkg/core` must stay leaf-level. Callers (the admin controller, the worker) flatten storage records into this shape.

type AnalyzeTask added in v1.4.3

type AnalyzeTask struct {
	Snapshot AnalyzeIncidentSnapshot
}

AnalyzeTask wraps an on-demand analysis request. The snapshot carries the incident payload the agent inspects; richer context (related logs, pattern history) is fetched via the agent's read-only tools at run time, not pre-loaded here.

func (AnalyzeTask) CacheKey added in v1.4.3

func (t AnalyzeTask) CacheKey() string

CacheKey implements AITask. Empty disables caching — operators expect a fresh tool walk on every analyze request.

func (AnalyzeTask) Kind added in v1.4.3

func (AnalyzeTask) Kind() AITaskKind

Kind implements AITask.

type AnalyzeTool added in v1.4.3

type AnalyzeTool interface {
	// Name is the model-visible tool name. Must be a stable identifier
	// (snake_case is the convention).
	Name() string
	// Description is the one-line model-visible doc. The model uses it
	// to decide when to call the tool.
	Description() string
	// ArgsSchema returns a JSON schema (drafted as a generic map) for
	// the tool's argument object. Eino converts this into the model's
	// tool-call schema.
	ArgsSchema() map[string]any
	// Invoke runs the tool with the model-provided JSON args. The
	// returned ToolResult is serialised to JSON and fed back to the
	// model as the tool message. Errors are surfaced to the model as
	// a tool error so it can adapt.
	Invoke(ctx context.Context, args json.RawMessage) (*ToolResult, error)
}

AnalyzeTool is the contract every analyze-side read-only tool satisfies. Tools are registered with the analyze agent at construction time; the agent surfaces them to the model as Eino ToolInfo and dispatches model-requested calls back to this interface.

Implementations MUST be read-only. The compile-time guard in pkg/agent/ai/analyze rejects any import of services.CreateIncident transitively.

type DetectTask added in v1.4.3

type DetectTask struct {
	Result AgentResult
}

DetectTask wraps an AgentResult for detect-mode classification.

func (DetectTask) CacheKey added in v1.4.3

func (t DetectTask) CacheKey() string

CacheKey implements AITask. Detect memoisation is keyed by pattern id; an empty pattern id (unknown pattern not yet stored) disables caching for that call.

func (DetectTask) Kind added in v1.4.3

func (DetectTask) Kind() AITaskKind

Kind implements AITask.

type Detector added in v1.3.9

type Detector interface {
	Name() string
	Process(ctx context.Context, batch []Signal) ([]AgentResult, error)
}

Detector consumes signals and emits AgentResults.

type EvidenceItem added in v1.4.3

type EvidenceItem struct {
	Source  string `json:"source"`
	Summary string `json:"summary"`
	Detail  string `json:"detail,omitempty"`
}

EvidenceItem records one piece of supporting evidence the analyze agent gathered (typically from a tool call). Source identifies where it came from (e.g. "tool:get_related_logs"); Summary is a one-liner shown in the UI; Detail is the long form (capped on persist).

type OnCallProvider added in v1.3.0

type OnCallProvider interface {
	TriggerOnCall(ctx context.Context, incidentID string, cfg *config.OnCallConfig) error
}

OnCallProvider defines the interface for on-call notification providers

type OnCallWorkflow

type OnCallWorkflow struct {
	// contains filtered or unexported fields
}

OnCallWorkflow coordinates on-call escalation with a single provider

func GetOnCallWorkflow

func GetOnCallWorkflow() *OnCallWorkflow

GetOnCallWorkflow returns the global singleton instance This maintains compatibility with existing code

func NewOnCallWorkflow added in v1.3.0

func NewOnCallWorkflow(redisClient *redis.Client, provider OnCallProvider) *OnCallWorkflow

NewOnCallWorkflow creates a new on-call workflow with the given provider

func (*OnCallWorkflow) Ack

func (w *OnCallWorkflow) Ack(incidentID string) error

Ack acknowledges an incident to prevent escalation

func (*OnCallWorkflow) Start

func (w *OnCallWorkflow) Start(incidentID string, oc config.OnCallConfig) error

Start initiates the on-call workflow for an incident

type QueueListener

type QueueListener interface {
	StartListening(handler func(content *map[string]interface{}) error) error
}

type RootCauseHypothesis added in v1.4.3

type RootCauseHypothesis struct {
	Hypothesis string  `json:"hypothesis"`
	Confidence float64 `json:"confidence"`
	Rationale  string  `json:"rationale,omitempty"`
}

RootCauseHypothesis is one candidate explanation produced by an analyze-mode agent. Confidence is in [0, 1]; Rationale is a short human-readable justification.

type Signal added in v1.3.9

type Signal struct {
	Source    string // e.g. "elasticsearch:prod-app"
	Timestamp time.Time
	Severity  string                 // raw severity from source, best-effort
	Message   string                 // primary text payload
	Fields    map[string]interface{} // structured fields
	Raw       map[string]interface{} // original document (capped size)
}

Signal is one normalized observation pulled from a SignalSource.

Fields holds best-effort structured fields; Raw is the original source document (capped to AgentConfig.SignalMaxBytes by the SignalSource so the pipeline cannot OOM on large documents).

type SignalSource added in v1.3.9

type SignalSource interface {
	// Name uniquely identifies the configured source instance. It is used as
	// part of Redis cursor keys, so it must be stable across restarts.
	Name() string

	// Pull returns all signals strictly newer than `since`, plus the new
	// cursor (== max timestamp seen, or `since` if no signals were returned).
	Pull(ctx context.Context, since time.Time) ([]Signal, time.Time, error)
}

SignalSource is a puller for one external observability backend (Elasticsearch, Loki, CloudWatch, ...).

type ToolCallTrace added in v1.4.3

type ToolCallTrace struct {
	Name       string
	Args       string
	Output     string
	DurationMs int64
	Error      string
}

ToolCallTrace is one model-issued tool round-trip captured for audit.

type ToolResult added in v1.4.3

type ToolResult struct {
	Tool  string         `json:"tool"`
	Found bool           `json:"found"`
	Data  map[string]any `json:"data,omitempty"`
}

ToolResult is the uniform envelope every AnalyzeTool returns. The shape is stable so the model sees a predictable schema across tools; the per-tool payload lives in Data as JSON-encodable values.

Tool — the tool name (mirrors AnalyzeTool.Name) so a model parsing multiple tool responses can disambiguate without relying on call ordering.

Found — optional flag for lookup-style tools (pattern_history, describe_service) to signal "no such entity" without an error. Defaults to true; lookups that miss should set it to false and leave Data empty (or populated with just the query echo).

Data — the typed payload. Keys are tool-specific; values must be JSON-marshalable (no channels, funcs, or unexported structs).

Jump to

Keyboard shortcuts

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