UNPKG

paqad-ai

Version:

Spec-driven development framework — AI agents that think before they type

71 lines (61 loc) • 2.33 kB
export const ACTIVITY_LINES = 1; export const SUBAGENT_PREFIX = 'Subagent: '; const WORKING_STATUSES: ReadonlySet<string> = new Set(['pending', 'running', 'waiting']); const INPUT_FIELDS = [ 'description', 'command', 'file_path', 'notebook_path', 'pattern', 'path', 'url', ]; const UNNAMED_TASK = 'background task'; const SYSTEM_REMINDER = '<system-reminder>'; export interface ListedAgent { id: string; description: string; status: string; } function firstLine(text: string): string { const line = text.split('\n').find((part) => part.trim() !== '') ?? ''; return line.replace(/\s+/g, ' ').trim(); } export function runningAgents<A extends ListedAgent>(list: readonly A[]): A[] { return list.filter((agent) => WORKING_STATUSES.has(agent.status)); } export function subagentTitle(running: readonly ListedAgent[]): string | null { const newest = running.at(-1); if (!newest) return null; return `${SUBAGENT_PREFIX}${firstLine(newest.description) || UNNAMED_TASK}`; } export function finishedSince(seen: readonly string[], list: readonly ListedAgent[]): string[] { const working = new Set(runningAgents(list).map((agent) => agent.id)); return seen.filter((id) => !working.has(id)); } export function toolLine(tool: string, input: unknown): string { const fields = typeof input === 'object' && input !== null ? (input as Record<string, unknown>) : {}; for (const field of INPUT_FIELDS) { const value = fields[field]; if (typeof value === 'string' && firstLine(value) !== '') return `${tool}: ${firstLine(value)}`; } return tool; } export function activityLine(message: { content?: unknown }): string | null { if (!Array.isArray(message.content)) return null; for (const block of message.content as Array<Record<string, unknown>>) { if (block.type === 'text' && typeof block.text === 'string') { const line = firstLine(block.text); if (line !== '' && !line.startsWith(SYSTEM_REMINDER)) return line; } if (block.type === 'tool_use' && typeof block.name === 'string') { return toolLine(block.name, block.input); } } return null; } export function pushActivity(lines: readonly string[], line: string | null): string[] { if (line === null || line === lines[0]) return [...lines]; return [line, ...lines].slice(0, ACTIVITY_LINES); }