heimdall

package
v1.2.2 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 23 Imported by: 0

Documentation

Overview

Package heimdall provides Heimdall - the cognitive guardian for NornicDB.

Package heimdall provides the Heimdall cognitive guardian for NornicDB. This file provides the CGO-enabled generator using localllm.

Package heimdall - Ollama-backed Generator for chat completions. When Heimdall provider is "ollama", NewManager uses this implementation.

Package heimdall - OpenAI-backed Generator for chat completions. When Heimdall provider is "openai", NewManager uses this implementation.

Package heimdall provides comprehensive metrics collection for the cognitive guardian.

Package heimdall provides Heimdall - the cognitive guardian for NornicDB.

Heimdall is named after the all-seeing Norse god who guards Bifröst. Like its namesake, Heimdall watches over NornicDB's cognitive subsystems, providing SLM (Small Language Model) management and plugin architecture.

Heimdall Plugins are a DISTINCT plugin type from regular NornicDB plugins. They specifically enable cognitive database features that the SLM manages.

Plugin Type: HeimdallPlugin

Unlike regular plugins (which provide Cypher functions), Heimdall plugins provide actions that the SLM can invoke based on user chat requests.

How it works:

  1. User sends chat message: "Check for graph anomalies"
  2. SLM interprets intent and maps to registered action: "heimdall_anomaly_detect"
  3. Action handler is invoked with context
  4. Results returned to user via chat

Plugin Loading:

Heimdall plugins are loaded from NORNICDB_HEIMDALL_PLUGINS_DIR (separate from regular plugins). Each .so plugin must export a "Plugin" variable of type HeimdallPlugin.

Built-in Heimdall Plugins:

Core Heimdall plugins ship with NornicDB:

  • watcher: SLM management (heimdall_watcher_*) - the core guardian
  • anomaly: Graph anomaly detection (heimdall_anomaly_*)
  • health: Runtime health diagnosis (heimdall_health_*)
  • curator: Memory curation (heimdall_curator_*)
  • optimizer: Query optimization (heimdall_optimizer_*)

Custom Heimdall Plugins:

Example implementing HeimdallPlugin interface:

package main

import "github.com/orneryd/nornicdb/pkg/heimdall"

// MySubsystem implements heimdall.HeimdallPlugin
type MySubsystem struct{}

func (p *MySubsystem) Name() string    { return "mysubsystem" }
func (p *MySubsystem) Version() string { return "1.0.0" }
func (p *MySubsystem) Type() string    { return "heimdall" } // MUST return "heimdall"

func (p *MySubsystem) Actions() map[string]heimdall.ActionFunc {
    return map[string]heimdall.ActionFunc{
        "analyze": {
            Handler:     p.Analyze,
            Description: "Analyze custom metrics",
            Category:    "analysis",
        },
    }
}

func (p *MySubsystem) Analyze(ctx heimdall.ActionContext) (*heimdall.ActionResult, error) {
    // Your implementation
    return &heimdall.ActionResult{Success: true, Message: "Done"}, nil
}

// Export as HeimdallPlugin type
var Plugin heimdall.HeimdallPlugin = &MySubsystem{}

Package heimdall provides RBAC context helpers for Bifrost request context. The server attaches RBAC via auth.WithRequest*; heimdall reads via these helpers which delegate to auth.Request*FromContext so the same context works for Bifrost and GraphQL.

Package heimdall provides Heimdall - the cognitive guardian for NornicDB.

Heimdall enables NornicDB to run reasoning SLMs alongside embedding models for cognitive database capabilities including anomaly detection, runtime diagnosis, and memory curation.

The Heimdall subsystem uses standard protocols:

  • WebSocket (WSS) for real-time streaming chat
  • Server-Sent Events (SSE) as fallback
  • JSON message format (OpenAI-compatible)
  • JWT authentication from existing auth system

Index

Constants

View Source
const (
	// DefaultMaxContextTokens is the default context window (8K for memory efficiency)
	DefaultMaxContextTokens = 8192

	// DefaultMaxSystemPromptTokens is the default system prompt budget
	DefaultMaxSystemPromptTokens = 6000

	// DefaultMaxUserMessageTokens is the default user message budget
	DefaultMaxUserMessageTokens = 2000

	// TokensPerChar is a rough estimate (~4 chars per token for English)
	TokensPerChar = 0.25
)

Token budget constants for Heimdall - DEFAULT values (can be overridden via config) These are used when config values are 0 or not provided. Configure via environment variables:

  • NORNICDB_HEIMDALL_MAX_CONTEXT_TOKENS (default: 8192)
  • NORNICDB_HEIMDALL_MAX_SYSTEM_TOKENS (default: 6000)
  • NORNICDB_HEIMDALL_MAX_USER_TOKENS (default: 2000)
View Source
const AgenticSystemPromptTools = `` /* 584-byte string literal not displayed */

AgenticSystemPromptTools is the short system prompt when using native tools (OpenAI/Ollama). The model receives tools via the API; no need to list actions in the prompt.

View Source
const CypherPrimer = `` /* 1948-byte string literal not displayed */

CypherPrimer is a comprehensive Cypher query reference for Heimdall.

View Source
const MaxAgenticRounds = 10

MaxAgenticRounds is the maximum number of tool-call rounds in the agentic loop. Prevents runaway when the model keeps requesting tools.

View Source
const PluginTypeHeimdall = "heimdall"

PluginType identifies the type of plugin.

Variables

View Source
var DefaultActionInputSchema = []byte(`{"type":"object","properties":{},"additionalProperties":true}`)

DefaultActionInputSchema is the MCP-compatible JSON Schema when an action does not declare parameters (type "object" with no required properties).

Functions

func ActionCatalog

func ActionCatalog() map[string][]ActionFunc

ActionCatalog returns all actions grouped by category for display.

func ActionPrompt

func ActionPrompt() string

ActionPrompt generates a list of available actions.

func BuildPrompt

func BuildPrompt(messages []ChatMessage) string

BuildPrompt converts chat messages to a prompt string. Uses ChatML format for instruction-tuned models.

func CallPostExecuteHooks

func CallPostExecuteHooks(ctx *PostExecuteContext)

CallPostExecuteHooks calls PostExecute on all plugins that implement PostExecuteHook. Plugins that don't implement the hook are silently skipped. This is fire-and-forget - runs asynchronously using a bounded worker pool.

func CallPrePromptHooks

func CallPrePromptHooks(ctx *PromptContext)

CallPrePromptHooks calls PrePrompt on all plugins that implement PrePromptHook. Plugins that don't implement the hook are silently skipped. Returns the first cancellation encountered, or nil if no cancellations.

func CallSynthesisHooks

func CallSynthesisHooks(ctx *SynthesisContext) string

CallSynthesisHooks calls Synthesize on all plugins that implement SynthesisHook. The first plugin to return a non-empty response wins. If no plugin provides a response, returns empty string (caller should use default synthesis). This is synchronous with a timeout to ensure responsive UX.

func DatabaseAccessModeFromContext

func DatabaseAccessModeFromContext(ctx context.Context) auth.DatabaseAccessMode

DatabaseAccessModeFromContext returns the principal's DatabaseAccessMode from context, or nil.

func EmitDatabaseEvent

func EmitDatabaseEvent(event *DatabaseEvent)

EmitDatabaseEvent sends a database event to all registered plugins. This is non-blocking - events are queued for async delivery. If the queue is full, the event is dropped (with a warning).

func EmitNodeEvent

func EmitNodeEvent(eventType DatabaseEventType, nodeID string, labels []string, props map[string]interface{})

EmitNodeEvent is a convenience function for emitting node-related events.

func EmitQueryEvent

func EmitQueryEvent(eventType DatabaseEventType, query string, params map[string]interface{}, duration time.Duration, rowsAffected int64, err error)

EmitQueryEvent is a convenience function for emitting query-related events.

func EmitRelationshipEvent

func EmitRelationshipEvent(eventType DatabaseEventType, relID, relType, sourceID, targetID string, props map[string]interface{})

EmitRelationshipEvent is a convenience function for emitting relationship-related events.

func EstimateTokens

func EstimateTokens(text string) int

EstimateTokens provides a rough token count estimate for a string. Uses ~4 chars per token which is typical for English text. For exact counts, use the actual tokenizer.

func EstimateToolRoundMessagesTokens

func EstimateToolRoundMessagesTokens(messages []ToolRoundMessage) int

EstimateToolRoundMessagesTokens returns a rough token count for a slice of tool-round messages. Used to stay within model context limits (e.g. OpenAI 128K) before sending.

func FormatActionResultForModel

func FormatActionResultForModel(result *ActionResult) string

FormatActionResultForModel formats an action result for the LLM to read (any provider). Used in the agentic loop so the model can infer and format the final response.

func FormatInMemoryToolResult

func FormatInMemoryToolResult(raw interface{}, err error) string

FormatInMemoryToolResult formats a raw tool result or error for the LLM (tool message content).

func HeimdallPluginsInitialized

func HeimdallPluginsInitialized() bool

HeimdallPluginsInitialized returns true if SLM plugins have been loaded.

func ListHeimdallActions

func ListHeimdallActions() []string

ListHeimdallActions returns all registered SLM action names.

func LoadHeimdallPluginsFromDir

func LoadHeimdallPluginsFromDir(dir string, ctx SubsystemContext) error

LoadHeimdallPluginsFromDir scans a directory for .so files and loads them. Called at startup if NORNICDB_HEIMDALL_PLUGINS_DIR is set.

func MaxContextTokens

func MaxContextTokens() int

MaxContextTokens returns the configured max context tokens.

func MaxSystemPromptTokens

func MaxSystemPromptTokens() int

MaxSystemPromptTokens returns the configured max system prompt tokens.

func MaxUserMessageTokens

func MaxUserMessageTokens() int

MaxUserMessageTokens returns the configured max user message tokens.

func PrincipalRolesFromContext

func PrincipalRolesFromContext(ctx context.Context) []string

PrincipalRolesFromContext returns the principal's roles from the request context, or nil.

func RegisterBuiltinAction

func RegisterBuiltinAction(action ActionFunc)

RegisterBuiltinAction registers a built-in action (not from .so plugin). Used to register core actions without requiring external plugins.

func RegisterHeimdallProvider

func RegisterHeimdallProvider(name string, factory func(Config) (Generator, error))

RegisterHeimdallProvider registers a remote provider (openai, ollama). Called from generator_* init().

func ResetSubsystemManagerForTests

func ResetSubsystemManagerForTests()

ResetSubsystemManagerForTests clears the global subsystem manager singleton. It is intended for test isolation when separate test cases need a fresh registration state for Heimdall plugins.

