mood

package
v0.32.0 Latest Latest
Warning

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

Go to latest
Published: Sep 5, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package mood detects interaction *friction* — how a user is engaging with the agent — from their terminal input, using a deterministic, dependency-free lexical heuristic. No model, no network, no surprise deps (consistent with memcode's local-first doctrine and the BM25-over-embeddings choice for recall).

This is NOT a personality judgment about the user. It is a control signal: a rising friction reading (caps, expletives, "still broken", repeated corrections, interrupts, denials) usually means the agent is on the wrong track and should change strategy. And the *intensity* of a direction is part of its meaning — an instruction given with force ("do NOT add a paid vendor") is a stronger, more durable constraint than a calm aside, so memcode records the intensity alongside the direction and weighs it later.

Index

Constants

This section is empty.

Variables

View Source
var W = struct {
	Caps, Expl, Neg, Punct, Rep, RepWord, Density, Combo, Directed, Pos float64
}{
	Caps: 0.5, Expl: 0.65, Neg: 0.55, Punct: 0.4, Rep: 0.3, RepWord: 0.25,
	Density: 0.2, Combo: 0.25, Directed: 0.1, Pos: 0.7,
}

W is the tunable feature-weight table for friction scoring — kept in one place (not scattered through conditionals) so the model can be calibrated easily.

Functions

func Friction

func Friction(s State) string

Friction collapses a state into the product-facing gauge level shown in the TUI: low (proceed normally), elevated (slow down / clarify), high (stop and repair). Deliberately not an emoji mood — it's about the work, not the person.

Types

type Cadence

type Cadence struct {
	InterMessageMs  int64 `json:"inter_message_ms"`           // gap since the previous turn (0 = first)
	Chars           int   `json:"chars"`                      // message length
	Words           int   `json:"words"`                      //
	Burst           bool  `json:"burst,omitempty"`            // arrived right after the previous turn
	RapidCorrection bool  `json:"rapid_correction,omitempty"` // a quick corrective follow-up → repair
	LongPause       bool  `json:"long_pause,omitempty"`       // big gap → possibly a new topic
}

Cadence is the timing shape of a turn — a subtle but real interaction signal. Three short messages fired off in five seconds is a different state than one calm, considered prompt. We capture only DERIVED aggregates (never raw keystrokes — that gets creepy fast): the gap since the last turn, size, and a few booleans the runtime uses for routing + friction.

type CadenceTracker

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

CadenceTracker derives per-turn timing features from message arrival times.

func NewCadenceTracker

func NewCadenceTracker() *CadenceTracker

NewCadenceTracker returns a tracker using the wall clock.

func (*CadenceTracker) Observe

func (c *CadenceTracker) Observe(text string, corrective bool) Cadence

Observe records a turn's arrival and returns its cadence. corrective signals the turn is a correction/negation (from routing or friction), so a quick follow-up is flagged as a rapid correction (a strong "we're off track" cue).

type Reading

type Reading struct {
	Valence     float64  `json:"valence"`
	Intensity   float64  `json:"intensity"`
	Frustration float64  `json:"frustration"`
	State       State    `json:"state"`
	Signals     []string `json:"signals,omitempty"`
}

Reading is the friction charge of one piece of text (or a smoothed aggregate). Valence is -1..+1; Intensity and Frustration are 0..1.

func Score

func Score(text string) Reading

Score reads a single turn of text.

type State

type State string

State is the interaction state inferred for a turn (or the running aggregate).

const (
	Calm        State = "calm"        // positive / satisfied
	Focused     State = "focused"     // neutral, working — the default
	Curious     State = "curious"     // exploratory: "what if", "I wonder", "how does X work"
	Confused    State = "confused"    // uncertainty, questions, "what / huh / unclear"
	Frustrated  State = "frustrated"  // negative, exasperated
	Angry       State = "angry"       // peak friction: caps + expletives + blame
	Urgent      State = "urgent"      // time pressure: now / asap / immediately
	Discouraged State = "discouraged" // low-energy defeat about the WORK ("stuck", "give up")
)

type Tracker

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

Tracker keeps a smoothed running friction across a session so the gauge reflects the general interaction rather than one stray message, and detects repeated corrections (the same complaint twice = the agent really isn't listening, which should raise friction).

func NewTracker

func NewTracker() *Tracker

NewTracker returns a Tracker with sensible smoothing.

func (*Tracker) Bump

func (t *Tracker) Bump(amount float64, signal string) Reading

Bump nudges friction up for a non-textual signal the runtime observes (an interrupt route, an approval denial) and returns the updated aggregate.

func (*Tracker) Current

func (t *Tracker) Current() Reading

Current returns the smoothed reading.

func (*Tracker) Observe

func (t *Tracker) Observe(r Reading, raw string) Reading

Observe folds a turn into the running aggregate. raw is the original text, used to detect repeated corrections. Returns the smoothed reading.

Jump to

Keyboard shortcuts

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