@compilr-dev/sdk 0.1.27 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/index.d.ts +6 -2
  2. package/dist/index.js +27 -1
  3. package/dist/meta-tools/registry.js +4 -2
  4. package/dist/team/activity.d.ts +21 -0
  5. package/dist/team/activity.js +34 -0
  6. package/dist/team/agent-selection.d.ts +53 -0
  7. package/dist/team/agent-selection.js +88 -0
  8. package/dist/team/artifacts.d.ts +175 -0
  9. package/dist/team/artifacts.js +279 -0
  10. package/dist/team/collision-utils.d.ts +16 -0
  11. package/dist/team/collision-utils.js +28 -0
  12. package/dist/team/context-resolver.d.ts +97 -0
  13. package/dist/team/context-resolver.js +322 -0
  14. package/dist/team/custom-agents.d.ts +68 -0
  15. package/dist/team/custom-agents.js +150 -0
  16. package/dist/team/delegation-tracker.d.ts +147 -0
  17. package/dist/team/delegation-tracker.js +215 -0
  18. package/dist/team/index.d.ts +34 -0
  19. package/dist/team/index.js +30 -0
  20. package/dist/team/interfaces.d.ts +36 -0
  21. package/dist/team/interfaces.js +7 -0
  22. package/dist/team/mention-parser.d.ts +64 -0
  23. package/dist/team/mention-parser.js +138 -0
  24. package/dist/team/shared-context.d.ts +293 -0
  25. package/dist/team/shared-context.js +673 -0
  26. package/dist/team/skill-requirements.d.ts +66 -0
  27. package/dist/team/skill-requirements.js +178 -0
  28. package/dist/team/task-assignment.d.ts +69 -0
  29. package/dist/team/task-assignment.js +123 -0
  30. package/dist/team/task-suggestion.d.ts +31 -0
  31. package/dist/team/task-suggestion.js +84 -0
  32. package/dist/team/team-agent.d.ts +201 -0
  33. package/dist/team/team-agent.js +492 -0
  34. package/dist/team/team.d.ts +297 -0
  35. package/dist/team/team.js +615 -0
  36. package/dist/team/tool-config.d.ts +110 -0
  37. package/dist/team/tool-config.js +739 -0
  38. package/dist/team/types.d.ts +211 -0
  39. package/dist/team/types.js +638 -0
  40. package/package.json +1 -1