func ResolvedAccessResolverFromContext

func ResolvedAccessResolverFromContext(ctx context.Context) func(string) auth.ResolvedAccess

ResolvedAccessResolverFromContext returns the ResolvedAccess resolver from context, or nil.

func SetTokenBudget

func SetTokenBudget(flags FeatureFlagsSource)

SetTokenBudget configures the token budget from feature flags. Call this during initialization to apply config values.

func StartEventDispatcher

func StartEventDispatcher()

StartEventDispatcher starts the background event dispatcher. This should be called when Heimdall is initialized.

func StopEventDispatcher

func StopEventDispatcher()

StopEventDispatcher stops the background event dispatcher.

Types

type ActionContext

type ActionContext struct {
	context.Context

	// UserMessage is what the user said to trigger this action
	UserMessage string

	// Params extracted from user message by SLM
	Params map[string]interface{}

	// Database routes Cypher/search operations across logical databases.
	Database DatabaseRouter

	// Metrics provides runtime metrics
	Metrics MetricsReader

	// Bifrost provides communication bridge to the user
	// Use this to send progress updates, request confirmation, etc.
	Bifrost BifrostBridge

	// PrincipalRoles are the authenticated principal's role names (from request context).
	// Plugins can use this with DatabaseAccessMode and ResolvedAccess to enforce per-DB access.
	PrincipalRoles []string

	// DatabaseAccessMode is the principal's per-database see/access mode (from request context).
	// Use CanAccessDatabase(dbName) before running Cypher against a database.
	DatabaseAccessMode auth.DatabaseAccessMode

	// ResolvedAccess returns per-database read/write for the principal (from request context).
	// Use for mutation checks: ResolvedAccess(dbName).Write before CREATE/DELETE/SET/etc.
	ResolvedAccess func(dbName string) auth.ResolvedAccess
}

ActionContext provides context for action execution. Passed to handlers when actions are invoked.

type ActionFunc

type ActionFunc struct {
	Name        string                                         // Full name: heimdall.{plugin}.{action} (MCP tool "name")
	Handler     func(ctx ActionContext) (*ActionResult, error) // The action handler
	Description string                                         // Human-readable description (MCP "description")
	Category    string                                         // Grouping: monitoring, optimization, curation
	// InputSchema is optional JSON Schema for parameters (MCP "inputSchema").
	// When nil or empty, ActionsAsMCPTools() uses DefaultActionInputSchema.
	InputSchema json.RawMessage
}

ActionFunc represents an action function provided by an SLM plugin. Aligned with MCP (Model Context Protocol) tool format: name, description, inputSchema. Invocation uses the same shape as MCP tools/call: action name + params (arguments).

func GetHeimdallAction

func GetHeimdallAction(name string) (ActionFunc, bool)

GetHeimdallAction returns an action by full name (e.g., "heimdall_anomaly_detect").

type ActionInvoker

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

ActionInvoker handles action invocation from SLM responses.

func NewActionInvoker

func NewActionInvoker(db DatabaseRouter, metrics MetricsReader) *ActionInvoker

NewActionInvoker creates an action invoker with database/metrics access.

func (*ActionInvoker) Invoke

func (i *ActionInvoker) Invoke(ctx context.Context, parsed ParsedAction, userMessage string) (*ActionResult, error)

Invoke executes a parsed action.

type ActionOpcode

type ActionOpcode int

ActionOpcode represents bounded actions the SLM can recommend. All SLM outputs map to these predefined actions for safety.

const (
	ActionNone ActionOpcode = iota
	ActionLogInfo
	ActionLogWarning
	ActionLogError
	ActionThrottleQuery
	ActionSuggestIndex
	ActionMergeNodes
	ActionRestartWorkerPool
	ActionClearQueue
	ActionTriggerGC
	ActionReduceConcurrency
)

type ActionResponse

type ActionResponse struct {
	Action     ActionOpcode   `json:"action"`
	Confidence float64        `json:"confidence"`
	Reasoning  string         `json:"reasoning"`
	Params     map[string]any `json:"params,omitempty"`
}

ActionResponse is the structured output format for SLM recommendations.

type ActionResult

type ActionResult struct {
	Success bool                   `json:"success"`
	Message string                 `json:"message"`
	Data    map[string]interface{} `json:"data,omitempty"`
}

ActionResult is the outcome of action execution.

func ExecuteAction

func ExecuteAction(name string, ctx ActionContext) (*ActionResult, error)

ExecuteAction executes an action by name with the given context.

type AsyncEngineStats

type AsyncEngineStats interface {
	Stats() (pendingWrites, totalFlushes int64)
}

AsyncEngineStats is the interface for async storage metrics.

type Bifrost

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

Bifrost implements BifrostBridge for real-time communication with clients. Named after the rainbow bridge that connects Asgard to other realms. Bifrost is the communication layer between Heimdall and connected UI clients.

func NewBifrost

func NewBifrost(cfg Config) *Bifrost

NewBifrost creates a new Bifrost bridge. Returns nil if Bifrost is not enabled in config.

func (*Bifrost) Broadcast

func (b *Bifrost) Broadcast(msg string) error

Broadcast sends a message to all connected clients. Useful for system-wide announcements.

func (*Bifrost) ConnectionCount

func (b *Bifrost) ConnectionCount() int

ConnectionCount returns the number of active Bifrost connections.

func (*Bifrost) IsConnected

func (b *Bifrost) IsConnected() bool

IsConnected returns true if there are active Bifrost connections.

func (*Bifrost) RegisterClient

func (b *Bifrost) RegisterClient(id string, w http.ResponseWriter, f http.Flusher)

RegisterClient adds a new connected client.

func (*Bifrost) RequestConfirmation

func (b *Bifrost) RequestConfirmation(action string) (bool, error)

RequestConfirmation asks the user to confirm an action. Returns true if user confirms, false if they decline or timeout. Note: This is a simplified implementation - real implementation would need WebSocket for bidirectional communication.

func (*Bifrost) SendMessage

func (b *Bifrost) SendMessage(msg string) error

SendMessage sends a message to all connected Bifrost clients. The message appears as a system message in the chat.

func (*Bifrost) SendNotification

func (b *Bifrost) SendNotification(notifType, title, message string) error

SendNotification sends a notification with a specific type. Types: "info", "warning", "error", "success"

func (*Bifrost) Stats

func (b *Bifrost) Stats() map[string]interface{}

Stats returns current Bifrost statistics.

func (*Bifrost) UnregisterClient

func (b *Bifrost) UnregisterClient(id string)

UnregisterClient removes a disconnected client.

type BifrostBridge

type BifrostBridge interface {
	// SendMessage sends a message to connected Bifrost clients.
	// The message appears as a system message in the chat.
	SendMessage(msg string) error

	// SendNotification sends a notification with a specific type.
	// Types: "info", "warning", "error", "success"
	SendNotification(notifType, title, message string) error

	// Broadcast sends a message to all connected clients.
	// Useful for system-wide announcements.
	Broadcast(msg string) error

	// RequestConfirmation asks the user to confirm an action.
	// Returns true if user confirms, false if they decline or timeout.
	// The action parameter describes what needs confirmation.
	RequestConfirmation(action string) (bool, error)

	// IsConnected returns true if there are active Bifrost connections.
	IsConnected() bool

	// ConnectionCount returns the number of active Bifrost connections.
	ConnectionCount() int
}

BifrostBridge is the interface for plugins to communicate via Bifrost. Named after the rainbow bridge connecting Asgard to other realms.

type BifrostClient

type BifrostClient struct {
	ID          string
	Flusher     http.Flusher
	Writer      http.ResponseWriter
	ConnectedAt time.Time
	LastPing    time.Time
}

BifrostClient represents a connected client.

type BifrostMessage

type BifrostMessage struct {
	Type      string                 `json:"type"`      // "message", "notification", "confirmation"
	Timestamp int64                  `json:"timestamp"` // Unix timestamp
	Content   string                 `json:"content,omitempty"`
	Title     string                 `json:"title,omitempty"`
	Level     string                 `json:"level,omitempty"` // "info", "warning", "error", "success"
	Data      map[string]interface{} `json:"data,omitempty"`
}

BifrostMessage is a message sent through Bifrost.

type CacheMetrics

type CacheMetrics struct {
	Size      int     `json:"size"`
	MaxSize   int     `json:"max_size"`
	Hits      uint64  `json:"hits"`
	Misses    uint64  `json:"misses"`
	HitRate   float64 `json:"hit_rate"`
	Evictions uint64  `json:"evictions"`
	TTL       string  `json:"ttl"`
}

CacheMetrics contains query cache statistics.

type CancellationInfo

type CancellationInfo struct {
	Reason      string `json:"reason"`
	CancelledBy string `json:"cancelled_by"`
	Phase       string `json:"phase"` // "PrePrompt" or "PreExecute"
}

CancellationInfo contains details about a cancelled request.

type ChatChoice

type ChatChoice struct {
	Index        int          `json:"index"`
	Message      *ChatMessage `json:"message,omitempty"`
	Delta        *ChatMessage `json:"delta,omitempty"` // For streaming
	FinishReason string       `json:"finish_reason,omitempty"`
}

ChatChoice represents a single completion choice.

type ChatMessage

type ChatMessage struct {
	Role      string             `json:"role"` // "system", "user", "assistant"
	Content   string             `json:"content"`
	ToolCalls []ChatToolCallWire `json:"tool_calls,omitempty"`
}

ChatMessage represents a message in the chat format (OpenAI-compatible).

type ChatRequest

type ChatRequest struct {
	Model       string               `json:"model"`
	Messages    []ChatMessage        `json:"messages"`
	Tools       []ChatToolDefinition `json:"tools,omitempty"`
	Stream      bool                 `json:"stream,omitempty"`
	MaxTokens   int                  `json:"max_tokens,omitempty"`
	Temperature float32              `json:"temperature,omitempty"`
	TopP        float32              `json:"top_p,omitempty"`
}

ChatRequest is the request format for chat completions. Compatible with OpenAI/Ollama API format.

type ChatResponse

type ChatResponse struct {
	ID      string       `json:"id"`
	Object  string       `json:"object"` // "chat.completion" or "chat.completion.chunk"
	Model   string       `json:"model"`
	Created int64        `json:"created"`
	Choices []ChatChoice `json:"choices"`
	Usage   *ChatUsage   `json:"usage,omitempty"`
}

ChatResponse is the response format for chat completions. Fully OpenAI API compatible.

type ChatToolCallWire added in v1.0.42

