AI Decorators
Overview
The AI decorator layer bridges framework-level decorator metadata and the runtime AI feature classes (StateAnalyzer, AIOptimizer, AIPredictor). @AIPowered is the primary entry point: it wraps the store constructor to create and wire all three AI components into the dispatch pipeline automatically. A set of helper functions then provides access to those instances from outside the store.
Public component AI decorators are experimental. The internal AIController and AIEndpoint decorators are not public root exports; see the Decorator Reference. This page focuses on the store AI system.
Key Concepts
@AIPoweredwraps the store constructor; setup runs asynchronously after construction (in asetTimeout(0)) so it never blocks initialization.- Dispatch interception —
@AIPoweredreplacesstore.dispatchwith an instrumented version that records transitions to the predictor, latencies to the optimizer, and runs analysis on every state change. - Helper functions —
getAnalyzer,getOptimizer,getPredictor,analyzeStore,getAIInsightsretrieve attached AI instances without accessing private properties. enableAI— programmatic alternative to the decorator; useful for dynamic or conditional AI feature activation.
API Reference
AIPoweredOptions
interface AIPoweredOptions {
analyzer?: StateAnalyzerConfig; // config forwarded to StateAnalyzer
optimizer?: OptimizerConfig; // config forwarded to AIOptimizer
predictor?: PredictorConfig; // config forwarded to AIPredictor
autoAnalyze?: boolean; // run analysis on every dispatch; default true
autoOptimize?: boolean; // generate optimizer suggestions on every dispatch; default true
logInsights?: boolean; // print AI insights to console; default false
onSuggestion?: (suggestion: OptimizationSuggestion) => void;
onAnomaly?: (anomaly: Anomaly) => void;
}
@AIPowered
function AIPowered(options?: AIPoweredOptions): ClassDecorator
Applied to a Store subclass. Creates StateAnalyzer, AIOptimizer, and AIPredictor instances and attaches them as __analyzer__, __optimizer__, __predictor__ on the store instance.
Helper functions
// Retrieve AI instances attached by @AIPowered (or enableAI)
function getAnalyzer(store: any): StateAnalyzer | undefined
function getOptimizer(store: any): AIOptimizer | undefined
function getPredictor(store: any): AIPredictor | undefined
// Check whether AI is active on a store
function hasAI(store: any): boolean
// Run a full on-demand analysis
function analyzeStore(store: any): {
score: number;
issues: AnalysisIssue[];
suggestions: OptimizationSuggestion[];
recommendations: string[];
}
// Get a combined AI snapshot
function getAIInsights(store: any): {
analysis?: AnalysisResult;
suggestions?: OptimizationSuggestion[];
anomalies?: Anomaly[];
}
// Programmatically attach AI features (no decorator required)
function enableAI(store: any, options?: AIPoweredOptions): void
Metadata helper
function getAIMetadata(target: any): { options: AIPoweredOptions } | undefined
Basic Usage
import 'reflect-metadata';
import {
ReactiveStore, AIPowered, Store, Mutation, Action, Selector,
getAnalyzer, getOptimizer, getPredictor, analyzeStore,
} from '@tagna/udiot';
interface TaskState {
tasks: Task[];
filter: 'all' | 'active' | 'done';
loading: boolean;
}
@ReactiveStore({ name: 'TaskStore', trackHistory: true })
@AIPowered({
autoAnalyze: true,
autoOptimize: true,
logInsights: process.env.NODE_ENV === 'development',
onSuggestion: (s) => console.log(`[AI Suggestion] ${s.title}`),
onAnomaly: (a) => console.error(`[AI Anomaly] ${a.severity}: ${a.description}`),
analyzer: { complexityThreshold: 12 },
optimizer: { latencyThreshold: 20 },
predictor: { minConfidenceThreshold: 0.7, historySize: 150 },
})
class TaskStore extends Store<TaskState> {
constructor() {
super({ tasks: [], filter: 'all', loading: false });
}
@Mutation({ aiTracking: true })
setFilter(filter: TaskState['filter']): void {
this.dispatch({ type: 'SET_FILTER', payload: filter });
}
@Action({ retry: 2 })
async fetchTasks(): Promise<void> {
const tasks = await fetch('/api/tasks').then(r => r.json());
this.dispatch({ type: 'SET_TASKS', payload: tasks });
}
@Selector()
visibleTasks(): Task[] {
const { tasks, filter } = this.getState();
if (filter === 'all') return tasks;
return tasks.filter(t => (filter === 'done') === t.done);
}
}
Common Patterns
On-demand analysis
import { analyzeStore } from '@tagna/udiot';
const store = new TaskStore();
// After some user interaction
document.querySelector('#analyze-btn')?.addEventListener('click', () => {
const report = analyzeStore(store);
console.log(`State health score: ${report.score}/100`);
report.issues.forEach(issue => console.warn(`${issue.severity}: ${issue.message}`));
report.recommendations.forEach(r => console.info(`Recommendation: ${r}`));
});
Conditional AI activation
import { enableAI, Store } from '@tagna/udiot';
class AppStore extends Store<AppState> {
constructor(state: AppState) { super(state); }
}
const store = new AppStore(initialState);
// Only enable AI in development
if (process.env.NODE_ENV === 'development') {
enableAI(store, {
autoAnalyze: true,
logInsights: true,
onAnomaly: (a) => console.error('[DEV] Anomaly:', a.description),
});
}
Combining with @EnableDevTools and @Persist
import 'reflect-metadata';
import {
ReactiveStore, AIPowered, EnableDevTools, Persist, Store, Mutation, Selector
} from '@tagna/udiot';
interface CartState { items: CartItem[]; coupon: string | null; }
@ReactiveStore({ name: 'CartStore' })
@AIPowered({ autoAnalyze: true, autoOptimize: true })
@EnableDevTools({ consoleLogger: true })
@Persist({ storage: 'localStorage', whitelist: ['items', 'coupon'] })
class CartStore extends Store<CartState> {
constructor() { super({ items: [], coupon: null }); }
@Mutation({ aiTracking: true })
addItem(item: CartItem): void {
this.dispatch({ type: 'ADD_ITEM', payload: item });
}
@Selector()
total(): number {
return this.getState().items.reduce((s, i) => s + i.price * i.qty, 0);
}
}
Reacting to AI suggestions in production
import { ReactiveStore, AIPowered, Store } from '@tagna/udiot';
import type { OptimizationSuggestion, Anomaly } from '@tagna/udiot';
import { telemetryClient } from './telemetry';
@ReactiveStore({ name: 'MonitoredStore' })
@AIPowered({
autoAnalyze: true,
autoOptimize: true,
onSuggestion: (s: OptimizationSuggestion) => {
if (s.impact === 'high' && s.priority >= 8) {
telemetryClient.track('ai.optimization.suggestion', {
id: s.id, type: s.type, title: s.title,
});
}
},
onAnomaly: (a: Anomaly) => {
telemetryClient.captureError(new Error(a.description), {
severity: a.severity,
recommendation: a.recommendation,
});
},
})
class MonitoredStore extends Store<AppState> {
constructor(state: AppState) { super(state); }
}
Integration Notes
@AIPoweredmust be applied below@ReactiveStorein the decorator stack (decorators are applied bottom-to-top, so write@ReactiveStoreabove@AIPowered). If@Persistand@EnableDevToolsare also applied, the order is@ReactiveStore→@AIPowered→@EnableDevTools→@Persistfrom top to bottom.- The AI setup (
setupAIFeatures) runs insidesetTimeout(fn, 0)— it executes after the store constructor returns. Do not callgetAnalyzeror similar helpers synchronously in the constructor; wait for at least one tick. logInsightsonly logs when the analysis score drops below 70, to avoid console noise during normal operation.analyzeStorethrows if the store does not have AI enabled (hasAI(store)isfalse). Guard withhasAI(store)if activation is conditional.
Pitfalls
- Applying
@AIPoweredwithout@ReactiveStoreis valid but the store will not be in theStoreRegistry. The AI features still work; only registry lookup is affected. @AIPoweredattaches AI instances using__analyzer__,__optimizer__,__predictor__property names. Do not define these properties on your store class or they will be overwritten on the first dispatch.autoAnalyze: trueandautoOptimize: trueadd overhead to every dispatch — typically sub-millisecond for simple states, but measurable for states with hundreds of properties. Set them tofalsein production for performance-critical stores; useanalyzeStoreon demand instead.onSuggestionandonAnomalycallbacks are called synchronously inside the patcheddispatch. Keep them fast; avoid blocking I/O or heavy computation in these callbacks.