@backbay/glia-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cognition/types.ts","../src/cognition/schema.ts","../src/cognition/reducers.ts","../src/cognition/controller.ts","../src/cognition/hooks/useCognition.ts"],"sourcesContent":["import type { AVO } from '../emotion/types.js';\n\n// =============================================================================\n// Cognitive Mode\n// =============================================================================\n\nexport type CognitiveMode =\n | 'idle'\n | 'listening'\n | 'deliberating'\n | 'acting'\n | 'explaining'\n | 'recovering'\n | 'blocked';\n\nexport type CognitiveSubmode =\n | 'reading'\n | 'searching'\n | 'verifying'\n | 'waiting'\n | 'writing'\n | 'tool_call';\n\n// =============================================================================\n// Continuous Signals (all normalized 0..1)\n// =============================================================================\n\nexport interface CognitionSignals {\n attention: number;\n workload: number;\n timePressure: number;\n planDrift: number;\n costPressure: number;\n risk: number;\n uncertainty: number;\n confidence: number;\n errorStress: number;\n}\n\n// =============================================================================\n// Persona Signals\n// =============================================================================\n\nexport interface PersonaSignals {\n personaAnchor: number;\n personaDriftRisk: number;\n personaStyle?: string[];\n}\n\n// =============================================================================\n// Dynamics (kernel integration)\n// =============================================================================\n\nexport interface TrapWarning {\n stateId: string;\n reason: string;\n recommendation: string;\n severity?: 'info' | 'warning' | 'danger';\n}\n\nexport interface DetailedBalance {\n chi2PerNdf: number;\n passed: boolean;\n threshold: number;\n}\n\nexport interface DynamicsState {\n potentialV?: number;\n actionRate?: number;\n detailedBalance?: DetailedBalance;\n traps?: TrapWarning[];\n}\n\n// =============================================================================\n// Personality + Policy (cockpit integration)\n// =============================================================================\n\nexport interface PersonalityConfig {\n style: 'professional' | 'casual' | 'terse' | 'verbose';\n riskTolerance: 'conservative' | 'moderate' | 'aggressive';\n autonomy: 'low' | 'medium' | 'high' | 'full';\n}\n\nexport interface PolicyConfig {\n safetyMode: boolean;\n trustTier?: string;\n}\n\n// =============================================================================\n// Evidence (verification-first)\n// =============================================================================\n\nexport type EvidenceRef =\n | { type: 'run'; runId: string }\n | { type: 'run_receipt'; receiptHash: string }\n | { type: 'artifact'; path: string; digest?: string }\n | { type: 'ui'; componentId: string; note?: string };\n\n// =============================================================================\n// Full Cognition State\n// =============================================================================\n\nexport interface CognitionState extends CognitionSignals, PersonaSignals {\n mode: CognitiveMode;\n submode?: CognitiveSubmode;\n focusRunId?: string;\n\n dynamics?: DynamicsState;\n personality?: PersonalityConfig;\n policy?: PolicyConfig;\n\n moodAVO: AVO;\n emotionAVO: AVO;\n}\n\n// =============================================================================\n// Cognition Events\n// =============================================================================\n\nexport type CognitionEvent =\n | { type: 'ui.input_received'; intensity?: number }\n | { type: 'ui.user_idle' }\n | { type: 'ui.interrupt'; intensity?: number }\n | { type: 'run.event'; runId: string; status: string; progress?: number }\n | { type: 'run.started'; runId: string }\n | { type: 'run.completed'; runId: string; success: boolean }\n | { type: 'intensity.update'; values: Partial<CognitionSignals> }\n | { type: 'signals.update'; signals: Partial<CognitionSignals> }\n | { type: 'dynamics.update'; dynamics: DynamicsState }\n | { type: 'policy.update'; policy?: PolicyConfig; personality?: PersonalityConfig }\n | { type: 'text.user_message'; text: string; categories?: string[] }\n | { type: 'tick'; deltaMs: number };\n\n// =============================================================================\n// Cognition Snapshot (serialization)\n// =============================================================================\n\nexport interface CognitionSnapshot {\n version: '1.0';\n timestamp: number;\n state: CognitionState;\n recentEvents?: Array<{ t: number; event: CognitionEvent }>;\n}\n\n// =============================================================================\n// Helpers\n// =============================================================================\n\nexport function clamp01(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n\nconst DEFAULT_AVO: AVO = { arousal: 0.25, valence: 0.6, openness: 0.35 };\n\nexport function createInitialCognitionState(\n overrides?: Partial<CognitionState>\n): CognitionState {\n return {\n mode: 'idle',\n attention: 0.3,\n workload: 0,\n timePressure: 0,\n planDrift: 0,\n costPressure: 0,\n risk: 0,\n uncertainty: 0.2,\n confidence: 0.8,\n errorStress: 0,\n personaAnchor: 1,\n personaDriftRisk: 0,\n moodAVO: { ...DEFAULT_AVO },\n emotionAVO: { ...DEFAULT_AVO },\n ...overrides,\n };\n}\n","import { z } from 'zod';\n\n// =============================================================================\n// Primitives\n// =============================================================================\n\nconst Signal01 = z.number().min(0).max(1);\n\nconst CognitiveModeSchema = z.enum([\n 'idle',\n 'listening',\n 'deliberating',\n 'acting',\n 'explaining',\n 'recovering',\n 'blocked',\n]);\n\nconst CognitiveSubmodeSchema = z.enum([\n 'reading',\n 'searching',\n 'verifying',\n 'waiting',\n 'writing',\n 'tool_call',\n]);\n\nconst AVOSchema = z.object({\n arousal: Signal01,\n valence: Signal01,\n openness: Signal01,\n});\n\n// =============================================================================\n// Sub-objects\n// =============================================================================\n\nconst TrapWarningSchema = z.object({\n stateId: z.string(),\n reason: z.string(),\n recommendation: z.string(),\n severity: z.enum(['info', 'warning', 'danger']).optional(),\n});\n\nconst DetailedBalanceSchema = z.object({\n chi2PerNdf: z.number(),\n passed: z.boolean(),\n threshold: z.number(),\n});\n\nconst DynamicsStateSchema = z.object({\n potentialV: z.number().optional(),\n actionRate: Signal01.optional(),\n detailedBalance: DetailedBalanceSchema.optional(),\n traps: z.array(TrapWarningSchema).optional(),\n});\n\nconst PersonalityConfigSchema = z.object({\n style: z.enum(['professional', 'casual', 'terse', 'verbose']),\n riskTolerance: z.enum(['conservative', 'moderate', 'aggressive']),\n autonomy: z.enum(['low', 'medium', 'high', 'full']),\n});\n\nconst PolicyConfigSchema = z.object({\n safetyMode: z.boolean(),\n trustTier: z.string().optional(),\n});\n\n// =============================================================================\n// CognitionState\n// =============================================================================\n\nexport const CognitionStateSchema = z.object({\n mode: CognitiveModeSchema,\n submode: CognitiveSubmodeSchema.optional(),\n focusRunId: z.string().optional(),\n\n attention: Signal01,\n workload: Signal01,\n timePressure: Signal01,\n planDrift: Signal01,\n costPressure: Signal01,\n risk: Signal01,\n uncertainty: Signal01,\n confidence: Signal01,\n errorStress: Signal01,\n\n personaAnchor: Signal01,\n personaDriftRisk: Signal01,\n personaStyle: z.array(z.string()).optional(),\n\n dynamics: DynamicsStateSchema.optional(),\n personality: PersonalityConfigSchema.optional(),\n policy: PolicyConfigSchema.optional(),\n\n moodAVO: AVOSchema,\n emotionAVO: AVOSchema,\n});\n\n// =============================================================================\n// CognitionSnapshot\n// =============================================================================\n\nexport const CognitionSnapshotSchema = z.object({\n version: z.literal('1.0'),\n timestamp: z.number(),\n state: CognitionStateSchema,\n recentEvents: z\n .array(\n z.object({\n t: z.number(),\n event: z.record(z.unknown()),\n })\n )\n .optional(),\n});\n\n// =============================================================================\n// Validation helpers\n// =============================================================================\n\nexport type CognitionSnapshotInput = z.input<typeof CognitionSnapshotSchema>;\nexport type CognitionSnapshotOutput = z.output<typeof CognitionSnapshotSchema>;\n\nexport interface CognitionSnapshotValidationResult {\n success: boolean;\n data?: CognitionSnapshotOutput;\n error?: z.ZodError;\n}\n\nexport function validateCognitionSnapshot(\n input: unknown\n): CognitionSnapshotValidationResult {\n const result = CognitionSnapshotSchema.safeParse(input);\n if (result.success) {\n return { success: true, data: result.data };\n }\n return { success: false, error: result.error };\n}\n","// packages/bb-ui/src/cognition/reducers.ts\n\n/**\n * Cognition State Reducers\n *\n * Pure functions for updating cognition state based on events and time decay.\n */\n\nimport type {\n CognitionState,\n CognitionEvent,\n CognitiveMode,\n CognitionSignals,\n DynamicsState,\n PolicyConfig,\n PersonalityConfig,\n} from './types.js';\nimport { clamp01 } from './types.js';\n\n/**\n * Trigger types that cause mode transitions\n */\nexport type CognitionTrigger =\n | 'ui.input_received'\n | 'ui.user_idle'\n | 'ui.interrupt'\n | 'run.started'\n | 'run.completed'\n | 'run.event';\n\n/**\n * Maps trigger events to resulting cognitive modes\n */\nexport const MODE_TRANSITION_MAP: Record<CognitionTrigger, CognitiveMode> = {\n 'ui.input_received': 'listening',\n 'ui.user_idle': 'idle',\n 'ui.interrupt': 'listening',\n 'run.started': 'deliberating',\n 'run.completed': 'idle',\n 'run.event': 'deliberating',\n};\n\n/**\n * Decay rates per second for various signals\n */\nexport const DECAY_RATES: Record<'errorStress' | 'timePressure' | 'planDrift', number> = {\n errorStress: 0.1, // Decays 10% per second\n timePressure: 0.05, // Decays 5% per second\n planDrift: 0.08, // Decays 8% per second\n};\n\n/**\n * Reduce signals from a signals.update event\n */\nfunction reduceSignals(\n state: CognitionState,\n signals: Partial<CognitionSignals>\n): CognitionState {\n return {\n ...state,\n attention: signals.attention !== undefined ? clamp01(signals.attention) : state.attention,\n workload: signals.workload !== undefined ? clamp01(signals.workload) : state.workload,\n risk: signals.risk !== undefined ? clamp01(signals.risk) : state.risk,\n timePressure: signals.timePressure !== undefined ? clamp01(signals.timePressure) : state.timePressure,\n errorStress: signals.errorStress !== undefined ? clamp01(signals.errorStress) : state.errorStress,\n planDrift: signals.planDrift !== undefined ? clamp01(signals.planDrift) : state.planDrift,\n costPressure: signals.costPressure !== undefined ? clamp01(signals.costPressure) : state.costPressure,\n uncertainty: signals.uncertainty !== undefined ? clamp01(signals.uncertainty) : state.uncertainty,\n confidence: signals.confidence !== undefined ? clamp01(signals.confidence) : state.confidence,\n };\n}\n\n/**\n * Reduce dynamics state update\n */\nfunction reduceDynamicsUpdate(\n state: CognitionState,\n dynamics: DynamicsState\n): CognitionState {\n return {\n ...state,\n dynamics,\n };\n}\n\n/**\n * Reduce policy/personality update\n */\nfunction reducePolicyUpdate(\n state: CognitionState,\n policy?: PolicyConfig,\n personality?: PersonalityConfig\n): CognitionState {\n return {\n ...state,\n policy: policy ?? state.policy,\n personality: personality ?? state.personality,\n };\n}\n\n/**\n * Reduce mode transitions based on events\n */\nfunction reduceModeTransition(\n state: CognitionState,\n event: CognitionEvent\n): CognitionState {\n const trigger = event.type as CognitionTrigger;\n const newMode = MODE_TRANSITION_MAP[trigger];\n\n if (!newMode) {\n return state;\n }\n\n let focusRunId = state.focusRunId;\n let errorStress = state.errorStress;\n let mode = newMode;\n\n // Handle run-related events\n if (event.type === 'run.started') {\n focusRunId = event.runId;\n } else if (event.type === 'run.completed') {\n focusRunId = undefined;\n if (!event.success) {\n errorStress = clamp01(state.errorStress + 0.2);\n mode = 'recovering';\n }\n } else if (event.type === 'run.event') {\n focusRunId = event.runId;\n }\n\n return {\n ...state,\n mode,\n focusRunId,\n errorStress,\n };\n}\n\n/**\n * Apply exponential decay to time-based signals\n */\nexport function reduceDecay(\n state: CognitionState,\n deltaMs: number\n): CognitionState {\n const deltaSec = deltaMs / 1000;\n\n // Exponential decay: value * e^(-rate * time)\n const errorStress = clamp01(\n state.errorStress * Math.exp(-DECAY_RATES.errorStress * deltaSec)\n );\n const timePressure = clamp01(\n state.timePressure * Math.exp(-DECAY_RATES.timePressure * deltaSec)\n );\n const planDrift = clamp01(\n state.planDrift * Math.exp(-DECAY_RATES.planDrift * deltaSec)\n );\n\n return {\n ...state,\n errorStress,\n timePressure,\n planDrift,\n };\n}\n\n/**\n * Main event reducer - handles all cognition events\n */\nexport function reduceEvent(\n state: CognitionState,\n event: CognitionEvent\n): CognitionState {\n switch (event.type) {\n case 'signals.update':\n return reduceSignals(state, event.signals);\n\n case 'intensity.update':\n return reduceSignals(state, event.values);\n\n case 'dynamics.update':\n return reduceDynamicsUpdate(state, event.dynamics);\n\n case 'policy.update':\n return reducePolicyUpdate(state, event.policy, event.personality);\n\n case 'tick':\n return reduceDecay(state, event.deltaMs);\n\n case 'ui.input_received':\n case 'ui.user_idle':\n case 'ui.interrupt':\n case 'run.started':\n case 'run.completed':\n case 'run.event':\n return reduceModeTransition(state, event);\n\n case 'text.user_message': {\n // Text messages transition to listening mode and update persona drift risk\n // based on message categories per spec section 7.5\n const categories = event.categories ?? [];\n const driftRisk = categories.includes('meta_reflection')\n ? 0.3\n : categories.includes('vulnerable_disclosure')\n ? 0.4\n : 0;\n\n // Exponential smoothing: 70% previous, 30% new\n const newPersonaDriftRisk = clamp01(\n state.personaDriftRisk * 0.7 + driftRisk * 0.3\n );\n\n return {\n ...state,\n mode: 'listening',\n personaDriftRisk: newPersonaDriftRisk,\n };\n }\n\n default: {\n // Exhaustive check - TypeScript will error if we miss a case\n const _exhaustive: never = event;\n return state;\n }\n }\n}\n","// packages/bb-ui/src/cognition/controller.ts\n\n/**\n * CognitionController manages the cognitive state lifecycle for the Glyph character.\n *\n * It handles:\n * - Cognitive mode transitions (idle, listening, deliberating, acting, etc.)\n * - Continuous signal processing (attention, workload, risk, etc.)\n * - Event-driven state changes from UI and kernel events\n * - Emotion bridge (mood and emotion AVO dimensions)\n * - Time-based decay of stress signals\n */\n\nimport type { AVO, AnchorState } from '../emotion/types.js';\nimport type {\n CognitionState,\n CognitionEvent,\n CognitiveMode,\n} from './types.js';\nimport { createInitialCognitionState } from './types.js';\nimport { reduceEvent, reduceDecay } from './reducers.js';\n\n// =============================================================================\n// Mode Mappings\n// =============================================================================\n\n/**\n * Maps cognitive modes to emotion anchor states for visual representation\n */\nexport const MODE_TO_ANCHOR: Record<CognitiveMode, AnchorState> = {\n idle: 'idle',\n listening: 'listening',\n deliberating: 'thinking',\n acting: 'focused',\n explaining: 'explaining',\n recovering: 'recovering',\n blocked: 'concerned',\n};\n\n/**\n * Default AVO values for each cognitive mode\n * These are the target emotional states for each mode\n */\nexport const MODE_TO_AVO: Record<CognitiveMode, AVO> = {\n idle: { arousal: 0.25, valence: 0.60, openness: 0.35 },\n listening: { arousal: 0.45, valence: 0.70, openness: 0.05 },\n deliberating: { arousal: 0.60, valence: 0.60, openness: 0.40 },\n acting: { arousal: 0.70, valence: 0.70, openness: 0.50 },\n explaining: { arousal: 0.55, valence: 0.80, openness: 0.85 },\n recovering: { arousal: 0.40, valence: 0.45, openness: 0.40 },\n blocked: { arousal: 0.55, valence: 0.30, openness: 0.30 },\n};\n\n// =============================================================================\n// Types\n// =============================================================================\n\ntype EventHandler<T> = (data: T) => void;\n\nexport interface CognitionControllerEvents {\n /** Emitted when any state change occurs */\n change: CognitionState;\n /** Emitted when mode changes */\n modeChange: { from: CognitiveMode; to: CognitiveMode };\n}\n\nexport interface CognitionControllerOptions {\n /** Initial state overrides */\n initial?: Partial<CognitionState>;\n}\n\nexport interface EmotionTarget {\n /** The anchor state name for the current mode */\n anchor: AnchorState;\n /** The target AVO values adjusted by signals */\n avo: AVO;\n}\n\n/**\n * CognitionController manages the cognitive state lifecycle for the Glyph character.\n */\nexport class CognitionController {\n private _state: CognitionState;\n private _listeners: Map<keyof CognitionControllerEvents, Set<EventHandler<unknown>>> = new Map();\n private _disposed: boolean = false;\n\n constructor(options: CognitionControllerOptions = {}) {\n this._state = createInitialCognitionState(options.initial);\n }\n\n /**\n * Get current cognition state\n */\n getState(): CognitionState {\n return { ...this._state };\n }\n\n /**\n * Get the emotion target for the current cognitive state\n * Returns anchor state and AVO values adjusted by signals\n */\n getEmotionTarget(): EmotionTarget {\n const anchor = MODE_TO_ANCHOR[this._state.mode];\n const baseAVO = MODE_TO_AVO[this._state.mode];\n\n // Adjust AVO based on signals\n const avo = this._adjustAVOBySignals(baseAVO);\n\n return { anchor, avo };\n }\n\n /**\n * Get emotion bridge - derives anchor and AVO from cognitive state\n * @deprecated Use getEmotionTarget() instead\n */\n getEmotionBridge(): { anchor?: AnchorState; avo?: AVO } {\n const target = this.getEmotionTarget();\n return { anchor: target.anchor, avo: target.avo };\n }\n\n /**\n * Handle a cognition event and update state\n */\n handleEvent(event: CognitionEvent): void {\n if (this._disposed) return;\n\n const prevMode = this._state.mode;\n this._state = reduceEvent(this._state, event);\n\n if (this._state.mode !== prevMode) {\n this._emitEvent('modeChange', { from: prevMode, to: this._state.mode });\n }\n\n this._emitEvent('change', this._state);\n }\n\n /**\n * Process an event and update state\n * @deprecated Use handleEvent() instead\n */\n emit(event: CognitionEvent): void {\n this.handleEvent(event);\n }\n\n /**\n * Update tick - call each frame with delta time in milliseconds\n * Applies time-based decay to stress signals\n */\n tick(deltaMs: number): void {\n if (this._disposed) return;\n\n const prevState = this._state;\n this._state = reduceDecay(this._state, deltaMs);\n\n // Only emit change if state actually changed\n if (\n prevState.errorStress !== this._state.errorStress ||\n prevState.timePressure !== this._state.timePressure ||\n prevState.planDrift !== this._state.planDrift\n ) {\n this._emitEvent('change', this._state);\n }\n }\n\n /**\n * Subscribe to controller events\n * Returns unsubscribe function\n */\n on<K extends keyof CognitionControllerEvents>(\n event: K,\n handler: EventHandler<CognitionControllerEvents[K]>\n ): () => void {\n if (!this._listeners.has(event)) {\n this._listeners.set(event, new Set());\n }\n this._listeners.get(event)!.add(handler as EventHandler<unknown>);\n\n return () => {\n this._listeners.get(event)?.delete(handler as EventHandler<unknown>);\n };\n }\n\n /**\n * Dispose controller and clean up resources\n */\n dispose(): void {\n this._disposed = true;\n this._listeners.clear();\n }\n\n /**\n * Adjust AVO values based on current signal levels\n */\n private _adjustAVOBySignals(baseAVO: AVO): AVO {\n const { errorStress, workload, timePressure, uncertainty, confidence, personaDriftRisk } = this._state;\n\n // Arousal increases with workload, time pressure, and error stress\n const arousalBoost = (workload * 0.2) + (timePressure * 0.15) + (errorStress * 0.1);\n\n // Valence decreases with error stress and uncertainty\n const valenceDrops = (errorStress * 0.3) + (uncertainty * 0.15);\n const valenceBoost = (confidence - 0.5) * 0.2; // Confidence above 0.5 boosts valence\n\n // Openness decreases with persona drift risk (more grounded when drift risk is high)\n // Per spec section 7.6: high drift risk should reduce openness to signal groundedness\n const opennessDrop = personaDriftRisk * 0.3;\n\n return {\n arousal: Math.max(0, Math.min(1, baseAVO.arousal + arousalBoost)),\n valence: Math.max(0, Math.min(1, baseAVO.valence - valenceDrops + valenceBoost)),\n openness: Math.max(0, Math.min(1, baseAVO.openness - opennessDrop)),\n };\n }\n\n private _emitEvent<K extends keyof CognitionControllerEvents>(\n event: K,\n data: CognitionControllerEvents[K]\n ): void {\n this._listeners.get(event)?.forEach((handler) => handler(data));\n }\n}\n","'use client';\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport type { AVO, AnchorState } from '../../emotion/types.js';\nimport type { CognitionState, CognitionEvent } from '../types.js';\nimport { CognitionController, type CognitionControllerOptions, type EmotionTarget } from '../controller.js';\n\nexport interface UseCognitionOptions extends CognitionControllerOptions {\n onChange?: (state: CognitionState) => void;\n autoTick?: boolean;\n}\n\nexport interface UseCognitionResult {\n state: CognitionState;\n emotion: EmotionTarget;\n handleEvent: (event: CognitionEvent) => void;\n tick: (deltaMs: number) => void;\n /** @deprecated Use handleEvent instead */\n emit: (event: CognitionEvent) => void;\n}\n\n/**\n * React hook for managing Glyph cognition state.\n *\n * Creates a CognitionController and provides reactive state updates.\n * Automatically handles RAF-based animation when autoTick is true (default).\n *\n * @example\n * ```tsx\n * const { state, emotion, emit, tick } = useCognition({\n * initial: { mode: 'idle' },\n * onChange: (state) => console.log('Cognition changed:', state),\n * });\n *\n * // Handle agent events\n * emit({ type: 'run.started', runId: 'r1' });\n *\n * // Access emotion bridge for rendering\n * console.log(emotion.anchor, emotion.avo);\n * ```\n */\nexport function useCognition(options: UseCognitionOptions = {}): UseCognitionResult {\n const { initial, onChange, autoTick = true } = options;\n\n // Create controller ref (stable across renders)\n const controllerRef = useRef<CognitionController | null>(null);\n\n if (!controllerRef.current) {\n controllerRef.current = new CognitionController({ initial });\n }\n\n const controller = controllerRef.current;\n\n // State for React reactivity\n const [state, setState] = useState<CognitionState>(controller.getState());\n const [emotion, setEmotion] = useState<EmotionTarget>(\n controller.getEmotionTarget()\n );\n\n // Store onChange in ref to avoid effect dependency changes\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n\n // Subscribe to controller events\n useEffect(() => {\n const unsub = controller.on('change', (newState) => {\n setState({ ...newState });\n setEmotion(controller.getEmotionTarget());\n onChangeRef.current?.(newState);\n });\n\n return () => {\n unsub();\n };\n }, [controller]);\n\n // Auto-tick with RAF\n useEffect(() => {\n if (!autoTick) return;\n\n let lastTime = performance.now();\n let rafId: number;\n\n const tickFn = (time: number) => {\n const delta = time - lastTime;\n lastTime = time;\n\n controller.tick(delta);\n\n rafId = requestAnimationFrame(tickFn);\n };\n\n rafId = requestAnimationFrame(tickFn);\n\n return () => {\n cancelAnimationFrame(rafId);\n };\n }, [controller, autoTick]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n controller.dispose();\n };\n }, [controller]);\n\n // Stable callbacks\n const handleEvent = useCallback(\n (event: CognitionEvent) => {\n controller.handleEvent(event);\n },\n [controller]\n );\n\n const tick = useCallback(\n (deltaMs: number) => {\n controller.tick(deltaMs);\n },\n [controller]\n );\n\n // Deprecated alias for backwards compatibility\n const emit = handleEvent;\n\n return {\n state,\n emotion,\n handleEvent,\n tick,\n emit,\n };\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,583 @@
1
+ // src/emotion/constants.ts
2
+ function isValidAVO(avo) {
3
+ return avo.arousal >= 0 && avo.arousal <= 1 && avo.valence >= 0 && avo.valence <= 1 && avo.openness >= 0 && avo.openness <= 1;
4
+ }
5
+ function clampAVO(avo) {
6
+ return {
7
+ arousal: Math.max(0, Math.min(1, avo.arousal ?? 0.25)),
8
+ valence: Math.max(0, Math.min(1, avo.valence ?? 0.6)),
9
+ openness: Math.max(0, Math.min(1, avo.openness ?? 0.35))
10
+ };
11
+ }
12
+ var ANCHOR_STATES = {
13
+ // Rest states
14
+ dormant: { arousal: 0.05, valence: 0.55, openness: 0.3 },
15
+ idle: { arousal: 0.25, valence: 0.6, openness: 0.35 },
16
+ // Receptive states
17
+ attentive: { arousal: 0.4, valence: 0.7, openness: 0.2 },
18
+ curious: { arousal: 0.5, valence: 0.75, openness: 0.1 },
19
+ listening: { arousal: 0.45, valence: 0.7, openness: 0.05 },
20
+ // Processing states
21
+ thinking: { arousal: 0.6, valence: 0.6, openness: 0.4 },
22
+ contemplating: { arousal: 0.55, valence: 0.65, openness: 0.45 },
23
+ focused: { arousal: 0.7, valence: 0.7, openness: 0.5 },
24
+ // Expressive states
25
+ responding: { arousal: 0.6, valence: 0.75, openness: 0.8 },
26
+ explaining: { arousal: 0.55, valence: 0.8, openness: 0.85 },
27
+ enthusiastic: { arousal: 0.8, valence: 0.9, openness: 0.75 },
28
+ // Completion states
29
+ satisfied: { arousal: 0.3, valence: 0.9, openness: 0.5 },
30
+ proud: { arousal: 0.45, valence: 0.95, openness: 0.6 },
31
+ // Negative states
32
+ uncertain: { arousal: 0.45, valence: 0.4, openness: 0.35 },
33
+ concerned: { arousal: 0.55, valence: 0.3, openness: 0.3 },
34
+ struggling: { arousal: 0.7, valence: 0.35, openness: 0.45 },
35
+ alarmed: { arousal: 0.8, valence: 0.2, openness: 0.4 },
36
+ error: { arousal: 0.75, valence: 0.1, openness: 0.35 },
37
+ // Recovery states
38
+ recovering: { arousal: 0.4, valence: 0.45, openness: 0.4 },
39
+ relieved: { arousal: 0.35, valence: 0.75, openness: 0.45 }
40
+ };
41
+ var LEGACY_STATE_MAP = {
42
+ idle: "idle",
43
+ listening: "listening",
44
+ thinking: "thinking",
45
+ responding: "responding",
46
+ success: "satisfied",
47
+ error: "error",
48
+ sleep: "dormant"
49
+ };
50
+ var DEFAULT_MICRO_CONFIG = {
51
+ enabled: true,
52
+ arousalNoise: 0.02,
53
+ valenceNoise: 0.015,
54
+ opennessNoise: 0.01,
55
+ frequency: 0.3
56
+ };
57
+ var DEFAULT_TRANSITION_DURATIONS = {
58
+ micro: 150,
59
+ standard: 400,
60
+ mood: 800,
61
+ major: 1200
62
+ };
63
+ var DEFAULT_AVO = ANCHOR_STATES.idle;
64
+
65
+ // src/emotion/mapping.ts
66
+ function lerp(a, b, t) {
67
+ return a + (b - a) * t;
68
+ }
69
+ function mapArousal(a) {
70
+ return {
71
+ breathingRate: 0.3 + Math.pow(a, 1.5) * 1.7,
72
+ // 0.3 - 2.0 Hz
73
+ breathingAmplitude: 0.01 + a * 0.05,
74
+ // 1% - 6%
75
+ ringRotationSpeed: 0.1 + Math.pow(a, 1.3) * 1.9,
76
+ // 0.1 - 2.0 rad/s
77
+ particleVelocity: 0.02 + a * 0.18,
78
+ // 0.02 - 0.20
79
+ particleCount: Math.floor(20 + a * 80),
80
+ // 20 - 100
81
+ glowPulseRate: 0.2 + Math.pow(a, 1.4) * 1.3
82
+ // 0.2 - 1.5 Hz
83
+ };
84
+ }
85
+ function mapValence(v) {
86
+ const colorT = 1 / (1 + Math.exp(-8 * (v - 0.4)));
87
+ return {
88
+ coreHue: lerp(220, 35, colorT),
89
+ // Blue(220) → Gold(35)
90
+ coreSaturation: 0.4 + v * 0.45,
91
+ // 40% - 85%
92
+ motionNoise: 0.15 * Math.pow(1 - v, 2),
93
+ // High noise when low
94
+ scaleFactor: 0.92 + v * 0.16,
95
+ // 0.92x - 1.08x
96
+ emissiveIntensity: 0.2 + Math.pow(v, 1.5) * 0.7
97
+ // 0.2 - 0.9
98
+ };
99
+ }
100
+ function mapOpenness(o) {
101
+ return {
102
+ particleFlowDirection: lerp(-1, 1, o),
103
+ // -1 (in) to +1 (out)
104
+ particleSpreadAngle: lerp(30, 120, o),
105
+ // 30° - 120°
106
+ breathingPhaseBias: lerp(-0.3, 0.3, o),
107
+ // Inhale vs exhale bias
108
+ ringTilt: lerp(-15, 15, o),
109
+ // -15° to +15°
110
+ auraExpansion: lerp(0.95, 1.1, o)
111
+ // 0.95x - 1.1x
112
+ };
113
+ }
114
+ function computeVisualState(avo) {
115
+ const arousalMap = mapArousal(avo.arousal);
116
+ const valenceMap = mapValence(avo.valence);
117
+ const opennessMap = mapOpenness(avo.openness);
118
+ const overallIntensity = 0.3 + avo.arousal * 0.4 + avo.valence * 0.3;
119
+ return {
120
+ ...arousalMap,
121
+ ...valenceMap,
122
+ ...opennessMap,
123
+ overallIntensity
124
+ };
125
+ }
126
+ function avoDistance(a, b) {
127
+ return Math.sqrt(
128
+ Math.pow(a.arousal - b.arousal, 2) + Math.pow(a.valence - b.valence, 2) + Math.pow(a.openness - b.openness, 2)
129
+ );
130
+ }
131
+ function blendAVO(from, to, t) {
132
+ return {
133
+ arousal: lerp(from.arousal, to.arousal, t),
134
+ valence: lerp(from.valence, to.valence, t),
135
+ openness: lerp(from.openness, to.openness, t)
136
+ };
137
+ }
138
+ function getAnimationWeights(currentAVO) {
139
+ const weights = {
140
+ idle: 0,
141
+ listening: 0,
142
+ thinking: 0,
143
+ responding: 0,
144
+ success: 0,
145
+ error: 0,
146
+ sleep: 0
147
+ };
148
+ for (const [state, anchor] of Object.entries(LEGACY_STATE_MAP)) {
149
+ const targetAVO = ANCHOR_STATES[anchor];
150
+ const distance = avoDistance(currentAVO, targetAVO);
151
+ weights[state] = Math.max(0, 1 - distance * 2);
152
+ }
153
+ const total = Object.values(weights).reduce((a, b) => a + b, 0);
154
+ if (total > 0) {
155
+ for (const key of Object.keys(weights)) {
156
+ weights[key] /= total;
157
+ }
158
+ } else {
159
+ weights.idle = 1;
160
+ }
161
+ return weights;
162
+ }
163
+
164
+ // src/emotion/transitions.ts
165
+ var EASING_FUNCTIONS = {
166
+ linear: (t) => t,
167
+ easeIn: (t) => t * t,
168
+ easeOut: (t) => 1 - Math.pow(1 - t, 2),
169
+ easeInOut: (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
170
+ spring: (t) => {
171
+ const c4 = 2 * Math.PI / 3;
172
+ return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
173
+ }
174
+ };
175
+ function ease(fn, t) {
176
+ return EASING_FUNCTIONS[fn](Math.max(0, Math.min(1, t)));
177
+ }
178
+ function getTransitionDuration(from, to) {
179
+ const distance = avoDistance(from, to);
180
+ const valenceDrop = from.valence - to.valence;
181
+ const arousalSpike = to.arousal - from.arousal;
182
+ if (valenceDrop > 0.3 && arousalSpike > 0.2) {
183
+ return 200;
184
+ }
185
+ if (to.valence > from.valence && to.valence > 0.6) {
186
+ return 600 + distance * 400;
187
+ }
188
+ return Math.floor(200 + distance * 800);
189
+ }
190
+ function getTransitionEasing(from, to) {
191
+ const valenceDrop = from.valence - to.valence;
192
+ const arousalSpike = to.arousal - from.arousal;
193
+ if (valenceDrop > 0.3 && arousalSpike > 0.2) {
194
+ return "easeOut";
195
+ }
196
+ if (to.valence > from.valence && to.valence > 0.7) {
197
+ return "spring";
198
+ }
199
+ return "easeInOut";
200
+ }
201
+ function getTransitionConfig(from, to) {
202
+ return {
203
+ duration: getTransitionDuration(from, to),
204
+ easing: getTransitionEasing(from, to),
205
+ onComplete: () => {
206
+ }
207
+ };
208
+ }
209
+
210
+ // src/emotion/micro-expressions.ts
211
+ function seededRandom(seed) {
212
+ let state = seed;
213
+ return () => {
214
+ state = state * 1103515245 + 12345 & 2147483647;
215
+ return state / 2147483647;
216
+ };
217
+ }
218
+ function createNoiseGenerator(seed = 42) {
219
+ const rand = seededRandom(seed);
220
+ const gradients = [];
221
+ for (let i = 0; i < 256; i++) {
222
+ gradients.push(rand() * 2 - 1);
223
+ }
224
+ const smoothstep = (t) => t * t * (3 - 2 * t);
225
+ return (t) => {
226
+ const i0 = Math.floor(t) & 255;
227
+ const i1 = i0 + 1 & 255;
228
+ const frac = t - Math.floor(t);
229
+ const g0 = gradients[i0];
230
+ const g1 = gradients[i1];
231
+ const d0 = g0 * frac;
232
+ const d1 = g1 * (frac - 1);
233
+ return smoothstep(frac) * (d1 - d0) + d0;
234
+ };
235
+ }
236
+ var arousalNoise = createNoiseGenerator(42);
237
+ var valenceNoise = createNoiseGenerator(137);
238
+ var opennessNoise = createNoiseGenerator(256);
239
+ function applyMicroExpression(base, config, time) {
240
+ if (!config.enabled) {
241
+ return base;
242
+ }
243
+ const t = time * config.frequency;
244
+ const noiseA = arousalNoise(t) * config.arousalNoise;
245
+ const noiseV = valenceNoise(t + 100) * config.valenceNoise;
246
+ const noiseO = opennessNoise(t + 200) * config.opennessNoise;
247
+ return {
248
+ arousal: Math.max(0, Math.min(1, base.arousal + noiseA)),
249
+ valence: Math.max(0, Math.min(1, base.valence + noiseV)),
250
+ openness: Math.max(0, Math.min(1, base.openness + noiseO))
251
+ };
252
+ }
253
+ function createMicroExpressionAnimator(config) {
254
+ let time = 0;
255
+ return {
256
+ tick(deltaMs) {
257
+ time += deltaMs / 1e3;
258
+ },
259
+ apply(base) {
260
+ return applyMicroExpression(base, config, time);
261
+ },
262
+ reset() {
263
+ time = 0;
264
+ }
265
+ };
266
+ }
267
+
268
+ // src/emotion/controller.ts
269
+ var EmotionController = class {
270
+ _dimensions;
271
+ _transition = null;
272
+ _microConfig;
273
+ _time = 0;
274
+ _listeners = /* @__PURE__ */ new Map();
275
+ _disposed = false;
276
+ constructor(options = {}) {
277
+ if (options.initialAnchor) {
278
+ this._dimensions = { ...ANCHOR_STATES[options.initialAnchor] };
279
+ } else if (options.initial) {
280
+ this._dimensions = clampAVO(options.initial);
281
+ } else {
282
+ this._dimensions = { ...DEFAULT_AVO };
283
+ }
284
+ if (options.microExpressions === false) {
285
+ this._microConfig = { ...DEFAULT_MICRO_CONFIG, enabled: false };
286
+ } else if (typeof options.microExpressions === "object") {
287
+ this._microConfig = { ...DEFAULT_MICRO_CONFIG, ...options.microExpressions };
288
+ } else {
289
+ this._microConfig = { ...DEFAULT_MICRO_CONFIG };
290
+ }
291
+ }
292
+ /**
293
+ * Get current base dimensions (without micro-expressions)
294
+ */
295
+ getDimensions() {
296
+ return { ...this._dimensions };
297
+ }
298
+ /**
299
+ * Get current dimensions with micro-expressions applied
300
+ */
301
+ getAnimatedDimensions() {
302
+ return applyMicroExpression(this._dimensions, this._microConfig, this._time);
303
+ }
304
+ /**
305
+ * Get computed visual state for rendering
306
+ */
307
+ getVisualState() {
308
+ return computeVisualState(this.getAnimatedDimensions());
309
+ }
310
+ /**
311
+ * Set dimensions immediately (no transition)
312
+ * Values are clamped to valid 0-1 range
313
+ */
314
+ setDimensions(dims) {
315
+ this._dimensions = clampAVO({ ...this._dimensions, ...dims });
316
+ this._transition = null;
317
+ this._emit("change", this._dimensions);
318
+ }
319
+ /**
320
+ * Transition to target dimensions over time
321
+ * Auto-calculates duration and easing if not specified
322
+ */
323
+ transitionTo(target, options = {}) {
324
+ const from = { ...this._dimensions };
325
+ const to = clampAVO({ ...this._dimensions, ...target });
326
+ const autoConfig = getTransitionConfig(from, to);
327
+ this._transition = {
328
+ from,
329
+ to,
330
+ duration: options.duration ?? autoConfig.duration,
331
+ easing: options.easing ?? autoConfig.easing,
332
+ elapsed: 0,
333
+ onComplete: options.onComplete
334
+ };
335
+ this._emit("transitionStart", { from, to });
336
+ }
337
+ /**
338
+ * Transition to a named anchor state
339
+ * Emits anchorReached when transition completes
340
+ */
341
+ transitionToAnchor(anchor, options = {}) {
342
+ this.transitionTo(ANCHOR_STATES[anchor], {
343
+ ...options,
344
+ onComplete: () => {
345
+ this._emit("anchorReached", anchor);
346
+ options.onComplete?.();
347
+ }
348
+ });
349
+ }
350
+ /**
351
+ * Handle emotion events from agent behaviors
352
+ * Maps event types to appropriate anchor transitions
353
+ */
354
+ handleEvent(event) {
355
+ const intensity = event.intensity ?? 0.5;
356
+ switch (event.type) {
357
+ case "input_received":
358
+ this.transitionToAnchor("listening");
359
+ break;
360
+ case "processing_start":
361
+ this.transitionToAnchor("thinking");
362
+ break;
363
+ case "processing_complete":
364
+ this.transitionToAnchor("responding");
365
+ break;
366
+ case "error_occurred":
367
+ this.transitionToAnchor(intensity > 0.7 ? "error" : "concerned");
368
+ break;
369
+ case "success":
370
+ this.transitionToAnchor(intensity > 0.7 ? "proud" : "satisfied");
371
+ break;
372
+ case "user_idle":
373
+ this.transitionToAnchor("idle", { duration: 2e3 });
374
+ break;
375
+ case "interrupt":
376
+ this.setDimensions({ arousal: Math.min(this._dimensions.arousal + 0.2, 1) });
377
+ break;
378
+ }
379
+ }
380
+ /**
381
+ * Blend toward target dimensions by a factor (0-1)
382
+ * Useful for continuous input-driven changes
383
+ */
384
+ blendToward(target, factor) {
385
+ const to = clampAVO({ ...this._dimensions, ...target });
386
+ this._dimensions = blendAVO(this._dimensions, to, factor);
387
+ this._emit("change", this._dimensions);
388
+ }
389
+ /**
390
+ * Check if currently transitioning
391
+ */
392
+ isTransitioning() {
393
+ return this._transition !== null;
394
+ }
395
+ /**
396
+ * Cancel current transition, keeping current position
397
+ */
398
+ cancelTransition() {
399
+ this._transition = null;
400
+ }
401
+ /**
402
+ * Subscribe to controller events
403
+ * Returns unsubscribe function
404
+ */
405
+ on(event, handler) {
406
+ if (!this._listeners.has(event)) {
407
+ this._listeners.set(event, /* @__PURE__ */ new Set());
408
+ }
409
+ this._listeners.get(event).add(handler);
410
+ return () => {
411
+ this._listeners.get(event)?.delete(handler);
412
+ };
413
+ }
414
+ /**
415
+ * Update tick - call each frame with delta time in milliseconds
416
+ * Advances transitions and micro-expression time
417
+ */
418
+ tick(deltaMs) {
419
+ if (this._disposed) return;
420
+ this._time += deltaMs / 1e3;
421
+ if (this._transition) {
422
+ this._transition.elapsed += deltaMs;
423
+ const progress = this._transition.duration <= 0 ? 1 : Math.min(this._transition.elapsed / this._transition.duration, 1);
424
+ const easedProgress = ease(this._transition.easing, progress);
425
+ this._dimensions = blendAVO(this._transition.from, this._transition.to, easedProgress);
426
+ this._emit("change", this._dimensions);
427
+ if (progress >= 1) {
428
+ const onComplete = this._transition.onComplete;
429
+ this._transition = null;
430
+ this._emit("transitionEnd", this._dimensions);
431
+ onComplete?.();
432
+ }
433
+ }
434
+ }
435
+ /**
436
+ * Dispose controller and clean up resources
437
+ */
438
+ dispose() {
439
+ this._disposed = true;
440
+ this._listeners.clear();
441
+ this._transition = null;
442
+ }
443
+ _emit(event, data) {
444
+ this._listeners.get(event)?.forEach((handler) => handler(data));
445
+ }
446
+ };
447
+
448
+ // src/emotion/hooks/useEmotion.ts
449
+ import { useState, useEffect, useCallback, useRef } from "react";
450
+ function useEmotion(options = {}) {
451
+ const {
452
+ initial,
453
+ initialAnchor,
454
+ microExpressions = true,
455
+ onChange,
456
+ autoTick = true
457
+ } = options;
458
+ const controllerRef = useRef(null);
459
+ if (!controllerRef.current) {
460
+ controllerRef.current = new EmotionController({
461
+ initial,
462
+ initialAnchor,
463
+ microExpressions
464
+ });
465
+ }
466
+ const controller = controllerRef.current;
467
+ const [dimensions, setDimensions] = useState(controller.getAnimatedDimensions());
468
+ const [baseDimensions, setBaseDimensions] = useState(controller.getDimensions());
469
+ const [visualState, setVisualState] = useState(controller.getVisualState());
470
+ const [isTransitioning, setIsTransitioning] = useState(false);
471
+ const onChangeRef = useRef(onChange);
472
+ onChangeRef.current = onChange;
473
+ useEffect(() => {
474
+ const unsub = controller.on("change", (dims) => {
475
+ setBaseDimensions({ ...dims });
476
+ setDimensions(controller.getAnimatedDimensions());
477
+ setVisualState(controller.getVisualState());
478
+ onChangeRef.current?.(dims);
479
+ });
480
+ const unsubStart = controller.on("transitionStart", () => {
481
+ setIsTransitioning(true);
482
+ });
483
+ const unsubEnd = controller.on("transitionEnd", () => {
484
+ setIsTransitioning(false);
485
+ });
486
+ return () => {
487
+ unsub();
488
+ unsubStart();
489
+ unsubEnd();
490
+ };
491
+ }, [controller]);
492
+ useEffect(() => {
493
+ if (!autoTick) return;
494
+ let lastTime = performance.now();
495
+ let rafId;
496
+ const tick2 = (time) => {
497
+ const delta = time - lastTime;
498
+ lastTime = time;
499
+ controller.tick(delta);
500
+ setDimensions(controller.getAnimatedDimensions());
501
+ setVisualState(controller.getVisualState());
502
+ rafId = requestAnimationFrame(tick2);
503
+ };
504
+ rafId = requestAnimationFrame(tick2);
505
+ return () => {
506
+ cancelAnimationFrame(rafId);
507
+ };
508
+ }, [controller, autoTick]);
509
+ useEffect(() => {
510
+ return () => {
511
+ controller.dispose();
512
+ };
513
+ }, [controller]);
514
+ const set = useCallback(
515
+ (dims) => {
516
+ controller.setDimensions(dims);
517
+ },
518
+ [controller]
519
+ );
520
+ const transition = useCallback(
521
+ (dims, opts) => {
522
+ controller.transitionTo(dims, opts);
523
+ },
524
+ [controller]
525
+ );
526
+ const goTo = useCallback(
527
+ (anchor, opts) => {
528
+ controller.transitionToAnchor(anchor, opts);
529
+ },
530
+ [controller]
531
+ );
532
+ const emit = useCallback(
533
+ (event) => {
534
+ controller.handleEvent(event);
535
+ },
536
+ [controller]
537
+ );
538
+ const tick = useCallback(
539
+ (deltaMs) => {
540
+ controller.tick(deltaMs);
541
+ },
542
+ [controller]
543
+ );
544
+ return {
545
+ dimensions,
546
+ baseDimensions,
547
+ visualState,
548
+ set,
549
+ transition,
550
+ goTo,
551
+ emit,
552
+ isTransitioning,
553
+ tick
554
+ };
555
+ }
556
+
557
+ export {
558
+ isValidAVO,
559
+ clampAVO,
560
+ ANCHOR_STATES,
561
+ LEGACY_STATE_MAP,
562
+ DEFAULT_MICRO_CONFIG,
563
+ DEFAULT_TRANSITION_DURATIONS,
564
+ DEFAULT_AVO,
565
+ lerp,
566
+ mapArousal,
567
+ mapValence,
568
+ mapOpenness,
569
+ computeVisualState,
570
+ avoDistance,
571
+ blendAVO,
572
+ getAnimationWeights,
573
+ ease,
574
+ getTransitionDuration,
575
+ getTransitionEasing,
576
+ getTransitionConfig,
577
+ createNoiseGenerator,
578
+ applyMicroExpression,
579
+ createMicroExpressionAnimator,
580
+ EmotionController,
581
+ useEmotion
582
+ };
583
+ //# sourceMappingURL=chunk-VU2XK2NI.js.map