type ChatToolCallWire struct {
	ID       string               `json:"id"`
	Type     string               `json:"type"`
	Function ChatToolFunctionWire `json:"function"`
}

type ChatToolDefinition added in v1.0.42

type ChatToolDefinition struct {
	Type     string                     `json:"type,omitempty"`
	Function ChatToolDefinitionFunction `json:"function"`
}

type ChatToolDefinitionFunction added in v1.0.42

type ChatToolDefinitionFunction struct {
	Name        string          `json:"name"`
	Description string          `json:"description,omitempty"`
	Parameters  json.RawMessage `json:"parameters,omitempty"`
}

type ChatToolFunctionWire added in v1.0.42

type ChatToolFunctionWire struct {
	Name      string `json:"name"`
	Arguments string `json:"arguments"`
}

type ChatUsage

type ChatUsage struct {
	PromptTokens     int `json:"prompt_tokens"`
	CompletionTokens int `json:"completion_tokens"`
	TotalTokens      int `json:"total_tokens"`
}

ChatUsage tracks token usage.

type ClusterStats

type ClusterStats struct {
	NumClusters    int     `json:"num_clusters"`
	EmbeddingCount int     `json:"embedding_count"`
	IsClustered    bool    `json:"is_clustered"`
	AvgClusterSize float64 `json:"avg_cluster_size,omitempty"`
	Iterations     int     `json:"iterations,omitempty"`
}

ClusterStats contains k-means clustering statistics.

type Config

type Config struct {
	// Enabled controls whether Heimdall (the cognitive guardian) is active.
	// When enabled, Bifrost (the chat interface) is automatically enabled.
	// Default: false (opt-in feature)
	Enabled bool `json:"enabled"`

	// BifrostEnabled controls the Bifrost chat interface.
	// Automatically set to true when Heimdall is enabled.
	// Cannot be enabled independently - Bifrost requires Heimdall.
	BifrostEnabled bool `json:"bifrost_enabled"`

	ModelsDir   string  `json:"models_dir"`
	Model       string  `json:"model"`
	Provider    string  `json:"provider"`     // local, ollama, openai, vllm
	APIURL      string  `json:"api_url"`      // for ollama/openai
	APIKey      string  `json:"api_key"`      // for openai
	ContextSize int     `json:"context_size"` // Context window size (single-shot, max out)
	BatchSize   int     `json:"batch_size"`   // Batch size (match context for single-shot)
	MaxTokens   int     `json:"max_tokens"`
	Temperature float32 `json:"temperature"`
	GPULayers   int     `json:"gpu_layers"`

	// Feature toggles
	AnomalyDetection bool          `json:"anomaly_detection"`
	AnomalyInterval  time.Duration `json:"anomaly_interval"`
	RuntimeDiagnosis bool          `json:"runtime_diagnosis"`
	RuntimeInterval  time.Duration `json:"runtime_interval"`
	MemoryCuration   bool          `json:"memory_curation"`
	CurationInterval time.Duration `json:"curation_interval"`
}

Config holds SLM subsystem configuration.

func ConfigFromFeatureFlags

func ConfigFromFeatureFlags(flags FeatureFlagsSource) Config

ConfigFromFeatureFlags creates Heimdall config from feature flags. This is the preferred way to create Config - respects BYOM settings.

Key behavior:

  • When Heimdall is enabled, Bifrost is automatically enabled
  • Bifrost cannot be enabled independently (requires Heimdall)
  • Heimdall is disabled by default (opt-in feature)
  • Uses NORNICDB_MODELS_DIR for model location (same as embedder)

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns sensible defaults. Heimdall is disabled by default (opt-in feature). When Heimdall is enabled, Bifrost is automatically enabled.

type DatabaseEvent

type DatabaseEvent struct {
	// Type identifies what kind of event occurred
	Type DatabaseEventType `json:"type"`

	// Timestamp when the event occurred
	Timestamp time.Time `json:"timestamp"`

	// RequestID links to the originating request (if applicable)
	RequestID string `json:"request_id,omitempty"`

	// NodeID for node events
	NodeID string `json:"node_id,omitempty"`

	// NodeLabels for node events
	NodeLabels []string `json:"node_labels,omitempty"`

	// RelationshipID for relationship events
	RelationshipID string `json:"relationship_id,omitempty"`

	// RelationshipType for relationship events
	RelationshipType string `json:"relationship_type,omitempty"`

	// SourceNodeID for relationship events
	SourceNodeID string `json:"source_node_id,omitempty"`

	// TargetNodeID for relationship events
	TargetNodeID string `json:"target_node_id,omitempty"`

	// Properties that were set/changed
	Properties map[string]interface{} `json:"properties,omitempty"`

	// OldProperties for update events (what was there before)
	OldProperties map[string]interface{} `json:"old_properties,omitempty"`

	// Query is the Cypher query that was executed
	Query string `json:"query,omitempty"`

	// QueryParams are the parameters passed to the query
	QueryParams map[string]interface{} `json:"query_params,omitempty"`

	// Duration of query execution
	Duration time.Duration `json:"duration,omitempty"`

	// RowsAffected by the query
	RowsAffected int64 `json:"rows_affected,omitempty"`

	// Error message if the query failed
	Error string `json:"error,omitempty"`

	// IndexName for index events
	IndexName string `json:"index_name,omitempty"`

	// IndexLabel for index events
	IndexLabel string `json:"index_label,omitempty"`

	// IndexProperty for index events
	IndexProperty string `json:"index_property,omitempty"`

	// UserID who triggered the event (if authenticated)
	UserID string `json:"user_id,omitempty"`

	// Source identifies where the event came from (e.g., "bolt", "http", "internal")
	Source string `json:"source,omitempty"`

	// Metadata for any additional event-specific data
	Metadata map[string]interface{} `json:"metadata,omitempty"`
}

DatabaseEvent represents a database event that plugins can react to. This provides a unified interface for all database operations.

func (*DatabaseEvent) IsNodeEvent

func (e *DatabaseEvent) IsNodeEvent() bool

IsNodeEvent returns true if this is a node-related event.

func (*DatabaseEvent) IsQueryEvent

func (e *DatabaseEvent) IsQueryEvent() bool

IsQueryEvent returns true if this is a query-related event.

func (*DatabaseEvent) IsRelationshipEvent

func (e *DatabaseEvent) IsRelationshipEvent() bool

IsRelationshipEvent returns true if this is a relationship-related event.

func (*DatabaseEvent) IsTransactionEvent

func (e *DatabaseEvent) IsTransactionEvent() bool

IsTransactionEvent returns true if this is a transaction-related event.

type DatabaseEventHook

type DatabaseEventHook interface {
	// OnDatabaseEvent is called when a database event occurs.
	// This is fire-and-forget (does not block database operations).
	// The plugin should handle errors internally and not panic.
	//
	// Events are delivered asynchronously - the database operation
	// has already completed by the time this is called.
	//
	// Plugins can use this to:
	//   - Build audit logs
	//   - Track usage patterns
	//   - Trigger alerts on specific events
	//   - Update caches
	//   - Collect metrics
	OnDatabaseEvent(event *DatabaseEvent)
}

DatabaseEventHook is an optional interface for plugins that want to react to database events. This enables plugins to monitor database activity without modifying the database layer.

type DatabaseEventType

type DatabaseEventType string

DatabaseEventType categorizes database events.

const (
	// Node events
	EventNodeCreated DatabaseEventType = "node.created"
	EventNodeUpdated DatabaseEventType = "node.updated"
	EventNodeDeleted DatabaseEventType = "node.deleted"
	EventNodeRead    DatabaseEventType = "node.read"

	// Relationship events
	EventRelationshipCreated DatabaseEventType = "relationship.created"
	EventRelationshipUpdated DatabaseEventType = "relationship.updated"
	EventRelationshipDeleted DatabaseEventType = "relationship.deleted"

	// Query events
	EventQueryExecuted DatabaseEventType = "query.executed"
	EventQueryFailed   DatabaseEventType = "query.failed"

	// Index events
	EventIndexCreated DatabaseEventType = "index.created"
	EventIndexDropped DatabaseEventType = "index.dropped"

	// Transaction events
	EventTransactionCommit   DatabaseEventType = "transaction.commit"
	EventTransactionRollback DatabaseEventType = "transaction.rollback"

	// System events
	EventDatabaseStarted  DatabaseEventType = "database.started"
	EventDatabaseShutdown DatabaseEventType = "database.shutdown"
	EventBackupStarted    DatabaseEventType = "backup.started"
	EventBackupCompleted  DatabaseEventType = "backup.completed"
)

type DatabaseMetrics

type DatabaseMetrics struct {
	NodeCount        int64                  `json:"node_count"`
	EdgeCount        int64                  `json:"edge_count"`
	LabelCounts      map[string]int64       `json:"label_counts,omitempty"`
	IndexCount       int                    `json:"index_count"`
	PropertyIndexes  int                    `json:"property_indexes"`
	CompositeIndexes int                    `json:"composite_indexes"`
	MVCCLifecycle    map[string]interface{} `json:"mvcc_lifecycle,omitempty"`
}

DatabaseMetrics contains core database statistics.

type DatabaseMetricsSource

type DatabaseMetricsSource interface {
	// Core stats
	Stats() interface{} // Returns DBStats or similar

	// Node/Edge counts
	NodeCount() (int64, error)
	EdgeCount() (int64, error)

	// Embed queue
	EmbedQueueStats() interface{}

	// Storage engine
	GetAsyncEngine() AsyncEngineStats
	GetWAL() WALStats
	GetSchemaManager() SchemaManagerStats

	// Query cache
	GetQueryCache() QueryCacheStats

	// GPU
	GetGPUManager() GPUManagerStats

	// Encryption
	EncryptionStats() map[string]interface{}
}

DatabaseMetricsSource is the interface for collecting database metrics.

type DatabaseRouter

type DatabaseRouter interface {
	// DefaultDatabaseName returns the configured default database name.
	DefaultDatabaseName() string

	// ResolveDatabase resolves a database alias or name to the underlying database name.
	ResolveDatabase(nameOrAlias string) (string, error)

	// ListDatabases returns the known logical database names.
	ListDatabases() []string

	// Query executes a Cypher query against the specified logical database.
	//
	// NOTE: Despite the historical "read-only" naming, this method may execute write
	// queries depending on the underlying Cypher engine. Treat it as a general Cypher
	// execution entrypoint unless your implementation enforces read-only semantics.
	Query(ctx context.Context, database string, cypher string, params map[string]interface{}) ([]map[string]interface{}, error)

	// Stats returns database statistics for the specified logical database.
	Stats(database string) (DatabaseStats, error)

	// Discover performs semantic search with graph traversal in the specified database.
	// Returns search results with related nodes up to the specified depth.
	Discover(ctx context.Context, database string, query string, nodeTypes []string, limit int, depth int) (*DiscoverResult, error)
}

