← back to Dw Boardroom Governance
src/engine/delegationEngine.ts
149 lines
/**
* Delegation Engine — Keyword-based task routing + contract management
* Ported from /root/DW-Agents/boardroom-agent/lib/delegation-engine.js
*
* Features:
* - TASK_KEYWORDS map for intelligent routing
* - EXEC_DELEGATES hierarchy for fallback
* - Contract lifecycle (create, complete, revoke, expire)
*/
import { query, queryOne, execute } from '../db/db';
import { broadcast } from '../ws/broadcast';
import { DelegationContract, TASK_KEYWORDS, EXEC_DELEGATES } from '../types';
import { v4 as uuidv4 } from 'uuid';
// ─── Keyword Routing ────────────────────────────
export function routeByKeywords(description: string): string | null {
const lower = description.toLowerCase();
// Check multi-word keywords first (more specific)
const multiWordKeys = Object.keys(TASK_KEYWORDS).filter(k => k.includes(' '));
for (const keyword of multiWordKeys) {
if (lower.includes(keyword)) {
return TASK_KEYWORDS[keyword];
}
}
// Then single-word keywords
const words = lower.split(/\s+/);
for (const word of words) {
if (TASK_KEYWORDS[word]) {
return TASK_KEYWORDS[word];
}
}
return null;
}
export function getExecForAgent(agentId: string): string | null {
for (const [exec, agents] of Object.entries(EXEC_DELEGATES)) {
if (agents.includes(agentId)) return exec;
}
return null;
}
export function buildHierarchyPath(agentId: string): string {
const exec = getExecForAgent(agentId);
if (!exec) return agentId;
return `${exec} > ${agentId}`;
}
// ─── Contract CRUD ──────────────────────────────
export async function createDelegation(data: {
decisionId?: string;
owner: string;
delegate: string;
autonomyLevel?: number;
metric?: string;
checkpointDate?: string;
routingKeywords?: string[];
}): Promise<DelegationContract> {
const id = uuidv4();
const hierarchyPath = buildHierarchyPath(data.delegate);
await query(
`INSERT INTO gov_delegation_contract
(id, decision_id, owner, delegate, autonomy_level, metric, checkpoint_date, routing_keywords, hierarchy_path)
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)`,
[
id,
data.decisionId || null,
data.owner,
data.delegate,
data.autonomyLevel || 1,
data.metric || null,
data.checkpointDate || null,
data.routingKeywords || null,
hierarchyPath,
]
);
const contract = (await queryOne<DelegationContract>(
'SELECT * FROM gov_delegation_contract WHERE id = $1', [id]
))!;
broadcast('delegation_created', contract);
console.log(`[Delegation] Created: ${data.owner} → ${data.delegate} (${hierarchyPath})`);
return contract;
}
export async function completeDelegation(id: string): Promise<DelegationContract> {
await execute(
"UPDATE gov_delegation_contract SET status = 'completed', completed_at = NOW() WHERE id = $1",
[id]
);
const contract = await queryOne<DelegationContract>(
'SELECT * FROM gov_delegation_contract WHERE id = $1', [id]
);
if (!contract) throw new Error('Delegation not found');
return contract;
}
export async function revokeDelegation(id: string): Promise<DelegationContract> {
await execute(
"UPDATE gov_delegation_contract SET status = 'revoked', completed_at = NOW() WHERE id = $1",
[id]
);
const contract = await queryOne<DelegationContract>(
'SELECT * FROM gov_delegation_contract WHERE id = $1', [id]
);
if (!contract) throw new Error('Delegation not found');
return contract;
}
export async function listDelegations(status?: string): Promise<DelegationContract[]> {
if (status) {
return query<DelegationContract>(
'SELECT * FROM gov_delegation_contract WHERE status = $1 ORDER BY created_at DESC',
[status]
);
}
return query<DelegationContract>(
'SELECT * FROM gov_delegation_contract ORDER BY created_at DESC LIMIT 50'
);
}
export async function getDelegation(id: string): Promise<DelegationContract | null> {
return queryOne<DelegationContract>(
'SELECT * FROM gov_delegation_contract WHERE id = $1', [id]
);
}
export async function checkExpiredContracts(): Promise<number> {
const result = await execute(
`UPDATE gov_delegation_contract
SET status = 'expired', completed_at = NOW()
WHERE status = 'active'
AND checkpoint_date IS NOT NULL
AND checkpoint_date < NOW()`
);
if (result > 0) {
console.log(`[Delegation] Expired ${result} contract(s)`);
}
return result;
}