- Standardized error handling across tool implementations - Improved return type consistency for tool execution results - Simplified configuration parsing and type definitions - Enhanced type safety for various configuration schemas - Cleaned up and normalized tool response structures - Updated SSE and event subscription tool implementations
240 lines
6.2 KiB
TypeScript
240 lines
6.2 KiB
TypeScript
import { EventEmitter } from "events";
|
|
|
|
// Resource types
|
|
export enum ResourceType {
|
|
DEVICE = "device",
|
|
AREA = "area",
|
|
USER = "user",
|
|
AUTOMATION = "automation",
|
|
SCENE = "scene",
|
|
SCRIPT = "script",
|
|
GROUP = "group",
|
|
}
|
|
|
|
// Resource state interface
|
|
export interface ResourceState {
|
|
id: string;
|
|
type: ResourceType;
|
|
state: any;
|
|
attributes: Record<string, any>;
|
|
lastUpdated: number;
|
|
context?: Record<string, any>;
|
|
}
|
|
|
|
// Resource relationship types
|
|
export enum RelationType {
|
|
CONTAINS = "contains",
|
|
CONTROLS = "controls",
|
|
TRIGGERS = "triggers",
|
|
DEPENDS_ON = "depends_on",
|
|
GROUPS = "groups",
|
|
}
|
|
|
|
// Resource relationship interface
|
|
export interface ResourceRelationship {
|
|
sourceId: string;
|
|
targetId: string;
|
|
type: RelationType;
|
|
metadata?: Record<string, any>;
|
|
}
|
|
|
|
// Context manager class
|
|
export class ContextManager extends EventEmitter {
|
|
private resources: Map<string, ResourceState> = new Map();
|
|
private relationships: ResourceRelationship[] = [];
|
|
private stateHistory: Map<string, ResourceState[]> = new Map();
|
|
private historyLimit = 100;
|
|
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
// Resource management
|
|
public addResource(resource: ResourceState): void {
|
|
this.resources.set(resource.id, resource);
|
|
this.emit("resource_added", resource);
|
|
}
|
|
|
|
public updateResource(id: string, update: Partial<ResourceState>): void {
|
|
const resource = this.resources.get(id);
|
|
if (resource) {
|
|
// Store current state in history
|
|
this.addToHistory(resource);
|
|
|
|
// Update resource
|
|
const updatedResource = {
|
|
...resource,
|
|
...update,
|
|
lastUpdated: Date.now(),
|
|
};
|
|
this.resources.set(id, updatedResource);
|
|
this.emit("resource_updated", updatedResource);
|
|
}
|
|
}
|
|
|
|
public removeResource(id: string): void {
|
|
const resource = this.resources.get(id);
|
|
if (resource) {
|
|
this.resources.delete(id);
|
|
// Remove related relationships
|
|
this.relationships = this.relationships.filter(
|
|
(rel) => rel.sourceId !== id && rel.targetId !== id,
|
|
);
|
|
this.emit("resource_removed", resource);
|
|
}
|
|
}
|
|
|
|
// Relationship management
|
|
public addRelationship(relationship: ResourceRelationship): void {
|
|
this.relationships.push(relationship);
|
|
this.emit("relationship_added", relationship);
|
|
}
|
|
|
|
public removeRelationship(
|
|
sourceId: string,
|
|
targetId: string,
|
|
type: RelationType,
|
|
): void {
|
|
const index = this.relationships.findIndex(
|
|
(rel) =>
|
|
rel.sourceId === sourceId &&
|
|
rel.targetId === targetId &&
|
|
rel.type === type,
|
|
);
|
|
if (index !== -1) {
|
|
const removed = this.relationships.splice(index, 1)[0];
|
|
this.emit("relationship_removed", removed);
|
|
}
|
|
}
|
|
|
|
// History management
|
|
private addToHistory(state: ResourceState): void {
|
|
const history = this.stateHistory.get(state.id) || [];
|
|
history.push({ ...state });
|
|
if (history.length > this.historyLimit) {
|
|
history.shift();
|
|
}
|
|
this.stateHistory.set(state.id, history);
|
|
}
|
|
|
|
public getHistory(id: string): ResourceState[] {
|
|
return this.stateHistory.get(id) || [];
|
|
}
|
|
|
|
// Context queries
|
|
public getResource(id: string): ResourceState | undefined {
|
|
return this.resources.get(id);
|
|
}
|
|
|
|
public getResourcesByType(type: ResourceType): ResourceState[] {
|
|
return Array.from(this.resources.values()).filter(
|
|
(resource) => resource.type === type,
|
|
);
|
|
}
|
|
|
|
public getRelatedResources(
|
|
id: string,
|
|
type?: RelationType,
|
|
depth: number = 1,
|
|
): ResourceState[] {
|
|
const related = new Set<ResourceState>();
|
|
const visited = new Set<string>();
|
|
|
|
const traverse = (currentId: string, currentDepth: number) => {
|
|
if (currentDepth > depth || visited.has(currentId)) return;
|
|
visited.add(currentId);
|
|
|
|
this.relationships
|
|
.filter(
|
|
(rel) =>
|
|
(rel.sourceId === currentId || rel.targetId === currentId) &&
|
|
(!type || rel.type === type),
|
|
)
|
|
.forEach((rel) => {
|
|
const relatedId =
|
|
rel.sourceId === currentId ? rel.targetId : rel.sourceId;
|
|
const relatedResource = this.resources.get(relatedId);
|
|
if (relatedResource) {
|
|
related.add(relatedResource);
|
|
traverse(relatedId, currentDepth + 1);
|
|
}
|
|
});
|
|
};
|
|
|
|
traverse(id, 0);
|
|
return Array.from(related);
|
|
}
|
|
|
|
// Context analysis
|
|
public analyzeResourceUsage(id: string): {
|
|
dependencies: string[];
|
|
dependents: string[];
|
|
groups: string[];
|
|
usage: {
|
|
triggerCount: number;
|
|
controlCount: number;
|
|
groupCount: number;
|
|
};
|
|
} {
|
|
const dependencies = this.relationships
|
|
.filter(
|
|
(rel) => rel.sourceId === id && rel.type === RelationType.DEPENDS_ON,
|
|
)
|
|
.map((rel) => rel.targetId);
|
|
|
|
const dependents = this.relationships
|
|
.filter(
|
|
(rel) => rel.targetId === id && rel.type === RelationType.DEPENDS_ON,
|
|
)
|
|
.map((rel) => rel.sourceId);
|
|
|
|
const groups = this.relationships
|
|
.filter((rel) => rel.targetId === id && rel.type === RelationType.GROUPS)
|
|
.map((rel) => rel.sourceId);
|
|
|
|
const usage = {
|
|
triggerCount: this.relationships.filter(
|
|
(rel) => rel.sourceId === id && rel.type === RelationType.TRIGGERS,
|
|
).length,
|
|
controlCount: this.relationships.filter(
|
|
(rel) => rel.sourceId === id && rel.type === RelationType.CONTROLS,
|
|
).length,
|
|
groupCount: groups.length,
|
|
};
|
|
|
|
return { dependencies, dependents, groups, usage };
|
|
}
|
|
|
|
// Event subscriptions
|
|
public subscribeToResource(
|
|
id: string,
|
|
callback: (state: ResourceState) => void,
|
|
): () => void {
|
|
const handler = (resource: ResourceState) => {
|
|
if (resource.id === id) {
|
|
callback(resource);
|
|
}
|
|
};
|
|
|
|
this.on("resource_updated", handler);
|
|
return () => this.off("resource_updated", handler);
|
|
}
|
|
|
|
public subscribeToType(
|
|
type: ResourceType,
|
|
callback: (state: ResourceState) => void,
|
|
): () => void {
|
|
const handler = (resource: ResourceState) => {
|
|
if (resource.type === type) {
|
|
callback(resource);
|
|
}
|
|
};
|
|
|
|
this.on("resource_updated", handler);
|
|
return () => this.off("resource_updated", handler);
|
|
}
|
|
}
|
|
|
|
// Export context manager instance
|
|
export const contextManager = new ContextManager();
|