Files
nanoclaw/src/db/agent-destinations.ts
gavrielc 67f081671d style: prettier formatting fixes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 16:31:45 +03:00

69 lines
2.6 KiB
TypeScript

/**
* Per-agent destination map + ACL.
*
* Each row means: agent `agent_group_id` is allowed to send messages to
* target (`target_type`, `target_id`), and refers to it locally as `local_name`.
*
* Names are local to each source agent — they exist only inside that agent's
* namespace. The host uses this table both for routing (resolve name → ID)
* and for permission checks (row exists ⇒ authorized).
*/
import type { AgentDestination } from '../types.js';
import { getDb } from './connection.js';
export function createDestination(row: AgentDestination): void {
getDb()
.prepare(
`INSERT INTO agent_destinations (agent_group_id, local_name, target_type, target_id, created_at)
VALUES (@agent_group_id, @local_name, @target_type, @target_id, @created_at)`,
)
.run(row);
}
export function getDestinations(agentGroupId: string): AgentDestination[] {
return getDb()
.prepare('SELECT * FROM agent_destinations WHERE agent_group_id = ?')
.all(agentGroupId) as AgentDestination[];
}
export function getDestinationByName(agentGroupId: string, localName: string): AgentDestination | undefined {
return getDb()
.prepare('SELECT * FROM agent_destinations WHERE agent_group_id = ? AND local_name = ?')
.get(agentGroupId, localName) as AgentDestination | undefined;
}
/** Reverse lookup: what does this agent call the given target? */
export function getDestinationByTarget(
agentGroupId: string,
targetType: 'channel' | 'agent',
targetId: string,
): AgentDestination | undefined {
return getDb()
.prepare('SELECT * FROM agent_destinations WHERE agent_group_id = ? AND target_type = ? AND target_id = ?')
.get(agentGroupId, targetType, targetId) as AgentDestination | undefined;
}
/** Permission check: can this agent send to this target? */
export function hasDestination(agentGroupId: string, targetType: 'channel' | 'agent', targetId: string): boolean {
const row = getDb()
.prepare('SELECT 1 FROM agent_destinations WHERE agent_group_id = ? AND target_type = ? AND target_id = ? LIMIT 1')
.get(agentGroupId, targetType, targetId);
return !!row;
}
export function deleteDestination(agentGroupId: string, localName: string): void {
getDb()
.prepare('DELETE FROM agent_destinations WHERE agent_group_id = ? AND local_name = ?')
.run(agentGroupId, localName);
}
/** Normalize a human-readable name into a lowercase, dash-separated identifier. */
export function normalizeName(name: string): string {
return (
name
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '') || 'unnamed'
);
}