DatabaseRouter provides multi-database access for Heimdall actions and plugins.

IMPORTANT:

  • The `database` parameter is a logical database name (or alias) as used by the Neo4j-compatible multi-database layer.
  • If `database` is empty, implementations must route to the configured default database.

This interface is intentionally database-name aware so plugins can maintain strict tenant isolation by routing each operation to the correct logical database.

type DatabaseStats

type DatabaseStats struct {
	NodeCount         int64            `json:"node_count"`
	RelationshipCount int64            `json:"relationship_count"`
	LabelCounts       map[string]int64 `json:"label_counts"`
	ClusterStats      *ClusterStats    `json:"cluster_stats,omitempty"`
	FeatureFlags      *FeatureFlags    `json:"feature_flags,omitempty"`
}

DatabaseStats contains database statistics.

type DefaultLogger

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

DefaultLogger is a simple logger implementation.

func NewDefaultLogger

func NewDefaultLogger(prefix string) *DefaultLogger

NewDefaultLogger creates a logger with the given prefix.

func (*DefaultLogger) Debug

func (l *DefaultLogger) Debug(msg string, args ...interface{})

func (*DefaultLogger) Error

func (l *DefaultLogger) Error(msg string, args ...interface{})

func (*DefaultLogger) Info

func (l *DefaultLogger) Info(msg string, args ...interface{})

func (*DefaultLogger) Warn

func (l *DefaultLogger) Warn(msg string, args ...interface{})

type DiscoverResult

type DiscoverResult struct {
	Results []SearchResult `json:"results"`
	Method  string         `json:"method"` // "vector" or "keyword"
	Total   int            `json:"total"`
}

DiscoverResult contains semantic search results with related nodes.

type Embedder

type Embedder interface {
	Embed(ctx context.Context, text string) ([]float32, error)
	ChunkText(text string, maxTokens, overlap int) ([]string, error)
}

Embedder generates embeddings for text.

type EmbeddingMetrics

type EmbeddingMetrics struct {
	WorkerRunning     bool    `json:"worker_running"`
	Processed         int     `json:"processed"`
	Failed            int     `json:"failed"`
	QueueLength       int     `json:"queue_length"`
	NodesWithEmbed    int64   `json:"nodes_with_embeddings"`
	NodesWithoutEmbed int64   `json:"nodes_without_embeddings"`
	EmbedRate         float64 `json:"embed_rate"`
	Provider          string  `json:"provider"`
	Model             string  `json:"model"`
	Dimensions        int     `json:"dimensions"`
}

EmbeddingMetrics contains embedding worker statistics.

type FeatureFlags

type FeatureFlags struct {
	// Core Heimdall flags
	HeimdallEnabled          bool `json:"heimdall_enabled"`
	HeimdallAnomalyDetection bool `json:"heimdall_anomaly_detection"`
	HeimdallRuntimeDiagnosis bool `json:"heimdall_runtime_diagnosis"`
	HeimdallMemoryCuration   bool `json:"heimdall_memory_curation"`

	// Clustering (derived from search stats)
	ClusteringEnabled bool `json:"clustering_enabled"`

	// Topology/prediction flags
	TopologyEnabled bool `json:"topology_enabled"`
	KalmanEnabled   bool `json:"kalman_enabled"`

	// Runtime flags (derived from DB state)
	AsyncWritesEnabled bool `json:"async_writes_enabled"`
}

FeatureFlags contains enabled/disabled feature status.

type FeatureFlagsSource

type FeatureFlagsSource interface {
	GetHeimdallEnabled() bool
	GetHeimdallModel() string
	GetHeimdallProvider() string
	GetHeimdallAPIURL() string
	GetHeimdallAPIKey() string
	GetHeimdallGPULayers() int
	GetHeimdallContextSize() int
	GetHeimdallBatchSize() int
	GetHeimdallMaxTokens() int
	GetHeimdallTemperature() float32
	GetHeimdallAnomalyDetection() bool
	GetHeimdallRuntimeDiagnosis() bool
	GetHeimdallMemoryCuration() bool
	GetHeimdallMaxContextTokens() int
	GetHeimdallMaxSystemTokens() int
	GetHeimdallMaxUserTokens() int
}

FeatureFlagsSource is the interface for getting Heimdall config from feature flags. This avoids import cycles with the config package.

type FullLifecycleHook

FullLifecycleHook is a convenience interface for plugins that implement all hooks. Plugins are NOT required to implement this - they can pick and choose.

Hook execution order:

  1. PrePromptHook - Modify prompt context before SLM processes it
  2. PreExecuteHook - Validate/modify params before action runs
  3. (Action executes)
  4. PostExecuteHook - Log, update state after action completes
  5. SynthesisHook - Transform action results into user-friendly prose
  6. (Response sent to user)

DatabaseEventHook runs asynchronously on database operations.

type GPUManagerStats

type GPUManagerStats interface {
	IsEnabled() bool
	Device() interface{}
	Stats() interface{}
	AllocatedMemoryMB() int
}

GPUManagerStats is the interface for GPU metrics.

type GPUMetrics

type GPUMetrics struct {
	Available     bool   `json:"available"`
	Enabled       bool   `json:"enabled"`
	DeviceName    string `json:"device_name,omitempty"`
	Backend       string `json:"backend,omitempty"`
	MemoryMB      int    `json:"memory_mb,omitempty"`
	AllocatedMB   int    `json:"allocated_mb"`
	OperationsGPU int64  `json:"operations_gpu"`
	OperationsCPU int64  `json:"operations_cpu"`
	FallbackCount int64  `json:"fallback_count"`
}

GPUMetrics contains GPU acceleration statistics.

type GenerateParams

type GenerateParams struct {
	MaxTokens   int
	Temperature float32
	TopP        float32
	TopK        int
	StopTokens  []string
}

GenerateParams configures text generation.

func DefaultGenerateParams

func DefaultGenerateParams() GenerateParams

DefaultGenerateParams returns sensible defaults for chat (Qwen3-aligned). Qwen3 0.6B instruct best practices: temperature 0.5–0.7, top_p 0.8, top_k 20 to reduce repetition.

type Generator

type Generator interface {
	// Generate produces a complete response.
	Generate(ctx context.Context, prompt string, params GenerateParams) (string, error)

	// GenerateStream produces tokens via callback.
	GenerateStream(ctx context.Context, prompt string, params GenerateParams, callback func(token string) error) error

	// Close releases model resources.
	Close() error

	// ModelPath returns the loaded model path.
	ModelPath() string
}

Generator is the interface for text generation models.

type GeneratorLoader

type GeneratorLoader func(modelPath string, gpuLayers, contextSize, batchSize int) (Generator, error)

GeneratorLoader is a function type for loading generators. This can be replaced for testing or by CGO implementation. Parameters:

  • modelPath: Path to the GGUF model file
  • gpuLayers: GPU layer offload (-1=auto, 0=CPU only)
  • contextSize: Context window size (single-shot = 8192)
  • batchSize: Batch processing size (match context for single-shot)
var DefaultGeneratorLoader GeneratorLoader = func(modelPath string, gpuLayers, contextSize, batchSize int) (Generator, error) {
	return nil, fmt.Errorf("SLM generation requires CGO build with localllm tag")
}

DefaultGeneratorLoader is the default loader (stub without CGO).

func SetGeneratorLoader

func SetGeneratorLoader(loader GeneratorLoader) GeneratorLoader

SetGeneratorLoader allows overriding the generator loader for testing. Returns the previous loader so it can be restored.

type GeneratorWithTools

type GeneratorWithTools interface {
	Generator

	// GenerateWithTools runs one round of chat with tools. messages is the full conversation
	// so far (system, user, optional assistant+tool_calls, tool results, ...). Returns content
	// (text reply) and/or toolCalls. Handler executes toolCalls, appends messages, and calls
	// again until toolCalls is empty (agentic loop).
	GenerateWithTools(ctx context.Context, messages []ToolRoundMessage, tools []MCPTool, params GenerateParams) (content string, toolCalls []ParsedToolCall, err error)
}

GeneratorWithTools is implemented by generators that support native tool/function calling. When used, the handler runs an agentic loop: call GenerateWithTools, execute any toolCalls, append assistant + tool result messages, call again until the model returns content only. Used for OpenAI and Ollama; local GGUF uses prompt-based agentic loop (same loop, prompt-based).

type GraphEdge

type GraphEdge struct {
	ID         string
	Type       string
	SourceID   string
	TargetID   string
	Properties map[string]interface{}
}

GraphEdge represents an edge in the graph.

type Handler

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

Handler provides HTTP endpoints for Bifrost chat. Uses standard HTTP/SSE - no external dependencies required. Bifrost is the rainbow bridge that connects to Heimdall.

Endpoints:

  • GET /api/bifrost/status - Heimdall and Bifrost status
  • POST /api/bifrost/chat/completions - Chat with Heimdall
  • GET /v1/models - OpenAI-compatible single-model list
  • POST /v1/chat/completions - OpenAI-compatible alias for Bifrost chat
  • GET /api/bifrost/events - SSE stream for real-time events

func NewHandler

func NewHandler(manager *Manager, cfg Config, db DatabaseRouter, metrics MetricsReader) *Handler

NewHandler creates a Bifrost HTTP handler. Returns nil if Heimdall is disabled (manager is nil). Automatically creates Bifrost bridge when Heimdall is enabled.

func (*Handler) Bifrost

func (h *Handler) Bifrost() BifrostBridge

Bifrost returns the BifrostBridge for plugin communication. Returns NoOpBifrost if Bifrost is not available.

func (*Handler) ServeHTTP

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP routes requests to appropriate handlers.

func (*Handler) SetInMemoryToolRunner

func (h *Handler) SetInMemoryToolRunner(runner InMemoryToolRunner)

SetInMemoryToolRunner sets the runner for MCP-style tools (store, recall, discover, etc.) so the agentic loop can call them in process. When set, tools from the runner are merged into the tool list and execution is dispatched in memory instead of via HTTP.

type HeimdallInvoker