@@ -0,0 +1,322 @@
1
+ /**
2
+ * ContextResolver - Resolve $agent mentions to actual content
3
+ *
4
+ * Resolution strategy:
5
+ * 1. Check for explicit artifact reference in context hint
6
+ * 2. Search artifacts by name/content matching context hint
7
+ * 3. Fall back to recent conversation history
8
+ *
9
+ * Token budgets:
10
+ * - Single mention: 2000 tokens max
11
+ * - Multiple mentions: 3000 tokens total, split among mentions
12
+ */
13
+ // =============================================================================
14
+ // Constants
15
+ // =============================================================================
16
+ const DEFAULT_MAX_TOKENS_PER_MENTION = 2000;
17
+ const DEFAULT_MAX_TOTAL_TOKENS = 3000;
18
+ const DEFAULT_MAX_HISTORY_MESSAGES = 10;
19
+ /**
20
+ * Simple token estimation: ~4 chars per token
21
+ */
22
+ function estimateTokens(text) {
23
+ return Math.ceil(text.length / 4);
24
+ }
25
+ // =============================================================================
26
+ // ContextResolver
27
+ // =============================================================================
28
+ /**
29
+ * Resolve mentions to actual content
30
+ */
31
+ export class ContextResolver {
32
+ team;
33
+ artifactStore;
34
+ constructor(team, artifactStore) {
35
+ this.team = team;
36
+ this.artifactStore = artifactStore;
37
+ }
38
+ /**
39
+ * Resolve multiple mentions
40
+ */
41
+ resolveAll(mentions, options = {}) {
42
+ const maxTotal = options.maxTotalTokens ?? DEFAULT_MAX_TOTAL_TOKENS;
43
+ const perMention = options.maxTokensPerMention ?? DEFAULT_MAX_TOKENS_PER_MENTION;
44
+ // Calculate budget per mention
45
+ const budgetPerMention = Math.min(perMention, Math.floor(maxTotal / mentions.length));
46
+ const results = new Map();
47
+ let totalTokens = 0;
48
+ for (const mention of mentions) {
49
+ // Skip if we're out of budget
50
+ if (totalTokens >= maxTotal) {
51
+ results.set(mention.agentId, {
52
+ mention,
53
+ resolved: false,
54
+ source: 'not_found',
55
+ sourceName: 'budget exceeded',
56
+ content: '',
57
+ tokenCount: 0,
58
+ });
59
+ continue;
60
+ }
61
+ const remainingBudget = Math.min(budgetPerMention, maxTotal - totalTokens);
62
+ const resolved = this.resolveMention(mention, {
63
+ ...options,
64
+ maxTokensPerMention: remainingBudget,
65
+ });
66
+ results.set(mention.agentId, resolved);
67
+ totalTokens += resolved.tokenCount;
68
+ }
69
+ return results;
70
+ }
71
+ /**
72
+ * Resolve a single mention
73
+ */
74
+ resolveMention(mention, options = {}) {
75
+ const maxTokens = options.maxTokensPerMention ?? DEFAULT_MAX_TOKENS_PER_MENTION;
76
+ // 1. Try to find matching artifact
77
+ const artifactResult = this.resolveFromArtifacts(mention, maxTokens, options);
78
+ if (artifactResult) {
79
+ return artifactResult;
80
+ }
81
+ // 2. Try to extract from conversation history
82
+ const historyResult = this.resolveFromHistory(mention, maxTokens, options);
83
+ if (historyResult) {
84
+ return historyResult;
85
+ }
86
+ // 3. Not found
87
+ return {
88
+ mention,
89
+ resolved: false,
90
+ source: 'not_found',
91
+ sourceName: 'no relevant content found',
92
+ content: '',
93
+ tokenCount: 0,
94
+ };
95
+ }
96
+ /**
97
+ * Resolve from artifacts
98
+ */
99
+ resolveFromArtifacts(mention, maxTokens, options) {
100
+ const { agentId, context } = mention;
101
+ // Get artifacts by this agent
102
+ const agentArtifacts = this.artifactStore.listByAgent(agentId);
103
+ if (agentArtifacts.length === 0) {
104
+ return null;
105
+ }
106
+ // Sort artifacts by most recent first
107
+ const sortedArtifacts = agentArtifacts.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
108
+ // Find matching artifact based on context hint
109
+ let matchedArtifact;
110
+ if (context) {
111
+ // Search by name or content
112
+ const searchResults = this.artifactStore.search(context);
113
+ const searchMatch = searchResults.find((a) => a.agent === agentId);
114
+ // Use search match if found, otherwise fall back to most recent
115
+ matchedArtifact = searchMatch ?? sortedArtifacts[0];
116
+ }
117
+ else {
118
+ // No context hint - use most recent artifact
119
+ matchedArtifact = sortedArtifacts[0];
120
+ }
121
+ // Format artifact content
122
+ let content;
123
+ let tokenCount;
124
+ if (options.includeFullArtifact) {
125
+ content = this.formatArtifactFull(matchedArtifact);
126
+ tokenCount = estimateTokens(content);
127
+ // If over budget, fall back to summary
128
+ if (tokenCount > maxTokens) {
129
+ content = this.formatArtifactSummary(matchedArtifact);
130
+ tokenCount = estimateTokens(content);
131
+ }
132
+ }
133
+ else {
134
+ // Start with summary, include full if within budget
135
+ const summary = this.formatArtifactSummary(matchedArtifact);
136
+ const full = this.formatArtifactFull(matchedArtifact);
137
+ if (estimateTokens(full) <= maxTokens) {
138
+ content = full;
139
+ }
140
+ else {
141
+ content = summary;
142
+ }
143
+ tokenCount = estimateTokens(content);
144
+ }
145
+ return {
146
+ mention,
147
+ resolved: true,
148
+ source: 'artifact',
149
+ sourceName: matchedArtifact.name,
150
+ content,
151
+ tokenCount,
152
+ };
153
+ }
154
+ /**
155
+ * Resolve from conversation history
156
+ */
157
+ resolveFromHistory(mention, maxTokens, options) {
158
+ const { agentId, context } = mention;
159
+ const maxMessages = options.maxHistoryMessages ?? DEFAULT_MAX_HISTORY_MESSAGES;
160
+ // Get the team agent
161
+ const teamAgent = this.team.get(agentId);
162
+ if (!teamAgent) {
163
+ return null;
164
+ }
165
+ // Get the underlying agent
166
+ const agent = teamAgent.agent;
167
+ if (!agent) {
168
+ return null;
169
+ }
170
+ // Get recent messages from the agent's history
171
+ const state = agent.serialize();
172
+ const messages = state.messages;
173
+ if (messages.length === 0) {
174
+ return null;
175
+ }
176
+ // Get assistant messages (agent's responses)
177
+ const assistantMessages = messages
178
+ .filter((m) => m.role === 'assistant')
179
+ .slice(-maxMessages);
180
+ if (assistantMessages.length === 0) {
181
+ return null;
182
+ }
183
+ // Extract relevant content
184
+ let relevantContent;
185
+ if (context) {
186
+ // Search for context in messages
187
+ relevantContent = this.extractRelevantContent(assistantMessages, context, maxTokens);
188
+ }
189
+ else {
190
+ // Use most recent message
191
+ const lastMessage = assistantMessages[assistantMessages.length - 1];
192
+ relevantContent = this.formatMessage(lastMessage);
193
+ }
194
+ if (!relevantContent) {
195
+ return null;
196
+ }
197
+ // Truncate if needed
198
+ const tokenCount = estimateTokens(relevantContent);
199
+ if (tokenCount > maxTokens) {
200
+ relevantContent = this.truncateToTokens(relevantContent, maxTokens);
201
+ }
202
+ return {
203
+ mention,
204
+ resolved: true,
205
+ source: 'history',
206
+ sourceName: 'recent conversation',
207
+ content: relevantContent,
208
+ tokenCount: estimateTokens(relevantContent),
209
+ };
210
+ }
211
+ /**
212
+ * Extract relevant content from messages based on context hint
213
+ */
214
+ extractRelevantContent(messages, context, maxTokens) {
215
+ const keywords = context
216
+ .toLowerCase()
217
+ .split(/\s+/)
218
+ .filter((w) => w.length > 2);
219
+ // Score messages by relevance
220
+ const scored = messages.map((msg) => {
221
+ const content = this.formatMessage(msg);
222
+ const contentLower = content.toLowerCase();
223
+ let score = 0;
224
+ for (const keyword of keywords) {
225
+ if (contentLower.includes(keyword)) {
226
+ score += 1;
227
+ }
228
+ }
229
+ return { content, score };
230
+ });
231
+ // Sort by score (highest first)
232
+ scored.sort((a, b) => b.score - a.score);
233
+ // Take best matches within token budget
234
+ const results = [];
235
+ let totalTokens = 0;
236
+ for (const { content, score } of scored) {
237
+ if (score === 0)
238
+ continue;
239
+ const tokens = estimateTokens(content);
240
+ if (totalTokens + tokens > maxTokens) {
241
+ // Try to include truncated version
242
+ const remaining = maxTokens - totalTokens;
243
+ if (remaining > 100) {
244
+ results.push(this.truncateToTokens(content, remaining));
245
+ }
246
+ break;
247
+ }
248
+ results.push(content);
249
+ totalTokens += tokens;
250
+ }
251
+ return results.join('\n\n---\n\n');
252
+ }
253
+ /**
254
+ * Format a message for injection
255
+ */
256
+ formatMessage(message) {
257
+ if (typeof message.content === 'string') {
258
+ return message.content;
259
+ }
260
+ // Handle array content (Claude format)
261
+ if (Array.isArray(message.content)) {
262
+ const blocks = message.content;
263
+ return blocks
264
+ .filter((block) => block.type === 'text' && typeof block.text === 'string')
265
+ .map((block) => block.text)
266
+ .join('\n');
267
+ }
268
+ return String(message.content);
269
+ }
270
+ /**
271
+ * Format artifact with full content
272
+ */
273
+ formatArtifactFull(artifact) {
274
+ return [
275
+ `**${artifact.name}** (${artifact.type})`,
276
+ `By: $${artifact.agent} | Updated: ${artifact.updatedAt.toLocaleDateString()}`,
277
+ '',
278
+ artifact.content,
279
+ ].join('\n');
280
+ }
281
+ /**
282
+ * Format artifact with summary only
283
+ */
284
+ formatArtifactSummary(artifact) {
285
+ return [
286
+ `**${artifact.name}** (${artifact.type})`,
287
+ `By: $${artifact.agent} | Updated: ${artifact.updatedAt.toLocaleDateString()}`,
288
+ '',
289
+ `Summary: ${artifact.summary}`,
290
+ '',
291
+ `[Full content available via artifact store]`,
292
+ ].join('\n');
293
+ }
294
+ /**
295
+ * Truncate content to approximate token count
296
+ */
297
+ truncateToTokens(content, maxTokens) {
298
+ const maxChars = maxTokens * 4;
299
+ if (content.length <= maxChars) {
300
+ return content;
301
+ }
302
+ // Truncate at word boundary
303
+ const truncated = content.slice(0, maxChars);
304
+ const lastSpace = truncated.lastIndexOf(' ');
305
+ if (lastSpace > maxChars * 0.8) {
306
+ return truncated.slice(0, lastSpace) + '...';
307
+ }
308
+ return truncated + '...';
309
+ }
310
+ }
311
+ /**
312
+ * Build a context map from resolved mentions
313
+ */
314
+ export function buildContextMap(resolved) {
315
+ const contextMap = new Map();
316
+ for (const [agentId, resolution] of resolved) {
317
+ if (resolution.resolved && resolution.content) {
318
+ contextMap.set(agentId, resolution.content);
319
+ }
320
+ }
321
+ return contextMap;
322
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Custom Agent Definitions
3
+ *
4
+ * Enables users to create custom specialized agents beyond predefined templates.
5
+ * Custom agents have user-defined names, specialties, and personalities.
6
+ *
7
+ * This SDK version contains only types and pure functions.
8
+ * Consumers handle their own persistence (load/save).
9
+ */
10
+ import { type ToolConfig, type ToolProfile } from './tool-config.js';
11
+ import type { ModelTier } from '../models/index.js';
12
+ export interface CustomAgentDefinition {
13
+ id: string;
14
+ displayName: string;
15
+ specialty: string;
16
+ personality?: string;
17
+ mascot: string;
18
+ createdAt: string;
19
+ toolConfig?: ToolConfig;
20
+ enabledSkills?: string[];
21
+ modelTier?: ModelTier;
22
+ }
23
+ export type { ToolConfig, ToolProfile };
24
+ /**
25
+ * Mascots available for custom agents.
26
+ * These are distinct from predefined role mascots.
27
+ */
28
+ export declare const CUSTOM_MASCOTS: string[];
29
+ /**
30
+ * Assign a mascot from the available pool.
31
+ * Avoids mascots already in use by other custom agents.
32
+ */
33
+ export declare function assignMascot(existingAgents: CustomAgentDefinition[]): string;
34
+ /**
35
+ * Generate system prompt for a custom agent.
36
+ * Uses a template-based approach (no LLM call).
37
+ * Includes tool awareness if the agent has tool restrictions.
38
+ */
39
+ export declare function generateCustomAgentSystemPrompt(agent: CustomAgentDefinition): string;
40
+ /**
41
+ * Get the tool filter (list of allowed tools) for a custom agent.
42
+ * Returns undefined for full access (no filtering).
43
+ */
44
+ export declare function getCustomAgentToolFilter(agent: CustomAgentDefinition): string[] | undefined;
45
+ /**
46
+ * Get the profile display name for a custom agent.
47
+ */
48
+ export declare function getCustomAgentProfileLabel(agent: CustomAgentDefinition): string;
49
+ /**
50
+ * Validate agent ID format.
51
+ * Must be lowercase letters, numbers, and underscores.
52
+ * Must start with a letter.
53
+ */
54
+ export declare function validateAgentId(id: string): {
55
+ valid: boolean;
56
+ error?: string;
57
+ };
58
+ /**
59
+ * Check if agent ID is already in use.
60
+ */
61
+ export declare function isAgentIdTaken(id: string, existingCustomAgents: CustomAgentDefinition[], teamAgentIds: string[], predefinedRoleIds: string[]): {
62
+ taken: boolean;
63
+ reason?: string;
64
+ };
65
+ /**
66
+ * Create a new CustomAgentDefinition with auto-assigned mascot.
67
+ */
68
+ export declare function createCustomAgentDefinition(id: string, displayName: string, specialty: string, personality: string | undefined, existingAgents: CustomAgentDefinition[], toolConfig?: ToolConfig, enabledSkills?: string[], modelTier?: ModelTier): CustomAgentDefinition;
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Custom Agent Definitions
3
+ *
4
+ * Enables users to create custom specialized agents beyond predefined templates.
5
+ * Custom agents have user-defined names, specialties, and personalities.
6
+ *
7
+ * This SDK version contains only types and pure functions.
8
+ * Consumers handle their own persistence (load/save).
9
+ */
10
+ import { createDefaultToolConfig, getToolsForProfile, generateToolAwarenessPrompt, PROFILE_INFO, } from './tool-config.js';
11
+ // =============================================================================
12
+ // Mascot Pool for Custom Agents
13
+ // =============================================================================
14
+ /**
15
+ * Mascots available for custom agents.
16
+ * These are distinct from predefined role mascots.
17
+ */
18
+ export const CUSTOM_MASCOTS = [
19
+ '[⊡_⊡]',
20
+ '[⊞_⊞]',
21
+ '[⊟_⊟]',
22
+ '[⊠_⊠]',
23
+ '[⋈_⋈]',
24
+ '[⋐_⋐]',
25
+ '[⋑_⋑]',
26
+ '[⋒_⋒]',
27
+ '[◌_◌]',
28
+ '[◍_◍]',
29
+ '[●_●]',
30
+ '[◐_◐]',
31
+ '[◑_◑]',
32
+ '[◒_◒]',
33
+ '[◓_◓]',
34
+ '[◔_◔]',
35
+ ];
36
+ /**
37
+ * Assign a mascot from the available pool.
38
+ * Avoids mascots already in use by other custom agents.
39
+ */
40
+ export function assignMascot(existingAgents) {
41
+ const usedMascots = new Set(existingAgents.map((a) => a.mascot));
42
+ const available = CUSTOM_MASCOTS.filter((m) => !usedMascots.has(m));
43
+ if (available.length > 0) {
44
+ return available[0];
45
+ }
46
+ // Fall back to random selection if all are used
47
+ return CUSTOM_MASCOTS[Math.floor(Math.random() * CUSTOM_MASCOTS.length)];
48
+ }
49
+ // =============================================================================
50
+ // System Prompt Generation
51
+ // =============================================================================
52
+ /**
53
+ * Generate system prompt for a custom agent.
54
+ * Uses a template-based approach (no LLM call).
55
+ * Includes tool awareness if the agent has tool restrictions.
56
+ */
57
+ export function generateCustomAgentSystemPrompt(agent) {
58
+ const lines = [`You are a ${agent.displayName} specialized in ${agent.specialty}.`];
59
+ if (agent.personality) {
60
+ lines.push('');
61
+ lines.push(`Your approach: ${agent.personality}`);
62
+ }
63
+ lines.push('');
64
+ lines.push('Focus on your area of expertise. When questions fall outside your specialty, suggest which team member might be better suited to help.');
65
+ // Add tool awareness if agent has tool restrictions
66
+ const toolConfig = agent.toolConfig ?? createDefaultToolConfig();
67
+ if (toolConfig.profile !== 'full') {
68
+ lines.push('');
69
+ lines.push('---');
70
+ lines.push('');
71
+ lines.push(generateToolAwarenessPrompt(toolConfig));
72
+ }
73
+ return lines.join('\n');
74
+ }
75
+ /**
76
+ * Get the tool filter (list of allowed tools) for a custom agent.
77
+ * Returns undefined for full access (no filtering).
78
+ */
79
+ export function getCustomAgentToolFilter(agent) {
80
+ const toolConfig = agent.toolConfig ?? createDefaultToolConfig();
81
+ return getToolsForProfile(toolConfig.profile, toolConfig.customGroups);
82
+ }
83
+ /**
84
+ * Get the profile display name for a custom agent.
85
+ */
86
+ export function getCustomAgentProfileLabel(agent) {
87
+ const toolConfig = agent.toolConfig ?? createDefaultToolConfig();
88
+ const info = PROFILE_INFO[toolConfig.profile];
89
+ return info.label;
90
+ }
91
+ // =============================================================================
92
+ // Validation
93
+ // =============================================================================
94
+ /**
95
+ * Validate agent ID format.
96
+ * Must be lowercase letters, numbers, and underscores.
97
+ * Must start with a letter.
98
+ */
99
+ export function validateAgentId(id) {
100
+ if (!id || id.trim() === '') {
101
+ return { valid: false, error: 'Agent ID is required' };
102
+ }
103
+ if (id.length > 20) {
104
+ return { valid: false, error: 'Agent ID must be 20 characters or less' };
105
+ }
106
+ if (!/^[a-z][a-z0-9_]*$/.test(id)) {
107
+ return {
108
+ valid: false,
109
+ error: 'Must be lowercase letters, numbers, underscore (start with letter)',
110
+ };
111
+ }
112
+ return { valid: true };
113
+ }
114
+ /**
115
+ * Check if agent ID is already in use.
116
+ */
117
+ export function isAgentIdTaken(id, existingCustomAgents, teamAgentIds, predefinedRoleIds) {
118
+ // Check predefined roles
119
+ if (predefinedRoleIds.includes(id)) {
120
+ return { taken: true, reason: `"${id}" is a predefined role` };
121
+ }
122
+ // Check team agents
123
+ if (teamAgentIds.includes(id)) {
124
+ return { taken: true, reason: `"${id}" is already in your team` };
125
+ }
126
+ // Check custom agents
127
+ if (existingCustomAgents.some((a) => a.id === id)) {
128
+ return { taken: true, reason: `"${id}" already exists as a custom agent` };
129
+ }
130
+ return { taken: false };
131
+ }
132
+ // =============================================================================
133
+ // Factory
134
+ // =============================================================================
135
+ /**
136
+ * Create a new CustomAgentDefinition with auto-assigned mascot.
137
+ */
138
+ export function createCustomAgentDefinition(id, displayName, specialty, personality, existingAgents, toolConfig, enabledSkills, modelTier) {
139
+ return {
140
+ id,
141
+ displayName,
142
+ specialty,
143
+ personality: personality || undefined,
144
+ mascot: assignMascot(existingAgents),
145
+ createdAt: new Date().toISOString(),
146
+ toolConfig: toolConfig ?? createDefaultToolConfig(),
147
+ enabledSkills: enabledSkills ?? [], // Empty = all skills
148
+ modelTier: modelTier ?? 'balanced', // Default tier
149
+ };
150
+ }
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Delegation Tracker (Coordinator Mode)
3
+ *
4
+ * Tracks active delegations from the coordinator to background specialists.
5
+ * Maintains a completion event queue so the coordinator can be notified
6
+ * when specialists finish their work.
7
+ */
8
+ import { EventEmitter } from 'events';
9
+ export type DelegationStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled';
10
+ export interface Delegation {
11
+ /** Unique delegation ID (del_<uuid>) */
12
+ id: string;
13
+ /** Agent that initiated the delegation (always 'default' for now) */
14
+ coordinatorId: string;
15
+ /** Target specialist agent ID (e.g., 'arch', 'dev', 'qa') */
16
+ targetAgentId: string;
17
+ /** Task description sent to the specialist */
18
+ task: string;
19
+ /** What the specialist is expected to produce */
20
+ expectedOutput?: string;
21
+ /** Associated todo index (if any) */
22
+ todoIndex?: number;
23
+ /** Current status */
24
+ status: DelegationStatus;
25
+ /** Result (set on completion or failure) */
26
+ result?: DelegationResult;
27
+ /** When the delegation was created */
28
+ createdAt: Date;
29
+ /** When the delegation completed */
30
+ completedAt?: Date;
31
+ }
32
+ export interface DelegationResult {
33
+ /** Whether the task completed successfully */
34
+ success: boolean;
35
+ /** Brief outcome summary */
36
+ summary: string;
37
+ /** Artifact IDs created by the specialist */
38
+ artifactIds: string[];
39
+ /** Error message (if failed) */
40
+ error?: string;
41
+ }
42
+ export interface CompletionEvent {
43
+ /** The delegation ID */
44
+ delegationId: string;
45
+ /** The specialist that completed the work */
46
+ agentId: string;
47
+ /** Completion status */
48
+ status: 'completed' | 'failed';
49
+ /** Result details */
50
+ result: DelegationResult;
51
+ /** When the event was generated */
52
+ timestamp: Date;
53
+ }
54
+ export interface CreateDelegationOptions {
55
+ /** Agent that initiated the delegation */
56
+ coordinatorId: string;
57
+ /** Target specialist agent ID */
58
+ targetAgentId: string;
59
+ /** Task description */
60
+ task: string;
61
+ /** Expected output description */
62
+ expectedOutput?: string;
63
+ /** Associated todo index */
64
+ todoIndex?: number;
65
+ }
66
+ export interface DelegationStats {
67
+ total: number;
68
+ pending: number;
69
+ running: number;
70
+ completed: number;
71
+ failed: number;
72
+ cancelled: number;
73
+ }
74
+ export interface DelegationTrackerEvents {
75
+ /** Emitted when a new delegation is created */
76
+ 'delegation-created': (delegation: Delegation) => void;
77
+ /** Emitted when a delegation completes successfully */
78
+ 'delegation-completed': (event: CompletionEvent) => void;
79
+ /** Emitted when a delegation fails */
80
+ 'delegation-failed': (event: CompletionEvent) => void;
81
+ /** Emitted when delegation counts change */
82
+ 'count-changed': (stats: DelegationStats) => void;
83
+ }
84
+ export declare class DelegationTracker extends EventEmitter {
85
+ private readonly delegations;
86
+ private readonly completionQueue;
87
+ /**
88
+ * Create a new delegation.
89
+ */
90
+ create(options: CreateDelegationOptions): Delegation;
91
+ /**
92
+ * Update a delegation's status.
93
+ */
94
+ updateStatus(id: string, status: DelegationStatus): void;
95
+ /**
96
+ * Mark a delegation as completed with a result.
97
+ */
98
+ complete(id: string, result: DelegationResult): void;
99
+ /**
100
+ * Mark a delegation as failed.
101
+ */
102
+ fail(id: string, error: string): void;
103
+ /**
104
+ * Mark a delegation as cancelled.
105
+ */
106
+ cancel(id: string): void;
107
+ /**
108
+ * Cancel all active delegations for a specific agent.
109
+ */
110
+ cancelAllForAgent(agentId: string): number;
111
+ /**
112
+ * Get a delegation by ID.
113
+ */
114
+ getDelegation(id: string): Delegation | undefined;
115
+ /**
116
+ * Get all delegations targeting a specific agent.
117
+ */
118
+ getByAgent(agentId: string): Delegation[];
119
+ /**
120
+ * Get all active (pending or running) delegations.
121
+ */
122
+ getActive(): Delegation[];
123
+ /**
124
+ * Get all delegations.
125
+ */
126
+ getAll(): Delegation[];
127
+ /**
128
+ * Check if there are pending completion events.
129
+ */
130
+ hasCompletionEvents(): boolean;
131
+ /**
132
+ * Drain all completion events (removes them from queue).
133
+ */
134
+ drainCompletionEvents(): CompletionEvent[];
135
+ /**
136
+ * Peek at completion events without removing them.
137
+ */
138
+ peekCompletionEvents(): CompletionEvent[];
139
+ /**
140
+ * Get delegation statistics.
141
+ */
142
+ getStats(): DelegationStats;
143
+ /**
144
+ * Clear all delegations and completion events.
145
+ */
146
+ clear(): void;
147
+ }