Documentation
¶
Index ¶
- Constants
- Variables
- func CallerActor(ctx context.Context) string
- func CallerAuthorizationPresent(ctx context.Context) bool
- func CallerAuthorized(ctx context.Context, permission Permission) bool
- func CallerClusterAllowed(ctx context.Context, clusterID string) bool
- func EmitAnalyzeEvent(ctx context.Context, ev AnalyzeEvent)
- func EmitChatEvent(ctx context.Context, event ChatEvent)
- func InitOnCallWorkflow(awsClient *ssmincidents.Client, redisClient redis.UniversalClient)
- func IsOnCallWorkflowInitialized() bool
- func NewToolError(code ToolErrorCode, message string, cause error) error
- func SetOnCallWorkflow(w *OnCallWorkflow)
- func ToolDisplayName(tool Tool) string
- func WithAnalyzeObserver(ctx context.Context, obs AnalyzeObserver) context.Context
- func WithCallerAuthorization(ctx context.Context, authorization CallerAuthorization) context.Context
- func WithChatObserver(ctx context.Context, observer ChatObserver) context.Context
- type AIAgent
- type AICallResult
- type AIFinding
- type AITask
- type AITaskKind
- type AgentResult
- type AgentVerdict
- type Alert
- type AlertProvider
- type AlertResult
- type AnalyzeEvent
- type AnalyzeIncidentSnapshot
- type AnalyzeObserver
- type AnalyzeTask
- type AnalyzeTool
- type AnalyzeToolDisplayer
- type AssessmentDriver
- type Attachment
- type AttachmentSender
- type BaselineCoverage
- type BaselineProvider
- type BaselineRecord
- type BaselineRequest
- type BaselineResult
- type Bucket
- type CallerAuthorization
- type ChatApproval
- type ChatAttachment
- type ChatCitation
- type ChatEvent
- type ChatIncidentContext
- type ChatObserver
- type ChatResourceBreak
- type ChatResourceChange
- type ChatResourceChangeField
- type ChatResourceConditionReason
- type ChatResourceEvidence
- type ChatResourceReasonCount
- type ChatResourceRef
- type ChatResourceTermination
- type ChatResourceWaiting
- type ChatTask
- type ChatTimeRange
- type ChatTurnAgent
- type ChatTurnResult
- type ClusterScope
- type ContextAuthorizedTool
- type DetectTask
- type DetectionEmissionResult
- type Detector
- type Embedder
- type EvidenceItem
- type HealthAssessment
- type HealthAssessmentInput
- type HealthBudget
- type HealthCapability
- type HealthCollectRequest
- type HealthCollection
- type HealthProvider
- type HealthState
- type HealthUsage
- type LogHealthObservation
- type LogHealthRecorder
- type MeasureAvailability
- type NotableIncident
- type Observation
- type OnCallProvider
- type OnCallWorkflow
- type Permission
- type QueueListener
- type Readiness
- type ReportImage
- type ReportModel
- type ReportRenderer
- type RootCauseHypothesis
- type Scrubber
- type ServiceTopology
- type ServiceTopologyEdge
- type ServiceTopologyNode
- type ServiceTopologyProvider
- type ServiceTopologyRequest
- type Signal
- type SignalDetector
- type SignalEvidence
- type SignalLearner
- type SignalSource
- type SourceCommitter
- type SourceHealthObservation
- type SourceRewinder
- type SourceRoutedTool
- type TextSender
- type Tool
- type ToolCallTrace
- type ToolDisplayer
- type ToolError
- type ToolErrorCode
- type ToolResult
- type TopologyExtension
- type TypedVerdict
Constants ¶
const ( // FieldService is the Signal.Fields key holding the discovered service // name (string). Empty when the source did not stamp one. FieldService = "service" // FieldSignal is the Signal.Fields key holding the logical signal name // (string) — e.g. a metric golden-signal or trace operation label. FieldSignal = "signal" )
Canonical Signal.Fields keys shared across the agent pipeline. They name the two attributes every signal type can carry regardless of source: the discovered service and the logical signal name (a metric's golden-signal, a trace operation, or a log template label). They live in OSS so any consumer — the worker's learn-exclusion chokepoint, an enterprise metric/trace brain, a standing data source — keys off ONE definition. Enterprise packages (pkg/intel, pkg/datasource) keep their own copies to stay decoupled; a cross-package drift test pins them equal.
const ( AnalyzeEventRunStarted = "run_started" AnalyzeEventModelStarted = "model_started" AnalyzeEventModelDelta = "model_delta" AnalyzeEventModelFinished = "model_finished" AnalyzeEventToolStarted = "tool_started" AnalyzeEventToolFinished = "tool_finished" AnalyzeEventToolError = "tool_error" AnalyzeEventRunFinished = "run_finished" AnalyzeEventRunFailed = "run_failed" )
Analyze run event kinds. These are the wire values the UI switches on, so they are part of the API surface — renaming one breaks a client.
const ( ChatEventRunStarted = "run_started" ChatEventModelDelta = "model_delta" ChatEventToolStarted = "tool_started" ChatEventToolFinished = "tool_finished" ChatEventCompacted = "compacted" ChatEventRunFinished = "run_finished" ChatEventRunFailed = "run_failed" ChatEventRunCancelled = "run_cancelled" ChatEventApproval = "approval_required" )
Variables ¶
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 CallerActor ¶ added in v1.4.29
func CallerAuthorizationPresent ¶ added in v1.4.31
func CallerAuthorized ¶ added in v1.4.25
func CallerAuthorized(ctx context.Context, permission Permission) bool
CallerAuthorized returns false for absent/background callers and explicit denials.
func CallerClusterAllowed ¶ added in v1.4.31
func EmitAnalyzeEvent ¶ added in v1.4.24
func EmitAnalyzeEvent(ctx context.Context, ev AnalyzeEvent)
EmitAnalyzeEvent delivers ev to the observer on ctx, if any. It stamps At when the caller left it zero.
func EmitChatEvent ¶ added in v1.4.25
EmitChatEvent stamps and delivers an event when an observer is attached.
func InitOnCallWorkflow ¶
func InitOnCallWorkflow(awsClient *ssmincidents.Client, redisClient redis.UniversalClient)
InitOnCallWorkflow initializes the global singleton instance This is called once from main.go with the Redis client and AWS client
func IsOnCallWorkflowInitialized ¶ added in v1.4.4
func IsOnCallWorkflowInitialized() bool
IsOnCallWorkflowInitialized reports whether the global on-call workflow singleton has been initialized via InitOnCallWorkflow. Callers should check this before GetOnCallWorkflow so an uninitialized singleton is skipped instead of panicking the process.
func NewToolError ¶ added in v1.4.25
func NewToolError(code ToolErrorCode, message string, cause error) error
NewToolError constructs a classified tool error with a model-safe message.
func SetOnCallWorkflow ¶ added in v1.4.13
func SetOnCallWorkflow(w *OnCallWorkflow)
SetOnCallWorkflow installs (or, with a nil argument, clears) the global on-call workflow singleton directly, bypassing the one-shot boot path in InitOnCallWorkflow. It lets callers wire a pre-built workflow after startup (or reset it) without the sync.Once guard.
func ToolDisplayName ¶ added in v1.4.24
ToolDisplayName returns an explicit display name or title-cases the stable name.
func WithAnalyzeObserver ¶ added in v1.4.24
func WithAnalyzeObserver(ctx context.Context, obs AnalyzeObserver) context.Context
WithAnalyzeObserver attaches an observer to ctx. Passing it through the context rather than the task keeps AnalyzeTask a plain serialisable value.
func WithCallerAuthorization ¶ added in v1.4.25
func WithCallerAuthorization(ctx context.Context, authorization CallerAuthorization) context.Context
WithCallerAuthorization carries one caller decision into HTTP and model tools.
func WithChatObserver ¶ added in v1.4.25
func WithChatObserver(ctx context.Context, observer ChatObserver) context.Context
WithChatObserver attaches an observer to a chat run context.
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 detect-only 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" // AITaskChat is an operator-triggered conversational DevOps/SRE turn. // Its markdown result is persisted in a chat session and is never cached. AITaskChat AITaskKind = "chat" )
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)
AgentKind string // emitting agent kind; "detect" for the detect worker
SignalKind string // brain kind: logs | metrics | traces
DetectionEmission *DetectionEmissionResult
// RuleSeverity is the strongest operator-declared severity carried by the
// grouped signals (e.g. an anomaly rule's `severity: critical`). Empty for
// auto-discovered signals with no declared severity. It acts as a floor:
// the AI may escalate but must not silently demote below it.
RuleSeverity string
}
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 ¶
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 ¶
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 AnalyzeEvent ¶ added in v1.4.24
type AnalyzeEvent struct {
Seq int64 `json:"seq"`
At time.Time `json:"at"`
Kind string `json:"kind"`
Tool string `json:"tool,omitempty"`
ToolDisplay string `json:"tool_display,omitempty"`
Args string `json:"args,omitempty"`
Output string `json:"output,omitempty"`
DurationMs int64 `json:"duration_ms,omitempty"`
Error string `json:"error,omitempty"`
// Turn is the model round-trip this event belongs to, starting at 1. The
// ReAct loop alternates model turn -> tool calls -> model turn, so the UI
// uses it to group tools under the turn that requested them.
Turn int `json:"turn,omitempty"`
// AnalysisID is set on the terminal event so the client can fetch the
// persisted record without guessing which analysis it just watched.
AnalysisID string `json:"analysis_id,omitempty"`
}
AnalyzeEvent is one observable step of an analyze run, emitted live while the ReAct loop is still working.
It carries the SAME already-capped, already-redacted strings that end up on the persisted ToolCallTrace — a live viewer never sees more than the stored record, so streaming opens no new egress path.
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 AnalyzeObserver ¶ added in v1.4.24
type AnalyzeObserver interface {
OnAnalyzeEvent(AnalyzeEvent)
}
AnalyzeObserver receives run events as they happen.
Implementations MUST NOT block: an observer is called from inside the agent's tool callbacks, so a slow or disconnected consumer would otherwise stall the model run itself.
func AnalyzeObserverFrom ¶ added in v1.4.24
func AnalyzeObserverFrom(ctx context.Context) AnalyzeObserver
AnalyzeObserverFrom returns the observer on ctx, or nil when the run is not being watched. Callers emit unconditionally via EmitAnalyzeEvent instead of nil-checking at every call site.
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 = Tool
AnalyzeTool is retained for source compatibility. Deprecated: use Tool.
type AnalyzeToolDisplayer ¶ added in v1.4.24
type AnalyzeToolDisplayer = ToolDisplayer
AnalyzeToolDisplayer is retained for source compatibility. Deprecated: use ToolDisplayer.
type AssessmentDriver ¶ added in v1.4.27
type AssessmentDriver struct {
Family string `json:"family"`
Measure string `json:"measure"`
Operation string `json:"operation,omitempty"`
Weight float64 `json:"weight,omitempty"`
}
AssessmentDriver identifies one normalized input that influenced an assessment.
type Attachment ¶ added in v1.4.8
type Attachment struct {
Filename string // "incident-<shortid>.png"
MIME string // "image/png"
Data []byte // the rendered image bytes
Caption string // short redacted text summary (also the fallback body)
}
Attachment is one rendered artifact (today, an incident report image) bound for a channel. Caption is the short text summary that image-capable channels attach alongside the binary AND that image-incapable channels fall back to. The Data bytes are already the final encoded image; the text is already redacted by the report assembler.
type AttachmentSender ¶ added in v1.4.8
type AttachmentSender interface {
SendAttachment(incident *m.Incident, att Attachment) error
}
AttachmentSender is an OPTIONAL capability a notification channel may implement on top of the mandatory AlertProvider — exactly like storage.Searcher / storage.Lifecycle. A channel that can upload a binary image (Slack, Telegram, Email) implements it; a channel that cannot (Teams, Viber, Lark webhooks) simply does not, and the report delivery path detects the difference with a type assertion. The interface is deliberately generic: no per-channel special-casing leaks into the caller.
type BaselineCoverage ¶ added in v1.4.27
type BaselineCoverage struct {
Family string `json:"family"`
SourceType string `json:"source_type"`
Availability HealthState `json:"availability"`
ReasonCode string `json:"reason_code,omitempty"`
}
BaselineCoverage reports one contributing surface even when it returned no records.
type BaselineProvider ¶ added in v1.4.27
type BaselineProvider interface {
DescribeBaselines(context.Context, BaselineRequest) (BaselineResult, error)
}
BaselineProvider returns authorized learned expectations for trusted scope.
type BaselineRecord ¶ added in v1.4.27
type BaselineRecord struct {
Service string `json:"service"`
Operation string `json:"operation,omitempty"`
Signal string `json:"signal"`
Family string `json:"family"`
SourceType string `json:"source_type"`
PatternID string `json:"pattern_id,omitempty"`
ExpectedMean float64 `json:"expected_mean"`
ExpectedStd float64 `json:"expected_std"`
CurrentValue *float64 `json:"current_value"`
Unit string `json:"unit"`
ObservationCount int `json:"observation_count"`
Confident bool `json:"confident"`
LastTrainedAt time.Time `json:"last_trained_at"`
Availability HealthState `json:"availability"`
ReasonCode string `json:"reason_code,omitempty"`
Provenance []string `json:"provenance"`
}
BaselineRecord is a provider-neutral learned expectation without raw observations.
type BaselineRequest ¶ added in v1.4.27
type BaselineRequest struct {
OrgID string `json:"-"`
Service string `json:"-"`
Signal string `json:"-"`
PatternID string `json:"-"`
Window time.Duration `json:"-"`
Limit int `json:"-"`
At time.Time `json:"-"`
}
BaselineRequest carries trusted scope and bounded selectors to a read-only provider.
type BaselineResult ¶ added in v1.4.27
type BaselineResult struct {
Availability HealthState `json:"availability"`
ReasonCode string `json:"reason_code,omitempty"`
Found bool `json:"found"`
Truncated bool `json:"truncated"`
Omitted int `json:"omitted_records,omitempty"`
Records []BaselineRecord `json:"records"`
Coverage []BaselineCoverage `json:"coverage"`
}
BaselineResult is a deterministic bounded projection from one or more providers.
type Bucket ¶ added in v1.4.8
Bucket is one labelled tally in an aggregate breakdown — a severity band, a trend time-slice, or a top service. Count is the total; AIDetect and Webhook carry the per-origin split so the trend timeline can draw a stacked bar (AIDetect + Webhook == Count). Labels are already redacted for the top-services list (a service name is attacker-influenced webhook content); the severity/trend labels are renderer-controlled constants.
type CallerAuthorization ¶ added in v1.4.25
type CallerAuthorization struct {
Authenticated bool
Actor string
Permissions map[Permission]bool
Clusters *ClusterScope
}
CallerAuthorization is a request-scoped, role-neutral permission decision.
type ChatApproval ¶ added in v1.4.29
type ChatAttachment ¶ added in v1.4.25
type ChatAttachment struct {
Incident *ChatIncidentContext `json:"incident,omitempty"`
Service string `json:"service,omitempty"`
Time *ChatTimeRange `json:"time_range,omitempty"`
Resource *ChatResourceRef `json:"resource,omitempty"`
}
ChatAttachment grounds a turn without restricting the conversation to that context. Each field is optional and validated by the chat service.
type ChatCitation ¶ added in v1.4.25
type ChatCitation struct {
Tool string `json:"tool"`
Label string `json:"label,omitempty"`
Locator string `json:"locator,omitempty"`
}
ChatCitation identifies evidence used by a conversational answer.
type ChatEvent ¶ added in v1.4.25
type ChatEvent struct {
Seq int64 `json:"seq"`
At time.Time `json:"at"`
Kind string `json:"kind"`
Delta string `json:"delta,omitempty"`
Tool string `json:"tool,omitempty"`
CallID string `json:"call_id,omitempty"`
ToolDisplay string `json:"tool_display,omitempty"`
Args string `json:"args,omitempty"`
Output string `json:"output,omitempty"`
DurationMs int64 `json:"duration_ms,omitempty"`
Error string `json:"error,omitempty"`
Citations []ChatCitation `json:"citations,omitempty"`
Approval *ChatApproval `json:"approval,omitempty"`
ApprovalNonce string `json:"approval_nonce,omitempty"`
}
ChatEvent is one observable step of a chat turn. Error contains only a safe classification; backend and model errors must never cross this boundary.
type ChatIncidentContext ¶ added in v1.4.25
type ChatIncidentContext struct {
ID string `json:"id"`
Title string `json:"title,omitempty"`
Service string `json:"service,omitempty"`
Severity string `json:"severity,omitempty"`
Status string `json:"status,omitempty"`
Created time.Time `json:"created,omitempty"`
}
ChatIncidentContext is the bounded, redacted incident context that may be attached to a turn. Raw incident payloads are deliberately absent.
type ChatObserver ¶ added in v1.4.25
type ChatObserver interface {
OnChatEvent(ChatEvent)
}
ChatObserver receives events synchronously. Implementations must return immediately, normally by using a bounded non-blocking channel send.
func ChatObserverFrom ¶ added in v1.4.25
func ChatObserverFrom(ctx context.Context) ChatObserver
ChatObserverFrom returns the observer attached to ctx, if any.
type ChatResourceBreak ¶ added in v1.4.31
type ChatResourceBreak struct {
BrokeAtSource string `json:"broke_at_source,omitempty"`
Rule string `json:"rule"`
Severity string `json:"severity"`
BrokeAt *time.Time `json:"broke_at,omitempty"`
Count int `json:"count"`
Of int `json:"of,omitempty"`
Changes []ChatResourceChange `json:"changes"`
MoreChanges int `json:"more_changes,omitempty"`
Evidence *ChatResourceEvidence `json:"evidence,omitempty"`
History string `json:"history"`
Rebuilt []string `json:"rebuilt,omitempty"`
Untracked []string `json:"untracked,omitempty"`
Partial bool `json:"partial,omitempty"`
}
type ChatResourceChange ¶ added in v1.4.31
type ChatResourceChange struct {
Kind string `json:"kind"`
Namespace string `json:"namespace,omitempty"`
Name string `json:"name"`
Type string `json:"type"`
At time.Time `json:"at"`
Relation string `json:"relation"`
LeadSeconds int64 `json:"lead_seconds"`
Fields []ChatResourceChangeField `json:"fields,omitempty"`
}
type ChatResourceChangeField ¶ added in v1.4.31
type ChatResourceConditionReason ¶ added in v1.4.31
type ChatResourceEvidence ¶ added in v1.4.31
type ChatResourceEvidence struct {
Terminations []ChatResourceTermination `json:"terminations,omitempty"`
Waiting []ChatResourceWaiting `json:"waiting,omitempty"`
PodReasons []ChatResourceReasonCount `json:"pod_reasons,omitempty"`
Nodes []ChatResourceReasonCount `json:"nodes,omitempty"`
Conditions []ChatResourceConditionReason `json:"conditions,omitempty"`
WarningReasons []ChatResourceReasonCount `json:"warning_reasons,omitempty"`
Warnings int `json:"warning_events"`
Restarts int `json:"restarts,omitempty"`
Partial bool `json:"partial,omitempty"`
From time.Time `json:"from"`
To time.Time `json:"to"`
}
type ChatResourceReasonCount ¶ added in v1.4.31
type ChatResourceRef ¶ added in v1.4.29
type ChatResourceRef struct {
Provider string `json:"provider"`
Cluster string `json:"cluster"`
ResourceID string `json:"resource_id"`
Namespace string `json:"namespace,omitempty"`
Name string `json:"name"`
UID string `json:"uid,omitempty"`
IncludeChanges bool `json:"include_changes,omitempty"`
Break *ChatResourceBreak `json:"break,omitempty"`
}
type ChatResourceTermination ¶ added in v1.4.31
type ChatResourceTermination struct {
Reason string `json:"reason"`
ExitCode int32 `json:"exit_code"`
Signal string `json:"signal,omitempty"`
ExitHint string `json:"exit_hint,omitempty"`
Count int `json:"count"`
Restarts int `json:"restarts,omitempty"`
Init bool `json:"init,omitempty"`
Last time.Time `json:"last"`
}
type ChatResourceWaiting ¶ added in v1.4.31
type ChatTask ¶ added in v1.4.25
type ChatTask struct {
SessionID string `json:"session_id"`
Message string `json:"message"`
Attachment *ChatAttachment `json:"attachment,omitempty"`
}
ChatTask is one user turn in a durable chat session.
type ChatTimeRange ¶ added in v1.4.25
ChatTimeRange is an absolute half-open interval attached to a chat turn. Natural-language date arithmetic is resolved before the model is called.
type ChatTurnAgent ¶ added in v1.4.25
type ChatTurnAgent interface {
Name() string
Kind() AITaskKind
RunChatTurn(ctx context.Context, task ChatTask) (*ChatTurnResult, error)
}
ChatTurnAgent is the narrow execution contract implemented by the ADK chat agent. Its streaming, markdown-native result does not fit AIAgent.Run.
type ChatTurnResult ¶ added in v1.4.25
type ChatTurnResult struct {
Markdown string `json:"markdown"`
Citations []ChatCitation `json:"citations,omitempty"`
ToolCalls []ToolCallTrace `json:"tool_calls,omitempty"`
DurationMs int64 `json:"duration_ms,omitempty"`
Model string `json:"model,omitempty"`
}
ChatTurnResult is the markdown-native result of one chat turn. It is intentionally separate from AICallResult so chat is never coerced into an incident finding.
type ClusterScope ¶ added in v1.4.31
type ClusterScope struct{ IDs []string }
func CallerClusterScope ¶ added in v1.4.31
func CallerClusterScope(ctx context.Context) *ClusterScope
type ContextAuthorizedTool ¶ added in v1.4.27
ContextAuthorizedTool can remove unauthorized sources or the entire tool before a model catalog is built. Implementations must not perform backend IO.
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 DetectionEmissionResult ¶ added in v1.4.25
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 Embedder ¶ added in v1.4.4
type Embedder interface {
// Embed returns one vector per input string, in the same order. An
// empty input yields an empty (non-nil) slice and a nil error.
Embed(ctx context.Context, texts []string) ([][]float32, error)
}
Embedder is the leaf-level contract for turning text into vector embeddings. It is the single embeddings seam every RAG-bearing agent in the suite reuses (the runbook-RAG find_runbook tool is the first consumer). Like AnalyzeTool / ToolResult, it lives in pkg/core so the tools layer can depend on it without importing the concrete Eino wrapper (pkg/agent/ai/eino) that constructs it.
Implementations are an external trust boundary: callers MUST scrub any incident-derived text through the redactor before passing it to Embed, exactly as the analyze tools scrub log lines before the chat-completion call. The runbook corpus that is embedded at ingestion time is operator-authored content (an accepted boundary, documented in the runbook-RAG docs).
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 HealthAssessment ¶ added in v1.4.27
type HealthAssessment struct {
OrgID string `json:"org_id"`
Service string `json:"service"`
RegressionScore *float64 `json:"regression_score"`
Regressing bool `json:"regressing,omitempty"`
Silent *bool `json:"silent"`
Confidence float64 `json:"confidence"`
ReasonCode string `json:"reason_code,omitempty"`
Drivers []AssessmentDriver `json:"drivers,omitempty"`
IncludedFamilies []string `json:"included_families,omitempty"`
AlgorithmVersion string `json:"algorithm_version"`
BaselineReference string `json:"baseline_reference,omitempty"`
AssessedAt time.Time `json:"assessed_at"`
FreshUntil time.Time `json:"fresh_until,omitempty"`
Severity string `json:"severity,omitempty"`
RaiseSeverity bool `json:"raise_severity,omitempty"`
AlertStateKnown bool `json:"alert_state_known,omitempty"`
}
HealthAssessment is an optional source-neutral enrichment. Nil score and silent values mean withheld or unknown; pointers preserve a real zero or false.
type HealthAssessmentInput ¶ added in v1.4.27
type HealthAssessmentInput struct {
OrgID string
Service string
Operation string
Family string
Measure string
SourceRef string
SignalRef string
ExpectedMean float64
ExpectedStd float64
ObservationCount int
MaturityThreshold int
}
HealthAssessmentInput is an ephemeral expected range paired with evidence from the same provider read. Collectors pass it to assessors but never persist it.
type HealthBudget ¶ added in v1.4.27
type HealthBudget struct {
Requests int
RequestsPerSource int
Rows int
ResponseBytes int64
CumulativeBytes int64
Concurrency int
}
HealthBudget is the server-clamped remaining allowance passed to a provider.
type HealthCapability ¶ added in v1.4.27
type HealthCapability struct {
Family string `json:"family"`
Measures map[string]MeasureAvailability `json:"measures"`
}
HealthCapability reports per-measure availability for one signal family.
type HealthCollectRequest ¶ added in v1.4.27
type HealthCollectRequest struct {
OrgID string
SourceIDs []string
ServiceIDs []string
WindowStart time.Time
WindowEnd time.Time
Deadline time.Time
Budget HealthBudget
}
HealthCollectRequest carries trusted scope and bounded collection inputs.
type HealthCollection ¶ added in v1.4.27
type HealthCollection struct {
Evidence []SignalEvidence
AssessmentInputs []HealthAssessmentInput
Usage HealthUsage
Partial bool
}
HealthCollection is one provider result plus the work it consumed.
type HealthProvider ¶ added in v1.4.27
type HealthProvider interface {
Capabilities(context.Context, string) []HealthCapability
Collect(context.Context, HealthCollectRequest) (HealthCollection, error)
}
HealthProvider discovers capabilities and performs one bounded read. OSS registers no metric or trace provider; out-of-tree providers implement this seam.
type HealthState ¶ added in v1.4.27
type HealthState string
HealthState is the canonical availability state for a health measure.
const ( HealthReady HealthState = "ready" HealthPartial HealthState = "partial" HealthNotConfigured HealthState = "not_configured" HealthCollecting HealthState = "collecting" HealthNoData HealthState = "no_data" HealthUnsupported HealthState = "unsupported" HealthError HealthState = "error" HealthStale HealthState = "stale" HealthRestricted HealthState = "restricted" )
type HealthUsage ¶ added in v1.4.27
type HealthUsage struct {
Sources int
Requests int
Rows int
ResponseBytes int64
LargestResponseBytes int64
}
HealthUsage reports the provider work charged against the shared tick budget.
type LogHealthObservation ¶ added in v1.4.27
type LogHealthObservation struct {
OrgID string
SourceID string
Service string
PatternID string
ObservedAt time.Time
Frequency int
StrongestSeverity string
NewPattern bool
InGrace bool
ExpectedRate float64
ExpectedSpread float64
LifecycleClass string
LifecycleClassified bool
}
LogHealthObservation is the safe post-grouping projection accepted by Service Health. It deliberately has no raw signal, message, sample, credential, provider-field, or cursor field.
type LogHealthRecorder ¶ added in v1.4.27
type LogHealthRecorder interface {
RecordLogHealth(context.Context, LogHealthObservation) error
RecordSourceHealth(context.Context, SourceHealthObservation) error
}
LogHealthRecorder receives the worker's already-computed fold projection. Training passes LifecycleClassified=false rather than inventing a verdict.
type MeasureAvailability ¶ added in v1.4.27
type MeasureAvailability struct {
State HealthState `json:"state"`
ReasonCode string `json:"reason_code,omitempty"`
ActionID string `json:"action_id,omitempty"`
}
MeasureAvailability separates operational state from a nullable value.
type NotableIncident ¶ added in v1.4.8
type NotableIncident struct {
ShortID string
Title string
Service string
Severity string
CreatedAt time.Time
}
NotableIncident is one row in the "recent high-severity" notable list. Every string field is ALREADY redacted by the assembler — the renderer draws it verbatim and never reaches back into raw content.
type Observation ¶ added in v1.4.4
type Observation struct {
Key string // stable per-type fingerprint
Service string // attribution (feeds grace + routing)
Signal string // human label: template | "latency_p99" | "GET /checkout error_rate"
Timestamp time.Time // observation time (seasonality needs it)
Value float64 // the scalar the learner folds + the detector scores
Frequency int // tick count (logs) / sample count (metrics/traces)
Samples []Signal // representative raw signals for the AI-analyze handoff
// StrongestSeverity is computed across the full grouped observation before
// Samples is bounded. It is evidence metadata, never part of identity.
StrongestSeverity string
// IsNew reports whether Group saw this Key for the first time during this
// tick (a freshly discovered template / metric / operation). It is used
// only for discovery logging and never affects classification. (Additive
// to the design-doc struct.)
IsNew bool
}
Observation is one keyed unit a typed pipeline learns/scores for a tick.
logs → one drain-template bucket (Value = tick frequency) metrics → one (service, golden-signal) window (Value = latest sample / p99 / error-ratio) traces → one (service, operation) window (Value = window p99 latency or error-ratio)
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.UniversalClient, 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 Permission ¶ added in v1.4.25
type Permission string
Permission is an application capability evaluated for the current caller.
const ( PermissionInfrastructureView Permission = "infrastructure:view" PermissionServiceHealthSettingsWrite Permission = "service-health:settings:write" PermissionAgentApprove Permission = "agent:approve" )
type QueueListener ¶
type Readiness ¶ added in v1.4.7
type Readiness struct {
// Ready reports the signal has reached its settled/known state.
Ready bool `json:"ready"`
// Seen is the evidence folded so far (log sightings / folded samples).
Seen int `json:"seen"`
// Needed is the evidence required to reach Ready. 0 is the INDETERMINATE
// sentinel: no count gate applies for this signal kind. The UI shows
// "Manual only", never "X of 0". (Log patterns always ship a positive
// Needed — a non-positive auto_promote_after is normalized to the default.)
Needed int `json:"needed"`
// RatePerMin is the observed arrival rate of NEW evidence for this key,
// in evidence/minute, used to derive the ETA. 0 is the UNKNOWN/STALLED
// sentinel: no honest rate yet, or the signal stopped flowing — the UI
// shows no ETA (never ∞).
RatePerMin float64 `json:"rate_per_min"`
}
Readiness is how close a signal is to its settled/known state — the point at which the agent's judgment of it is final rather than provisional. It is a generic, type-agnostic value produced at each read boundary (the log catalog reader in OSS, the enterprise metric/trace baseline reader). It is a plain value type with no behaviour: presentation (remaining evidence, ETA, progress bar) is DERIVED from these facts by the UI — the server ships facts, not formatted strings.
Derivations the UI does: remaining = max(0, Needed-Seen) (when Needed>0); etaMinutes = remaining / RatePerMin (when RatePerMin>0, Needed>0, !Ready); progress = Seen/Needed (when Needed>0).
type ReportImage ¶ added in v1.4.8
type ReportImage struct {
Data []byte // encoded image bytes (PNG)
MIME string // "image/png"
Filename string // e.g. "incidents-today-20260704.png"
Width int
Height int
}
ReportImage is a rendered report: the encoded image bytes plus enough metadata for a channel to upload it or an HTTP handler to serve it.
type ReportModel ¶ added in v1.4.8
type ReportModel struct {
// Window identity. Timestamps are expressed in TZLabel's location (UTC by
// default), so a renderer/caption can print them verbatim.
Window string // "today" | "24h" | "7d"
WindowStart time.Time // inclusive
WindowEnd time.Time // exclusive (== GeneratedAt for today/24h)
GeneratedAt time.Time
// TZLabel is the IANA name of the timezone WindowStart/WindowEnd/
// GeneratedAt are expressed in (e.g. "UTC" or "Asia/Ho_Chi_Minh"). The
// renderer and channel caption print it beside the times so a reader knows
// the wall-clock zone. Empty is treated as "UTC".
TZLabel string
// Title is the header/caption heading. It is operator-configurable via
// the report settings; an empty value is treated as "Incident report" so a
// directly-constructed model still renders a title.
Title string
// Headline stats.
Total int // incidents in the window
ByOrigin map[string]int // ai_detect / webhook counts (primary category axis)
Resolved int
Open int
CriticalHigh int // count of critical + high severity incidents
// Chart series (hand-drawn, no chart lib).
BySeverity []Bucket // ordered critical..unknown (category breakdown)
Trend []Bucket // hourly (today/24h) or daily (7d) counts
TrendUnit string // "hour" | "day" — labels the trend axis
// Notable lists (bounded, redacted labels).
TopServices []Bucket // top-N services by count
Notable []NotableIncident // recent high-severity incidents
// IncludeCharts mirrors the runtime include_chart toggle: when false the
// renderer omits the trend + severity charts (headline + lists remain).
IncludeCharts bool
// enterprise white-label renderer overrides it behind the same seam.
Footer string
}
ReportModel is the channel-agnostic, ALREADY-REDACTED aggregate summary of every incident in a time window. It is assembled by querying the incident history over the window (both ai_detect and webhook) and handed to a ReportRenderer. Every string field has already passed through a Scrubber, so a renderer draws it verbatim and must never reach back into raw incident content. No AckURL, token, or config value is ever placed here.
type ReportRenderer ¶ added in v1.4.8
type ReportRenderer interface {
Render(ctx context.Context, m ReportModel) (*ReportImage, error)
}
ReportRenderer turns a ReportModel into a ReportImage. The OSS build wires the default pure-Go PNG card renderer at boot via services.SetReportRenderer; an enterprise build may install a branded / high-fidelity renderer behind the SAME seam without the API, channel delivery, or UI changing. Mirrors the SetAnalyzeAgent seam.
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 Scrubber ¶ added in v1.4.8
Scrubber is the minimal DLP contract the report path depends on: turn a possibly-sensitive string into a safe one. It is satisfied by agent.Redactor.Scrub, so the report assembler can scrub every field WITHOUT the services/report layers importing the heavier agent package. Every text value drawn onto a shared report image is run through a Scrubber first — defence-in-depth, because webhook incident Content is attacker-influenced input.
type ServiceTopology ¶ added in v1.4.27
type ServiceTopology struct {
Availability HealthState `json:"availability"`
Extensions *TopologyExtension `json:"extensions,omitempty"`
Provenance []string `json:"provenance"`
Nodes []ServiceTopologyNode `json:"nodes"`
Edges []ServiceTopologyEdge `json:"edges"`
OmittedNodes int `json:"omitted_nodes,omitempty"`
OmittedEdges int `json:"omitted_edges,omitempty"`
}
ServiceTopology is a bounded service-dependency graph with honest source metadata.
type ServiceTopologyEdge ¶ added in v1.4.27
type ServiceTopologyEdge struct {
Service string `json:"service"`
DependsOn string `json:"depends_on"`
Source string `json:"source"`
}
ServiceTopologyEdge records a directed dependency from service to upstream.
type ServiceTopologyNode ¶ added in v1.4.27
type ServiceTopologyNode struct {
Service string `json:"service"`
}
ServiceTopologyNode identifies one service without provider payloads.
type ServiceTopologyProvider ¶ added in v1.4.27
type ServiceTopologyProvider interface {
ServiceTopology(context.Context, ServiceTopologyRequest) (ServiceTopology, error)
}
ServiceTopologyProvider returns authorized additional topology only. It must not acquire raw payloads or infer service edges from operation names. A zero budget is an availability probe: providers must not perform unbounded reads and must report partial availability or omissions when extension data exists.
type ServiceTopologyRequest ¶ added in v1.4.27
ServiceTopologyRequest carries trusted scope and hard output caps. Providers must independently enforce entitlement and organization access.
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 SignalDetector ¶ added in v1.4.4
type SignalDetector interface {
// Kind identifies the signal type and must match its paired Learner.
Kind() string
// Classify scores one observation against the learned expectation
// (mean, std, confident) captured by SignalLearner.Expected.
Classify(obs Observation, mean, std float64, confident bool) TypedVerdict
}
SignalDetector is the pure SCORING POLICY: a function of (observation, learned expectation) → verdict. The per-type knob (z threshold, spike multiplier, sustained-tick debounce) lives here, not in the worker. The detector scores against the PASSED expectation (the pre-fold snapshot), never by re-reading the learner, so the result is independent of whether the worker has already folded the tick.
type SignalEvidence ¶ added in v1.4.27
type SignalEvidence struct {
OrgID string `json:"org_id"`
Service string `json:"service"`
Operation string `json:"operation,omitempty"`
Family string `json:"family"`
Measure string `json:"measure"`
Value *float64 `json:"value"`
Unit string `json:"unit,omitempty"`
Numerator *float64 `json:"numerator,omitempty"`
Denominator *float64 `json:"denominator,omitempty"`
Availability MeasureAvailability `json:"availability"`
SourceRef string `json:"source_ref"`
SignalRef string `json:"signal_ref,omitempty"`
ObservedAt time.Time `json:"observed_at"`
WindowStart time.Time `json:"window_start"`
WindowEnd time.Time `json:"window_end"`
FreshUntil time.Time `json:"fresh_until,omitempty"`
Provenance string `json:"provenance,omitempty"`
}
SignalEvidence is a source-neutral nullable measure with explicit availability.
type SignalLearner ¶ added in v1.4.4
type SignalLearner interface {
// Kind identifies the signal type: "logs" | "metrics" | "traces".
Kind() string
// Group keys a tick's batch into observations WITHOUT mutating the model.
Group(ctx context.Context, batch []Signal) ([]Observation, error)
// Expected returns the learned mean/spread for a key at ts, and whether
// the model is confident enough to score (the per-key training gate).
// It must be a pure read of pre-fold state: the worker snapshots it
// BEFORE Learn folds the tick, so a deviation is judged against the
// pre-tick baseline.
Expected(ctx context.Context, key string, ts time.Time) (mean, std float64, confident bool)
// Learn folds observations into the model. Called every tick in EVERY
// mode (training/shadow/detect) so the baseline keeps adapting to drift.
Learn(ctx context.Context, obs []Observation) error
}
SignalLearner owns the per-type LEARNED MODEL: keying + folding + the "what is normal" estimate. Implementations persist their derived state via the model-state seam (opaque bytes, keyed by OrgID). One implementation per signal type (logs in OSS; metrics/traces in Versus Enterprise).
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).
//
// Tailing invariant: the returned cursor MUST NOT exceed the wall-clock
// time at pull, and a cursor-driven source MUST NOT scan past `now`.
// Document timestamps are untrusted producer data; a single future-dated
// record would otherwise push the cursor ahead of real time and make every
// following `>= cursor` query match nothing until that time arrives — the
// source stops emitting until its cursor is wiped. Sources bound their scan
// at `now` (Loki `end`, Graylog `to`, Splunk `latest`, Elasticsearch `lte`,
// CloudWatch `EndTime`) and clamp the returned cursor via
// signalsources.ClampCursor.
Pull(ctx context.Context, since time.Time) ([]Signal, time.Time, error)
}
SignalSource is a puller for one external observability backend (Elasticsearch, Loki, CloudWatch, ...).
type SourceCommitter ¶ added in v1.4.23
SourceCommitter is the OPTIONAL capability a SignalSource implements when a Pull leaves behind DELIVERY STATE — its own record of which rows it has already handed over — that must not become durable before the signals it describes are durable.
A tailing source dedupes the rows its inclusive re-read window returns twice using a set of the ids it already delivered. Persisting that set at the end of Pull is one write too early: the worker has not folded those rows into the catalog yet, and the catalog reaches storage only on its own flush interval. A process that dies in between comes back with the ids recorded as delivered and the rows themselves absent — silent, permanent loss.
So Pull only STAGES the delivery state in memory (enough to suppress the next tick's re-read inside the same process) and the worker calls Commit once the rows are durable: after a successful catalog flush, and again after the shutdown flush. The failure direction is deliberate and asymmetric — a crash between the flush and Commit re-delivers rows (bounded duplicates), a crash before the flush leaves the ids uncommitted so the next scan re-reads them (no loss). Duplicates are recoverable; dropped rows are not.
The ctx passed to Commit is always live, including on the shutdown path where the worker's own context has already been canceled. Sources with no staged state do not implement this and are skipped, so they behave exactly as they did before the seam existed. Implementations must be safe to call concurrently with Pull.
type SourceHealthObservation ¶ added in v1.4.27
type SourceHealthObservation struct {
OrgID string
SourceID string
AttemptedAt time.Time
Succeeded bool
ErrorClass string
}
SourceHealthObservation records one worker pull outcome without its raw backend error or provider-specific delivery state.
type SourceRewinder ¶ added in v1.4.7
SourceRewinder is the OPTIONAL capability a SignalSource implements when it keeps its OWN internal read position — a byte offset, page token, or similar — that is INDEPENDENT of the poll cursor the worker passes to Pull as `since`. The file source is the canonical example: it tails a log file by byte offset (persisted in a sidecar) and ignores `since` entirely.
Clearing the learned catalog rewinds the worker's poll cursor, which makes cursor-driven sources (Elasticsearch, Loki, CloudWatch, …) re-read their lookback window on the next tick. A source that tracks its own position must additionally rewind THAT position here — otherwise the clear leaves it pinned past the already-consumed data and it never re-emits, so the SAME running worker stops learning until the process is recreated (which reconstructs the source from scratch). Rewind reconciles the two cursors of truth so a clear behaves like a fresh process start in-place.
Sources whose position is driven purely by `since` do not implement it; the worker skips them. Implementations must be safe to call concurrently with Pull and must leave the source in the state a freshly-constructed instance would have.
type SourceRoutedTool ¶ added in v1.4.27
SourceRoutedTool identifies a provider tool whose existing capability can be combined with another provider by dispatching an explicit source argument.
type TextSender ¶ added in v1.4.8
TextSender is the OPTIONAL text-fallback sibling of AttachmentSender. A channel that cannot upload a binary but CAN post text (Teams, Viber, Lark webhooks) implements it so the report delivery path can still deliver the already-redacted caption + a short note to that channel. Like AttachmentSender it is generic and detected via type assertion; a channel that implements neither simply receives no report and the caller records a graceful fallback outcome.
type Tool ¶ added in v1.4.25
type Tool 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)
}
Tool is the contract every read-only AI tool satisfies. Tools are registered with an 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 ToolCallTrace ¶ added in v1.4.3
type ToolCallTrace struct {
CallID string `json:"call_id,omitempty"`
Name string
Args string
Output string
DurationMs int64
Error string
}
ToolCallTrace is one model-issued tool round-trip captured for audit.
type ToolDisplayer ¶ added in v1.4.25
type ToolDisplayer interface {
DisplayName() string
}
ToolDisplayer optionally gives a tool a human-readable activity name.
type ToolError ¶ added in v1.4.25
type ToolError struct {
Code ToolErrorCode
Message string
Cause error
}
ToolError carries a model-safe message while retaining the underlying cause for trusted server-side handling. Cause is never part of the model envelope.
type ToolErrorCode ¶ added in v1.4.25
type ToolErrorCode string
ToolErrorCode classifies a tool failure without exposing its underlying cause.
const ( ToolErrorInvalidArguments ToolErrorCode = "invalid_arguments" ToolErrorTimeout ToolErrorCode = "timeout" ToolErrorCancelled ToolErrorCode = "cancelled" ToolErrorBackend ToolErrorCode = "backend_error" ToolErrorInternal ToolErrorCode = "internal_error" )
func ClassifyToolError ¶ added in v1.4.25
func ClassifyToolError(err error) (ToolErrorCode, string)
ClassifyToolError returns only model-safe fields. Unknown errors are treated as backend failures and their text is deliberately discarded.
type ToolResult ¶ added in v1.4.3
type ToolResult struct {
Tool string `json:"tool"`
Found bool `json:"found"`
Available *bool `json:"-"`
Reason string `json:"reason,omitempty"`
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 (get_pattern, get_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).
func UnavailableToolResult ¶ added in v1.4.25
func UnavailableToolResult(tool, reason string) *ToolResult
UnavailableToolResult returns an expected missing-capability result. UnavailableToolResult reports missing capability as a successful result so the model can adapt without treating expected configuration as a tool error.
func (ToolResult) IsAvailable ¶ added in v1.4.25
func (result ToolResult) IsAvailable() bool
IsAvailable reports availability, defaulting existing results to true.
func (ToolResult) MarshalJSON ¶ added in v1.4.25
func (result ToolResult) MarshalJSON() ([]byte, error)
MarshalJSON keeps availability explicit on the wire while preserving old constructors.
func (*ToolResult) UnmarshalJSON ¶ added in v1.4.25
func (result *ToolResult) UnmarshalJSON(data []byte) error
UnmarshalJSON preserves explicit availability when reading stored results.
type TopologyExtension ¶ added in v1.4.27
type TopologyExtension struct {
Availability HealthState `json:"availability"`
}
TopologyExtension reports optional extension coverage without describing the retained static graph as restricted when an extension is unavailable.
type TypedVerdict ¶ added in v1.4.4
type TypedVerdict struct {
Class AgentVerdict // reuse the enum: VerdictKnownPattern | VerdictUnknown | VerdictSpike
Confident bool // false ⇒ this key is still TRAINING ⇒ lifecycle suppresses, any mode
Score float64 // z-score (metrics/traces) or spike ratio (logs)
Baseline float64 // learned expected value (for the finding text)
Reason string // "p99 4.2σ above the learned Tue-14:00 baseline (≈ 180ms)"
}
TypedVerdict is the per-type classification of one observation.