type HeimdallInvoker interface {
	// InvokeAction directly invokes a registered action by name.
	// The action must be registered (e.g., "heimdall_watcher_status").
	// Results are returned synchronously.
	//
	// Example:
	//   result, err := ctx.Heimdall.InvokeAction("heimdall_anomaly_detect", map[string]interface{}{
	//       "threshold": 0.8,
	//   })
	InvokeAction(ctx context.Context, action string, params map[string]interface{}) (*ActionResult, error)

	// SendPrompt sends a natural language prompt to the SLM for processing.
	// The SLM will interpret the prompt and may invoke registered actions.
	// Results are returned after the SLM processes the request.
	//
	// Example:
	//   result, err := ctx.Heimdall.SendPrompt("Analyze recent error patterns")
	SendPrompt(ctx context.Context, prompt string) (*ActionResult, error)

	// InvokeActionAsync invokes an action without waiting for result.
	// Use this for fire-and-forget scenarios where you don't need the result.
	// Results will be broadcast via Bifrost to connected clients.
	InvokeActionAsync(action string, params map[string]interface{})

	// SendPromptAsync sends a prompt without waiting for result.
	// Results will be broadcast via Bifrost to connected clients.
	SendPromptAsync(prompt string)

	// SendRawPrompt sends a prompt directly to the LLM without action routing context.
	// Use this for synthesis or direct question-answering where you don't want
	// the SLM to try parsing actions from the response.
	//
	// Example:
	//   result, err := ctx.Heimdall.SendRawPrompt("Answer this question: How many nodes?")
	SendRawPrompt(ctx context.Context, prompt string) (*ActionResult, error)
}

HeimdallInvoker allows plugins to autonomously trigger SLM actions. This enables event-driven automation where plugins can analyze accumulated events and trigger appropriate responses.

Example: A security plugin monitors failed auth events and after N failures triggers "heimdall_security_analyze" to investigate.

type HeimdallPlugin

type HeimdallPlugin interface {

	// Name returns the plugin/subsystem identifier (e.g., "anomaly", "health", "curator")
	Name() string

	// Version returns the plugin version (semver format)
	Version() string

	// Type must return "heimdall" to identify this as a Heimdall plugin
	Type() string

	// Description returns human-readable description of what this subsystem does
	Description() string

	// Initialize is called when the subsystem is loaded
	// Receives context for accessing database, config, etc.
	Initialize(ctx SubsystemContext) error

	// Start begins the subsystem's background operations (if any)
	Start() error

	// Stop halts the subsystem's background operations
	Stop() error

	// Shutdown is called when the subsystem is being unloaded
	Shutdown() error

	// Status returns current subsystem status
	Status() SubsystemStatus

	// Health returns detailed health information
	Health() SubsystemHealth

	// Metrics returns subsystem-specific metrics for the SLM to analyze
	Metrics() map[string]interface{}

	// Config returns current configuration
	Config() map[string]interface{}

	// Configure updates subsystem configuration
	// The SLM can use this to tune subsystem behavior
	Configure(settings map[string]interface{}) error

	// Schema returns the configuration schema (for validation)
	ConfigSchema() map[string]interface{}

	// Actions returns all actions this subsystem provides
	// Map key is the action name (e.g., "detect"), will be prefixed as slm.{name}.{action}
	Actions() map[string]ActionFunc

	// Summary returns a text summary of current subsystem state
	// Used by SLM to understand what the subsystem is doing
	Summary() string

	// RecentEvents returns recent notable events from this subsystem
	// Used by SLM for contextual awareness
	RecentEvents(limit int) []SubsystemEvent
}

HeimdallPlugin is the interface that all Heimdall plugins must implement. This is a DISTINCT plugin type from regular NornicDB plugins.

Regular plugins provide Cypher functions (apoc.*). Heimdall plugins provide SUBSYSTEM MANAGEMENT for cognitive database features.

Heimdall (the guardian) uses this interface to:

  • Query subsystem state and health
  • Configure subsystem behavior
  • Control subsystem lifecycle
  • Execute subsystem actions
  • Collect subsystem metrics

type InMemoryToolRunner

type InMemoryToolRunner interface {
	// ToolDefinitions returns tool definitions for the LLM (name, description, inputSchema).
	ToolDefinitions() []MCPTool
	// ToolNames returns the list of tool names this runner handles (for dispatch).
	ToolNames() []string
	// CallTool executes the named tool with the given arguments in the given database context.
	// dbName is the logical database name (e.g. from DefaultDatabaseName()); use "" for default.
	CallTool(ctx context.Context, name string, args map[string]interface{}, dbName string) (interface{}, error)
}

InMemoryToolRunner provides MCP-style tools (e.g. store, recall, discover) that the agentic loop can call in process instead of via HTTP. Used to expose pkg/mcp memory tools to the LLM so it can manage memories through the same tool list.

type LiveHeimdallInvoker

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

LiveHeimdallInvoker is the production implementation of HeimdallInvoker. It uses the SubsystemManager to invoke actions and can optionally use a Generator for SLM prompt processing.

func NewLiveHeimdallInvoker

func NewLiveHeimdallInvoker(manager *SubsystemManager, generator Generator, bifrost BifrostBridge, database DatabaseRouter, metrics MetricsReader) *LiveHeimdallInvoker

NewLiveHeimdallInvoker creates a new invoker with the required dependencies.

func (*LiveHeimdallInvoker) InvokeAction

func (h *LiveHeimdallInvoker) InvokeAction(ctx context.Context, action string, params map[string]interface{}) (*ActionResult, error)

InvokeAction directly invokes a registered action.

func (*LiveHeimdallInvoker) InvokeActionAsync

func (h *LiveHeimdallInvoker) InvokeActionAsync(action string, params map[string]interface{})

InvokeActionAsync invokes an action asynchronously, broadcasting results via Bifrost.

func (*LiveHeimdallInvoker) SendPrompt

func (h *LiveHeimdallInvoker) SendPrompt(ctx context.Context, prompt string) (*ActionResult, error)

SendPrompt sends a prompt to the SLM and processes the response.

func (*LiveHeimdallInvoker) SendPromptAsync

func (h *LiveHeimdallInvoker) SendPromptAsync(prompt string)

SendPromptAsync sends a prompt asynchronously, broadcasting results via Bifrost.

func (*LiveHeimdallInvoker) SendRawPrompt

func (h *LiveHeimdallInvoker) SendRawPrompt(ctx context.Context, prompt string) (*ActionResult, error)

SendRawPrompt sends a prompt directly to the SLM without action routing context. This is used for synthesis where we just want the LLM to answer a question, not try to parse and route actions.

type LoadedHeimdallPlugin

type LoadedHeimdallPlugin struct {
	Plugin  HeimdallPlugin // The actual plugin implementing full interface
	Path    string         // Path to .so file (empty for built-in)
	Builtin bool           // True if this is a built-in plugin
}

LoadedHeimdallPlugin represents a loaded SLM plugin with full subsystem management.

func ListHeimdallPlugins

func ListHeimdallPlugins() []*LoadedHeimdallPlugin

ListHeimdallPlugins returns information about all loaded SLM plugins.

type MCPTool

type MCPTool struct {
	Name        string          `json:"name"`
	Description string          `json:"description"`
	InputSchema json.RawMessage `json:"inputSchema"`
}

MCPTool is the MCP (Model Context Protocol) tool definition shape. Use ActionsAsMCPTools() to export Heimdall actions as MCP tools. Same fields as MCP Tool: name, description, inputSchema (JSON Schema).

func ActionsAsMCPTools

func ActionsAsMCPTools() []MCPTool

ActionsAsMCPTools returns all registered Heimdall actions in MCP tool format. Use this to expose Heimdall actions to MCP clients or to merge with pkg/mcp tool list. Each tool has name, description, and inputSchema (JSON Schema); when an action has no InputSchema set, DefaultActionInputSchema is used.

type Manager

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

Manager handles Heimdall SLM model loading and inference. Follows the same BYOM pattern as the embedding subsystem.

Environment variables:

  • NORNICDB_MODELS_DIR: Directory for .gguf files (default: /data/models)
  • NORNICDB_HEIMDALL_MODEL: Model name (default: qwen2.5-1.5b-instruct-q4_k_m)
  • NORNICDB_HEIMDALL_GPU_LAYERS: GPU layer offload (-1=auto, 0=CPU only)
  • NORNICDB_HEIMDALL_ENABLED: Feature flag (default: false)

func NewManager

func NewManager(cfg Config) (*Manager, error)

NewManager creates an SLM manager using BYOM configuration. Returns nil if SLM feature is disabled.

Provider selection (matches embeddings: local / ollama / openai / vllm):

  • openai: Use OpenAI (or compatible) chat API; requires NORNICDB_HEIMDALL_API_KEY.
  • ollama: Use Ollama /api/chat; NORNICDB_HEIMDALL_API_URL defaults to http://localhost:11434.
  • vllm: Use vLLM's OpenAI-compatible API; NORNICDB_HEIMDALL_API_URL defaults to http://localhost:8000.
  • local or empty: Load GGUF from NORNICDB_MODELS_DIR (BYOM).

func (*Manager) Chat

func (m *Manager) Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error)

Chat handles chat completion requests.

func (*Manager) Close

func (m *Manager) Close() error

Close releases all resources.

func (*Manager) Generate

func (m *Manager) Generate(ctx context.Context, prompt string, params GenerateParams) (string, error)

Generate produces a response for the given prompt.

func (*Manager) GenerateStream

func (m *Manager) GenerateStream(ctx context.Context, prompt string, params GenerateParams, callback func(token string) error) error

GenerateStream produces tokens via callback.

func (*Manager) GenerateWithTools

func (m *Manager) GenerateWithTools(ctx context.Context, messages []ToolRoundMessage, tools []MCPTool, params GenerateParams) (content string, toolCalls []ParsedToolCall, err error)

GenerateWithTools runs one round of chat with tools (agentic loop). Only valid when SupportsTools() is true. Returns content and/or toolCalls; caller executes tools and calls again until no toolCalls.

func (*Manager) ModelPath

func (m *Manager) ModelPath() string

ModelPath returns the path to the loaded model. This allows Manager to implement the Generator interface.

func (*Manager) Stats

func (m *Manager) Stats() ManagerStats

func (*Manager) SupportsTools

func (m *Manager) SupportsTools() bool

SupportsTools returns true if the generator supports native tool/function calling (e.g. OpenAI, Ollama). When true, the handler uses GenerateWithTools and an agentic loop.

type ManagerStats

type ManagerStats struct {
	ModelPath    string    `json:"model_path"`
	RequestCount int64     `json:"request_count"`
	ErrorCount   int64     `json:"error_count"`
	LastUsed     time.Time `json:"last_used"`
	Enabled      bool      `json:"enabled"`
}

Stats returns current manager statistics.

type MetricsCollector

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

MetricsCollector collects metrics from all NornicDB subsystems.

func NewMetricsCollector

