100 lines
2.7 KiB
TypeScript
100 lines
2.7 KiB
TypeScript
/**
|
|
* Deterministic Agent ID System
|
|
*
|
|
* This module provides helper functions for formatting and parsing deterministic
|
|
* agent IDs used in the swarm/teammate system.
|
|
*
|
|
* ## ID Formats
|
|
*
|
|
* **Agent IDs**: `agentName@teamName`
|
|
* - Example: `team-lead@my-project`, `researcher@my-project`
|
|
* - The @ symbol acts as a separator between agent name and team name
|
|
*
|
|
* **Request IDs**: `{requestType}-{timestamp}@{agentId}`
|
|
* - Example: `shutdown-1702500000000@researcher@my-project`
|
|
* - Used for shutdown requests, plan approvals, etc.
|
|
*
|
|
* ## Why Deterministic IDs?
|
|
*
|
|
* Deterministic IDs provide several benefits:
|
|
*
|
|
* 1. **Reproducibility**: The same agent spawned with the same name in the same team
|
|
* always gets the same ID, enabling reconnection after crashes/restarts.
|
|
*
|
|
* 2. **Human-readable**: IDs are meaningful and debuggable (e.g., `tester@my-project`).
|
|
*
|
|
* 3. **Predictable**: Team leads can compute a teammate's ID without looking it up,
|
|
* simplifying message routing and task assignment.
|
|
*
|
|
* ## Constraints
|
|
*
|
|
* - Agent names must NOT contain `@` (it's used as the separator)
|
|
* - Use `sanitizeAgentName()` from TeammateTool.ts to strip @ from names
|
|
*/
|
|
|
|
/**
|
|
* Formats an agent ID in the format `agentName@teamName`.
|
|
*/
|
|
export function formatAgentId(agentName: string, teamName: string): string {
|
|
return `${agentName}@${teamName}`
|
|
}
|
|
|
|
/**
|
|
* Parses an agent ID into its components.
|
|
* Returns null if the ID doesn't contain the @ separator.
|
|
*/
|
|
export function parseAgentId(
|
|
agentId: string,
|
|
): { agentName: string; teamName: string } | null {
|
|
const atIndex = agentId.indexOf('@')
|
|
if (atIndex === -1) {
|
|
return null
|
|
}
|
|
return {
|
|
agentName: agentId.slice(0, atIndex),
|
|
teamName: agentId.slice(atIndex + 1),
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Formats a request ID in the format `{requestType}-{timestamp}@{agentId}`.
|
|
*/
|
|
export function generateRequestId(
|
|
requestType: string,
|
|
agentId: string,
|
|
): string {
|
|
const timestamp = Date.now()
|
|
return `${requestType}-${timestamp}@${agentId}`
|
|
}
|
|
|
|
/**
|
|
* Parses a request ID into its components.
|
|
* Returns null if the request ID doesn't match the expected format.
|
|
*/
|
|
export function parseRequestId(
|
|
requestId: string,
|
|
): { requestType: string; timestamp: number; agentId: string } | null {
|
|
const atIndex = requestId.indexOf('@')
|
|
if (atIndex === -1) {
|
|
return null
|
|
}
|
|
|
|
const prefix = requestId.slice(0, atIndex)
|
|
const agentId = requestId.slice(atIndex + 1)
|
|
|
|
const lastDashIndex = prefix.lastIndexOf('-')
|
|
if (lastDashIndex === -1) {
|
|
return null
|
|
}
|
|
|
|
const requestType = prefix.slice(0, lastDashIndex)
|
|
const timestampStr = prefix.slice(lastDashIndex + 1)
|
|
const timestamp = parseInt(timestampStr, 10)
|
|
|
|
if (isNaN(timestamp)) {
|
|
return null
|
|
}
|
|
|
|
return { requestType, timestamp, agentId }
|
|
}
|