func NewMetricsCollector(db DatabaseMetricsSource, server ServerMetricsSource) *MetricsCollector

NewMetricsCollector creates a new metrics collector.

func (*MetricsCollector) Collect

func (c *MetricsCollector) Collect() *NornicDBMetrics

Collect gathers all metrics from the database.

func (*MetricsCollector) Runtime

func (c *MetricsCollector) Runtime() RuntimeMetrics

Runtime returns current runtime metrics (always cheap to collect).

type MetricsReader

type MetricsReader interface {
	// Runtime returns current runtime metrics
	Runtime() RuntimeMetrics
}

MetricsReader provides runtime metrics access for actions.

type ModelInfo

type ModelInfo struct {
	Name         string    `json:"name"`
	Path         string    `json:"path"`
	Type         ModelType `json:"type"`
	SizeBytes    int64     `json:"size_bytes"`
	Quantization string    `json:"quantization,omitempty"`
	Loaded       bool      `json:"loaded"`
	LastUsed     time.Time `json:"last_used,omitempty"`
	VRAMEstimate int64     `json:"vram_estimate_bytes"`
}

ModelInfo describes an available model in the registry.

type ModelType

type ModelType string

ModelType categorizes models by their purpose.

const (
	ModelTypeEmbedding      ModelType = "embedding"
	ModelTypeReasoning      ModelType = "reasoning"
	ModelTypeClassification ModelType = "classification"
)

type NoOpBifrost

type NoOpBifrost struct{}

NoOpBifrost is a no-op implementation for when Bifrost is not available.

func (*NoOpBifrost) Broadcast

func (n *NoOpBifrost) Broadcast(msg string) error

func (*NoOpBifrost) ConnectionCount

func (n *NoOpBifrost) ConnectionCount() int

func (*NoOpBifrost) IsConnected

func (n *NoOpBifrost) IsConnected() bool

func (*NoOpBifrost) RequestConfirmation

func (n *NoOpBifrost) RequestConfirmation(action string) (bool, error)

func (*NoOpBifrost) SendMessage

func (n *NoOpBifrost) SendMessage(msg string) error

func (*NoOpBifrost) SendNotification

func (n *NoOpBifrost) SendNotification(t, title, msg string) error

type NoOpHeimdallInvoker

type NoOpHeimdallInvoker struct{}

NoOpHeimdallInvoker is a no-op implementation when Heimdall is not available.

func (*NoOpHeimdallInvoker) InvokeAction

func (n *NoOpHeimdallInvoker) InvokeAction(ctx context.Context, action string, params map[string]interface{}) (*ActionResult, error)

func (*NoOpHeimdallInvoker) InvokeActionAsync

func (n *NoOpHeimdallInvoker) InvokeActionAsync(action string, params map[string]interface{})

func (*NoOpHeimdallInvoker) SendPrompt

func (n *NoOpHeimdallInvoker) SendPrompt(ctx context.Context, prompt string) (*ActionResult, error)

func (*NoOpHeimdallInvoker) SendPromptAsync

func (n *NoOpHeimdallInvoker) SendPromptAsync(prompt string)

func (*NoOpHeimdallInvoker) SendRawPrompt

func (n *NoOpHeimdallInvoker) SendRawPrompt(ctx context.Context, prompt string) (*ActionResult, error)

type NodeData

type NodeData struct {
	ID         string
	Labels     []string
	Properties map[string]interface{}
}

NodeData represents a node from the database.

type NornicDBMetrics

type NornicDBMetrics struct {
	// Server metrics
	Server ServerMetrics `json:"server"`

	// Database metrics
	Database DatabaseMetrics `json:"database"`

	// Storage engine metrics
	Storage StorageMetrics `json:"storage"`

	// Cache metrics
	Cache CacheMetrics `json:"cache"`

	// Embedding metrics
	Embedding EmbeddingMetrics `json:"embedding"`

	// GPU metrics
	GPU GPUMetrics `json:"gpu"`

	// Query metrics
	Query QueryMetrics `json:"query"`

	// Runtime metrics
	Runtime RuntimeMetrics `json:"runtime"`

	// Timestamp
	CollectedAt time.Time `json:"collected_at"`
}

NornicDBMetrics aggregates ALL database metrics for the SLM. This is the single source of truth for database observability.

type ParsedAction

type ParsedAction struct {
	Action string                 `json:"action"`
	Params map[string]interface{} `json:"params"`
}

ParseActionResponse parses an SLM response to extract action requests.

type ParsedToolCall

type ParsedToolCall struct {
	Id        string
	Name      string
	Arguments string
}

ParsedToolCall is a single tool invocation from a remote provider (OpenAI/Ollama). Arguments is the JSON string of parameters (e.g. "{\"cypher\": \"MATCH (n) RETURN n\"}"). Id is set by the provider (e.g. OpenAI) and must be sent back with the tool result for that call.

type PluginOrdering

type PluginOrdering interface {
	// Priority controls ordering when there are no explicit dependencies.
	// Higher values run earlier.
	Priority() int

	// Before lists plugin names that must run after this plugin.
	Before() []string

	// After lists plugin names that must run before this plugin.
	After() []string
}

PluginOrdering is an optional interface for plugins that want deterministic ordering. Higher priority runs earlier. Before/After define ordering constraints by plugin name.

type PostExecuteContext

type PostExecuteContext struct {
	// Context carries request cancellation and deadlines.
	Context context.Context

	// RequestID for tracking
	RequestID string

	// Action that was executed
	Action string

	// Params that were passed
	Params map[string]interface{}

	// Result from the action execution
	Result *ActionResult

	// Duration of action execution
	Duration time.Duration

	// PluginData from earlier phases
	PluginData map[string]interface{}

	// WasCancelled indicates if the request was cancelled in an earlier phase
	WasCancelled bool

	// CancellationInfo contains details if cancelled
	CancellationInfo *CancellationInfo
	// contains filtered or unexported fields
}

PostExecuteContext contains execution results for logging/state updates.

Notifications from PostExecute are queued and sent inline after the action result, ensuring proper ordering in the streaming response.

func (*PostExecuteContext) DrainNotifications

func (p *PostExecuteContext) DrainNotifications() []QueuedNotification

DrainNotifications returns and clears all queued notifications.

func (*PostExecuteContext) Notify

func (p *PostExecuteContext) Notify(notificationType, title, message string)

Notify queues a notification to be sent inline after the action result.

func (*PostExecuteContext) NotifyError

func (p *PostExecuteContext) NotifyError(title, message string)

NotifyError queues an error notification.

func (*PostExecuteContext) NotifyInfo

func (p *PostExecuteContext) NotifyInfo(title, message string)

NotifyInfo queues an info notification.

func (*PostExecuteContext) NotifySuccess

func (p *PostExecuteContext) NotifySuccess(title, message string)

NotifySuccess queues a success notification.

func (*PostExecuteContext) NotifyWarning

func (p *PostExecuteContext) NotifyWarning(title, message string)

NotifyWarning queues a warning notification.

type PostExecuteHook

type PostExecuteHook interface {
	// PostExecute is called AFTER action execution completes.
	// Plugins can:
	//   - Log execution metrics
	//   - Update internal state
	//   - Cache results
	//   - Trigger side effects
	// This is fire-and-forget (does not block response).
	PostExecute(ctx *PostExecuteContext)
}

PostExecuteHook is an optional interface for plugins that want to react to action results. If a plugin implements this, PostExecute will be called after each action completes.

type PreExecuteContext

type PreExecuteContext struct {
	// Context carries request cancellation and deadlines.
	Context context.Context

	// RequestID for tracking
	RequestID string

	// RequestTime when the request started
	RequestTime time.Time

	// Action is the parsed action name (e.g., "heimdall_watcher_status")
	Action string

	// Params are the parsed action parameters
	Params map[string]interface{}

	// RawResponse is the raw SLM response (for inspection if needed)
	RawResponse string

	// PluginData from the PrePrompt phase
	PluginData map[string]interface{}

	// Database routes Cypher/search operations across logical databases.
	Database DatabaseRouter

	// Metrics provides runtime metrics
	Metrics MetricsReader

	// PrincipalRoles are the authenticated principal's role names (from request context).
	PrincipalRoles []string

	// DatabaseAccessMode is the principal's per-database see/access mode (from request context).
	DatabaseAccessMode auth.DatabaseAccessMode

	// ResolvedAccess returns per-database read/write for the principal (from request context).
	ResolvedAccess func(dbName string) auth.ResolvedAccess
	// contains filtered or unexported fields
}

PreExecuteContext contains the parsed action before execution.

Cancellation: Call ctx.Cancel("reason", "hook:plugin") to abort execution. The reason will be logged and sent to the user via Bifrost.

Notifications: Plugins can send non-blocking SSE messages to the UI via ctx.Notify() - these are fire-and-forget and won't block the request.

func (*PreExecuteContext) Cancel

func (p *PreExecuteContext) Cancel(reason string, cancelledBy string)

Cancel aborts the action execution with a reason.

func (*PreExecuteContext) CancelReason

func (p *PreExecuteContext) CancelReason() string

CancelReason returns the reason for cancellation.

func (*PreExecuteContext) Cancelled

func (p *PreExecuteContext) Cancelled() bool

Cancelled returns true if the request has been cancelled.

func (*PreExecuteContext) CancelledBy

func (p *PreExecuteContext) CancelledBy() string

CancelledBy returns which hook/plugin cancelled.

func (*PreExecuteContext) DrainNotifications

func (p *PreExecuteContext) DrainNotifications() []QueuedNotification

DrainNotifications returns and clears all queued notifications.

func (*PreExecuteContext) Notify

func (p *PreExecuteContext) Notify(notificationType, title, message string)

Notify queues a notification to be sent inline after the AI response. This ensures proper ordering with the streaming content.

func (*PreExecuteContext) NotifyError

func (p *PreExecuteContext) NotifyError(title, message string)

NotifyError queues an error notification.

func (*PreExecuteContext) NotifyInfo

func (p *PreExecuteContext) NotifyInfo(title, message string)

NotifyInfo queues an info notification.

func (*PreExecuteContext) NotifyProgress

func (p *PreExecuteContext) NotifyProgress(title, message string)

NotifyProgress queues a progress notification.

func (*PreExecuteContext) NotifyWarning

func (p *PreExecuteContext) NotifyWarning(title, message string)

NotifyWarning queues a warning notification.

func (*PreExecuteContext) SetBifrost

func (p *PreExecuteContext) SetBifrost(b BifrostBridge)

SetBifrost sets the Bifrost bridge for notifications (called by handler).

type PreExecuteHook

type PreExecuteHook interface {
	// PreExecute is called AFTER Heimdall responds, BEFORE action execution.
	// Plugins can perform async operations:
	//   - Fetch additional data from external services
	//   - Validate/modify params
	//   - Abort execution by setting Continue=false
	// The done callback MUST be called when complete.
	PreExecute(ctx *PreExecuteContext, done func(PreExecuteResult))
}

PreExecuteHook is an optional interface for plugins that want to validate/modify actions. If a plugin implements this, PreExecute will be called after SLM responds but before action runs.

type PreExecuteResult

type PreExecuteResult struct {
	// Continue indicates whether to proceed with execution.
	// Set to false to abort the action.
	Continue bool

	// ModifiedParams replaces the original params if non-nil.
	ModifiedParams map[string]interface{}

	// AdditionalContext is merged into ActionContext.
	AdditionalContext map[string]interface{}

	// AbortMessage is returned to user if Continue=false.
	AbortMessage string

	// Error if something went wrong during pre-execute.
	Error error
}

PreExecuteResult is returned via callback after async operations complete.

func CallPreExecuteHooks

func CallPreExecuteHooks(ctx *PreExecuteContext) PreExecuteResult

CallPreExecuteHooks calls PreExecute on all plugins that implement PreExecuteHook. Plugins that don't implement the hook are silently skipped. This is synchronous - waits for each plugin with a timeout.

type PrePromptHook

type PrePromptHook interface {
	// PrePrompt is called BEFORE sending the prompt to Heimdall.
	// The ActionPrompt field is IMMUTABLE (already set, read-only).
	// Plugins can modify mutable fields:
	//   - AdditionalInstructions: Add context, constraints, guidance
	//   - Examples: Add domain-specific examples
	//   - PluginData: Store state for later phases
	// Return error to log warning (does not abort request).
	PrePrompt(ctx *PromptContext) error
}

PrePromptHook is an optional interface for plugins that want to modify prompts. If a plugin implements this, PrePrompt will be called before each SLM request.

type PromptBudgetInfo

type PromptBudgetInfo struct {
	SystemTokens    int `json:"system_tokens"`
	UserTokens      int `json:"user_tokens"`
	TotalTokens     int `json:"total_tokens"`
	MaxSystem       int `json:"max_system"`
	MaxUser         int `json:"max_user"`
	MaxTotal        int `json:"max_total"`
	SystemAvailable int `json:"system_available"`
	UserAvailable   int `json:"user_available"`
}

PromptBudgetInfo returns token budget information for debugging.

type PromptContext

type PromptContext struct {
	// Context carries request cancellation and deadlines.
	Context context.Context

	// RequestID for tracking through the lifecycle
	RequestID string

	// RequestTime when the request started
	RequestTime time.Time

	// ActionPrompt contains all registered actions formatted for the SLM.
	// This is always injected at the start of the system prompt.
	// Plugins CANNOT modify this field.
	ActionPrompt string

	// UserMessage is the current user input
	UserMessage string

	// Messages is the full conversation history
	Messages []ChatMessage

	// ExternalTools are tool definitions provided by the client (e.g. Continue/OpenAI tools).
	// These are exposed to the underlying model in addition to Heimdall's built-in actions.
	ExternalTools []MCPTool

	// AdditionalInstructions are appended after ActionPrompt.
	// Plugins add context, constraints, or guidance here.
	AdditionalInstructions string

	// Examples help Heimdall understand user intent.
	// Plugins can add domain-specific examples.
	Examples []PromptExample

	// PluginData persists through the request lifecycle.
	// Plugins can store state here for use in PreExecute/PostExecute.
	PluginData map[string]interface{}
	// contains filtered or unexported fields
}

PromptContext contains the prompt being built for Heimdall. ActionPrompt is immutable (always injected first). Plugins can modify the mutable fields to add context.

Cancellation: Any lifecycle hook can cancel the request by calling ctx.Cancel("reason"). The request will be aborted and the reason sent to the user via Bifrost.

Notifications: Plugins can send non-blocking SSE messages to the UI via ctx.Notify() - these are fire-and-forget and won't block the request.

func (*PromptContext) Broadcast

func (p *PromptContext) Broadcast(message string)

Broadcast sends a message to all connected clients (fire-and-forget).

func (*PromptContext) BuildFinalPrompt

func (p *PromptContext) BuildFinalPrompt() string

BuildFinalPrompt constructs the complete prompt for Heimdall (prompt-based flow: model outputs JSON actions). ActionPrompt is ALWAYS first and immutable. Falls back to minimal prompt if full prompt exceeds budget.

func (*PromptContext) BuildFinalPromptForTools

func (p *PromptContext) BuildFinalPromptForTools() string

BuildFinalPromptForTools constructs the system prompt when the provider uses native tool calling. Same as BuildFinalPrompt but with tools-friendly instructions: answer in natural language when the context contains the answer; use tools only when an action is needed. Plugins inject context via AdditionalInstructions (e.g. order status); the model should use it and reply in plain text.

func (*PromptContext) Cancel

func (p *PromptContext) Cancel(reason string, cancelledBy string)

Cancel aborts the request with a reason. The reason will be logged and sent to the user via Bifrost. cancelledBy should identify which plugin/hook is cancelling (e.g., "PrePrompt:myplugin").

func (*PromptContext) CancelReason

func (p *PromptContext) CancelReason() string

CancelReason returns the reason for cancellation (empty if not cancelled).

func (*PromptContext) Cancelled

func (p *PromptContext) Cancelled() bool

Cancelled returns true if the request has been cancelled.

func (*PromptContext) CancelledBy

func (p *PromptContext) CancelledBy() string

CancelledBy returns which hook/plugin cancelled the request.

func (*PromptContext) DrainNotifications

func (p *PromptContext) DrainNotifications() []QueuedNotification

DrainNotifications returns and clears all queued notifications. Called by the handler to send them inline with the streaming response.

func (*PromptContext) EstimatedSystemTokens

func (p *PromptContext) EstimatedSystemTokens() int

EstimatedSystemTokens returns estimated token count for the system prompt.

func (*PromptContext) GetBudgetInfo

func (p *PromptContext) GetBudgetInfo() PromptBudgetInfo

GetBudgetInfo returns current token budget information.

func (*PromptContext) Notify

func (p *PromptContext) Notify(notificationType, title, message string)

Notify queues a notification to be sent inline with the streaming response. This ensures proper ordering - notifications appear at the correct point in the chat. Use this to send progress updates, warnings, or informational messages.

func (*PromptContext) NotifyError

func (p *PromptContext) NotifyError(title, message string)

NotifyError sends an error notification (fire-and-forget).

func (*PromptContext) NotifyInfo

func (p *PromptContext) NotifyInfo(title, message string)

NotifyInfo sends an info notification (fire-and-forget).

func (*PromptContext) NotifyProgress

func (p *PromptContext) NotifyProgress(title, message string)

NotifyProgress sends a progress notification (fire-and-forget).

func (*PromptContext) NotifyWarning

func (p *PromptContext) NotifyWarning(title, message string)

NotifyWarning sends a warning notification (fire-and-forget).

func (*PromptContext) SendMessage

func (p *PromptContext) SendMessage(message string)

SendMessage sends a raw message to the UI (fire-and-forget).

func (*PromptContext) SetBifrost

func (p *PromptContext) SetBifrost(b BifrostBridge)

SetBifrost sets the Bifrost bridge for notifications (called by handler).

func (*PromptContext) ValidateTokenBudget

func (p *PromptContext) ValidateTokenBudget() error

ValidateTokenBudget checks if the prompt fits within the token budget. Returns an error if the system prompt is too large.

type PromptExample

type PromptExample struct {
	UserSays   string // What the user might say
	ActionJSON string // The JSON action Heimdall should output
}

PromptExample is a user→action mapping example for Heimdall.

type QueryCacheStats

type QueryCacheStats interface {
	Stats() interface{}
}

QueryCacheStats is the interface for cache metrics.

type QueryDatabase

type QueryDatabase interface {
	// Query executes a read-only Cypher query
	Query(ctx context.Context, cypher string, params map[string]interface{}) ([]map[string]interface{}, error)

	// Stats returns basic database stats
	Stats() interface{}

	// NodeCount returns total nodes
	NodeCount() (int64, error)

	// EdgeCount returns total edges
	EdgeCount() (int64, error)
}

QueryDatabase is the interface for executing Cypher queries.

type QueryExecutor

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

QueryExecutor provides read-only database access for Heimdall actions.

func NewQueryExecutor

func NewQueryExecutor(db QueryDatabase, timeout time.Duration) *QueryExecutor

NewQueryExecutor creates a query executor with the given database.

func NewQueryExecutorWithSearch

func NewQueryExecutorWithSearch(db QueryDatabase, searcher SemanticSearcher, embedder Embedder, timeout time.Duration) *QueryExecutor

NewQueryExecutorWithSearch creates a query executor with semantic search support.

func (*QueryExecutor) Discover

func (e *QueryExecutor) Discover(ctx context.Context, query string, nodeTypes []string, limit int, depth int) (*DiscoverResult, error)

Discover implements DatabaseReader.Discover for semantic search.

func (*QueryExecutor) Query

func (e *QueryExecutor) Query(ctx context.Context, cypher string, params map[string]interface{}) ([]map[string]interface{}, error)

Query implements DatabaseReader.Query

func (*QueryExecutor) Stats

func (e *QueryExecutor) Stats() DatabaseStats

Stats implements DatabaseReader.Stats

type QueryMetrics

type QueryMetrics struct {
	TotalQueries     int64         `json:"total_queries"`
	SlowQueries      int64         `json:"slow_queries"`
	AvgExecutionTime time.Duration `json:"avg_execution_time"`
	CacheHitRate     float64       `json:"cache_hit_rate"`
	ThresholdMs      int64         `json:"threshold_ms"`
}

QueryMetrics contains Cypher query statistics.

type QueuedNotification

type QueuedNotification struct {
	Type    string `json:"type"` // "info", "warning", "error", "success", "progress"
	Title   string `json:"title"`
	Message string `json:"message"`
}

QueuedNotification represents a notification waiting to be sent inline.

type RealMetricsReader

type RealMetricsReader struct{}

RealMetricsReader provides actual runtime metrics.

func (*RealMetricsReader) Runtime

func (r *RealMetricsReader) Runtime() RuntimeMetrics

Runtime returns current runtime metrics.

type RelatedNode

type RelatedNode struct {
	ID           string `json:"id"`
	Type         string `json:"type,omitempty"`
	Title        string `json:"title,omitempty"`
	Distance     int    `json:"distance"`            // Hops from the source node
	Relationship string `json:"relationship"`        // Relationship type
	Direction    string `json:"direction,omitempty"` // "incoming", "outgoing", or ""
	Path         string `json:"path,omitempty"`      // Path description
}

RelatedNode represents a node connected to a search result.

type RuntimeMetrics

type RuntimeMetrics struct {
	GoroutineCount int    `json:"goroutine_count"`
	MemoryAllocMB  uint64 `json:"memory_alloc_mb"`
	NumGC          uint32 `json:"num_gc"`
}

RuntimeMetrics contains runtime statistics.

type SchemaManagerStats

type SchemaManagerStats interface {
	GetIndexStats() interface{}
}

SchemaManagerStats is the interface for schema/index metrics.

type SearchResult

type SearchResult struct {
	ID             string                 `json:"id"`
	Type           string                 `json:"type"`
	Title          string                 `json:"title,omitempty"`
	ContentPreview string                 `json:"content_preview,omitempty"`
	Similarity     float64                `json:"similarity"`
	Properties     map[string]interface{} `json:"properties,omitempty"`
	Related        []RelatedNode          `json:"related,omitempty"`
}

SearchResult represents a single search result with similarity and related nodes.

type SemanticSearchResult

type SemanticSearchResult struct {
	ID         string
	Labels     []string
	Properties map[string]interface{}
	Score      float64
}

SemanticSearchResult is the result of a semantic search operation.

type SemanticSearcher

type SemanticSearcher interface {
	// HybridSearch performs vector + text search with pre-computed embedding
	HybridSearch(ctx context.Context, query string, queryEmbedding []float32, labels []string, limit int) ([]*SemanticSearchResult, error)
	// Search performs full-text BM25 search
	Search(ctx context.Context, query string, labels []string, limit int) ([]*SemanticSearchResult, error)
	// Neighbors returns connected node IDs
	Neighbors(ctx context.Context, nodeID string) ([]string, error)
	// GetEdgesForNode returns edges for a node
	GetEdgesForNode(ctx context.Context, nodeID string) ([]*GraphEdge, error)
	// GetNode retrieves a node by ID
	GetNode(ctx context.Context, nodeID string) (*NodeData, error)
}

SemanticSearcher is an optional interface for databases that support semantic search. QueryDatabase implementations may optionally implement this for vector search.

type ServerMetrics

type ServerMetrics struct {
	Uptime         time.Duration `json:"uptime"`
	RequestsTotal  int64         `json:"requests_total"`
	ErrorsTotal    int64         `json:"errors_total"`
	ActiveRequests int64         `json:"active_requests"`
	SlowQueryCount int64         `json:"slow_query_count"`
	RequestsPerSec float64       `json:"requests_per_sec"`
}

ServerMetrics contains HTTP server statistics.

type ServerMetricsSource

type ServerMetricsSource interface {
	Stats() interface{}
	SlowQueryCount() int64
}

ServerMetricsSource is the interface for collecting server metrics.

type StorageMetrics

type StorageMetrics struct {
	// Async engine stats
	PendingWrites int64 `json:"pending_writes"`
	TotalFlushes  int64 `json:"total_flushes"`

	// WAL stats
	WALSequence    uint64    `json:"wal_sequence"`
	WALEntries     uint64    `json:"wal_entries"`
	WALBytes       uint64    `json:"wal_bytes"`
	WALTotalWrites uint64    `json:"wal_total_writes"`
	WALTotalSyncs  uint64    `json:"wal_total_syncs"`
	WALLastSync    time.Time `json:"wal_last_sync"`

	// Node config stats
	NodeConfigs    int64   `json:"node_configs"`
	ConfigChecks   int64   `json:"config_checks"`
	ConfigsBlocked int64   `json:"configs_blocked"`
	BlockRate      float64 `json:"block_rate"`

	// Edge meta stats
	EdgeMetaRecords      int64            `json:"edge_meta_records"`
	EdgeMetaMaterialized int64            `json:"edge_meta_materialized"`
	EdgeMetaBySignal     map[string]int64 `json:"edge_meta_by_signal,omitempty"`
}

StorageMetrics contains storage engine statistics.

type StreamEvent

type StreamEvent struct {
	Event string `json:"event,omitempty"` // "message", "done", "error"
	Data  string `json:"data"`
}

StreamEvent represents a Server-Sent Event for streaming.

type SubsystemContext

type SubsystemContext struct {
	// Config is the Heimdall configuration
	Config Config

	// Database routes Cypher/search operations across logical databases.
	// This is multi-database aware (Neo4j 4.x style) and should be used instead of
	// relying on a single default database.
	Database DatabaseRouter

	// Metrics provides runtime metrics
	Metrics MetricsReader

	// Logger for subsystem logging
	Logger SubsystemLogger

	// Bifrost provides the communication bridge to connected clients
	// Plugins can use this to send messages, notifications, and request input
	Bifrost BifrostBridge

	// Heimdall provides autonomous action invocation for plugins.
	// Plugins can use this to trigger actions or send prompts to the SLM
	// based on accumulated events or other triggers.
	Heimdall HeimdallInvoker
}

SubsystemContext is provided to plugins during initialization.

type SubsystemEvent

type SubsystemEvent struct {
	Time    time.Time              `json:"time"`
	Type    string                 `json:"type"` // "info", "warning", "error", "action"
	Message string                 `json:"message"`
	Data    map[string]interface{} `json:"data,omitempty"`
}

SubsystemEvent represents a notable event from a subsystem.

type SubsystemHealth

type SubsystemHealth struct {
	Status    SubsystemStatus        `json:"status"`
	Healthy   bool                   `json:"healthy"`
	Message   string                 `json:"message,omitempty"`
	LastCheck time.Time              `json:"last_check"`
	Details   map[string]interface{} `json:"details,omitempty"`
}

SubsystemHealth contains detailed health information.

type SubsystemLogger

type SubsystemLogger interface {
	Debug(msg string, args ...interface{})
	Info(msg string, args ...interface{})
	Warn(msg string, args ...interface{})
	Error(msg string, args ...interface{})
}

SubsystemLogger is the logging interface for subsystems.

type SubsystemManager

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

SubsystemManager manages all SLM plugins/subsystems. Provides the SLM with full control over registered subsystems.

func GetSubsystemManager

func GetSubsystemManager() *SubsystemManager

GetSubsystemManager returns the global subsystem manager (creates if needed).

func (*SubsystemManager) AllHealth

func (m *SubsystemManager) AllHealth() map[string]SubsystemHealth

AllHealth returns health status of all subsystems.

func (*SubsystemManager) AllSummaries

func (m *SubsystemManager) AllSummaries() map[string]string

AllSummaries returns summaries of all subsystems (for SLM context).

func (*SubsystemManager) GetAction

func (m *SubsystemManager) GetAction(name string) (ActionFunc, bool)

GetAction returns an action by full name (e.g., "heimdall_plugin_action").

func (*SubsystemManager) GetPlugin

func (m *SubsystemManager) GetPlugin(name string) (HeimdallPlugin, bool)

GetPlugin returns a plugin by name.

func (*SubsystemManager) RegisterPlugin

func (m *SubsystemManager) RegisterPlugin(p HeimdallPlugin, path string, builtin bool) error

RegisterPlugin registers an SLM plugin and initializes it.

func (*SubsystemManager) SetContext

func (m *SubsystemManager) SetContext(ctx SubsystemContext)

SetContext configures the shared context for all subsystems.

func (*SubsystemManager) ShutdownAll

func (m *SubsystemManager) ShutdownAll() error

ShutdownAll shuts down all registered subsystems.

func (*SubsystemManager) StartAll

func (m *SubsystemManager) StartAll() error

StartAll starts all registered subsystems.

func (*SubsystemManager) StopAll

func (m *SubsystemManager) StopAll() error

StopAll stops all registered subsystems.

type SubsystemStatus

type SubsystemStatus string

SubsystemStatus represents the current state of a subsystem.

const (
	StatusUninitialized SubsystemStatus = "uninitialized"
	StatusInitializing  SubsystemStatus = "initializing"
	StatusReady         SubsystemStatus = "ready"
	StatusRunning       SubsystemStatus = "running"
	StatusStopping      SubsystemStatus = "stopping"
	StatusStopped       SubsystemStatus = "stopped"
	StatusError         SubsystemStatus = "error"
)

type SynthesisContext

type SynthesisContext struct {
	// Context carries request cancellation and deadlines.
	Context context.Context

	// RequestID for tracking
	RequestID string

	// UserQuestion is the original user message
	UserQuestion string

	// Action that was executed
	Action string

	// Result from the action execution
	Result *ActionResult

	// PluginData from earlier phases
	PluginData map[string]interface{}

	// Database routes Cypher/search operations across logical databases.
	Database DatabaseRouter
}

SynthesisContext provides context for response synthesis.

type SynthesisHook

type SynthesisHook interface {
	// Synthesize transforms action results into a user-friendly response.
	//
	// Return values:
	//   - Non-empty string: Use this as the final response (skips default synthesis)
	//   - Empty string: Continue with default LLM-based synthesis
	//
	// The done callback MUST be called when complete.
	Synthesize(ctx *SynthesisContext, done func(response string))
}

SynthesisHook is an optional interface for plugins that want to customize how action results are presented to users. This is called AFTER PostExecute but BEFORE the response is sent to the user.

Plugins can use this to:

  • Provide domain-specific formatting (e.g., format POC data nicely)
  • Add custom context or explanations
  • Transform data into more user-friendly formats
  • Skip synthesis entirely and return raw data

type TokenBudget

type TokenBudget struct {
	MaxContext int // Total context window
	MaxSystem  int // System prompt budget
	MaxUser    int // User message budget
}

TokenBudget holds the configurable token limits for prompt construction. Use GetTokenBudget() to get the current budget from config.

func GetTokenBudget

func GetTokenBudget() TokenBudget

GetTokenBudget returns the current token budget.

type ToolRoundMessage

type ToolRoundMessage struct {
	Role       string           // "system", "user", "assistant", "tool"
	Content    string           // For tool role: the result content (e.g. JSON or text)
	ToolCalls  []ParsedToolCall // For assistant: tool invocations from the model
	ToolCallID string           // For tool role: which call this result is for (OpenAI id)
}

ToolRoundMessage is one message in an agentic conversation (system, user, assistant, or tool result). Used for the tool-calling loop: after executing tools, handler appends assistant message (with ToolCalls) and tool result messages (Role "tool", ToolCallID, Content), then calls again.

type WALStats

type WALStats interface {
	Stats() interface{}
}

WALStats is the interface for WAL metrics.

Jump to

Keyboard shortcuts

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