@compilr-dev/sdk 0.1.28 → 0.2.1

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 (41) hide show
  1. package/dist/agent.js +16 -4
  2. package/dist/config.d.ts +12 -1
  3. package/dist/index.d.ts +6 -2
  4. package/dist/index.js +27 -1
  5. package/dist/team/activity.d.ts +21 -0
  6. package/dist/team/activity.js +34 -0
  7. package/dist/team/agent-selection.d.ts +53 -0
  8. package/dist/team/agent-selection.js +88 -0
  9. package/dist/team/artifacts.d.ts +175 -0
  10. package/dist/team/artifacts.js +279 -0
  11. package/dist/team/collision-utils.d.ts +16 -0
  12. package/dist/team/collision-utils.js +28 -0
  13. package/dist/team/context-resolver.d.ts +97 -0
  14. package/dist/team/context-resolver.js +322 -0
  15. package/dist/team/custom-agents.d.ts +68 -0
  16. package/dist/team/custom-agents.js +150 -0
  17. package/dist/team/delegation-tracker.d.ts +147 -0
  18. package/dist/team/delegation-tracker.js +215 -0
  19. package/dist/team/index.d.ts +34 -0
  20. package/dist/team/index.js +30 -0
  21. package/dist/team/interfaces.d.ts +36 -0
  22. package/dist/team/interfaces.js +7 -0
  23. package/dist/team/mention-parser.d.ts +64 -0
  24. package/dist/team/mention-parser.js +138 -0
  25. package/dist/team/shared-context.d.ts +293 -0
  26. package/dist/team/shared-context.js +673 -0
  27. package/dist/team/skill-requirements.d.ts +66 -0
  28. package/dist/team/skill-requirements.js +178 -0
  29. package/dist/team/task-assignment.d.ts +69 -0
  30. package/dist/team/task-assignment.js +123 -0
  31. package/dist/team/task-suggestion.d.ts +31 -0
  32. package/dist/team/task-suggestion.js +84 -0
  33. package/dist/team/team-agent.d.ts +201 -0
  34. package/dist/team/team-agent.js +492 -0
  35. package/dist/team/team.d.ts +297 -0
  36. package/dist/team/team.js +615 -0
  37. package/dist/team/tool-config.d.ts +110 -0
  38. package/dist/team/tool-config.js +739 -0
  39. package/dist/team/types.d.ts +211 -0
  40. package/dist/team/types.js +638 -0
  41. package/package.json +1 -1
@@ -0,0 +1,215 @@
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
+ import { randomUUID } from 'crypto';
10
+ // =============================================================================
11
+ // Tracker Class
12
+ // =============================================================================
13
+ export class DelegationTracker extends EventEmitter {
14
+ delegations = new Map();
15
+ completionQueue = [];
16
+ /**
17
+ * Create a new delegation.
18
+ */
19
+ create(options) {
20
+ const delegation = {
21
+ id: `del_${randomUUID().slice(0, 8)}`,
22
+ coordinatorId: options.coordinatorId,
23
+ targetAgentId: options.targetAgentId,
24
+ task: options.task,
25
+ expectedOutput: options.expectedOutput,
26
+ todoIndex: options.todoIndex,
27
+ status: 'pending',
28
+ createdAt: new Date(),
29
+ };
30
+ this.delegations.set(delegation.id, delegation);
31
+ this.emit('delegation-created', delegation);
32
+ this.emit('count-changed', this.getStats());
33
+ return delegation;
34
+ }
35
+ /**
36
+ * Update a delegation's status.
37
+ */
38
+ updateStatus(id, status) {
39
+ const delegation = this.delegations.get(id);
40
+ if (!delegation)
41
+ return;
42
+ delegation.status = status;
43
+ this.emit('count-changed', this.getStats());
44
+ }
45
+ /**
46
+ * Mark a delegation as completed with a result.
47
+ */
48
+ complete(id, result) {
49
+ const delegation = this.delegations.get(id);
50
+ if (!delegation)
51
+ return;
52
+ delegation.status = 'completed';
53
+ delegation.result = result;
54
+ delegation.completedAt = new Date();
55
+ const event = {
56
+ delegationId: id,
57
+ agentId: delegation.targetAgentId,
58
+ status: 'completed',
59
+ result,
60
+ timestamp: new Date(),
61
+ };
62
+ this.completionQueue.push(event);
63
+ this.emit('delegation-completed', event);
64
+ this.emit('count-changed', this.getStats());
65
+ }
66
+ /**
67
+ * Mark a delegation as failed.
68
+ */
69
+ fail(id, error) {
70
+ const delegation = this.delegations.get(id);
71
+ if (!delegation)
72
+ return;
73
+ const result = {
74
+ success: false,
75
+ summary: `Failed: ${error}`,
76
+ artifactIds: [],
77
+ error,
78
+ };
79
+ delegation.status = 'failed';
80
+ delegation.result = result;
81
+ delegation.completedAt = new Date();
82
+ const event = {
83
+ delegationId: id,
84
+ agentId: delegation.targetAgentId,
85
+ status: 'failed',
86
+ result,
87
+ timestamp: new Date(),
88
+ };
89
+ this.completionQueue.push(event);
90
+ this.emit('delegation-failed', event);
91
+ this.emit('count-changed', this.getStats());
92
+ }
93
+ /**
94
+ * Mark a delegation as cancelled.
95
+ */
96
+ cancel(id) {
97
+ const delegation = this.delegations.get(id);
98
+ if (!delegation)
99
+ return;
100
+ delegation.status = 'cancelled';
101
+ delegation.completedAt = new Date();
102
+ this.emit('count-changed', this.getStats());
103
+ }
104
+ /**
105
+ * Cancel all active delegations for a specific agent.
106
+ */
107
+ cancelAllForAgent(agentId) {
108
+ const active = this.getByAgent(agentId).filter((d) => d.status === 'pending' || d.status === 'running');
109
+ for (const delegation of active) {
110
+ this.cancel(delegation.id);
111
+ }
112
+ return active.length;
113
+ }
114
+ // ===========================================================================
115
+ // Query
116
+ // ===========================================================================
117
+ /**
118
+ * Get a delegation by ID.
119
+ */
120
+ getDelegation(id) {
121
+ return this.delegations.get(id);
122
+ }
123
+ /**
124
+ * Get all delegations targeting a specific agent.
125
+ */
126
+ getByAgent(agentId) {
127
+ return Array.from(this.delegations.values()).filter((d) => d.targetAgentId === agentId);
128
+ }
129
+ /**
130
+ * Get all active (pending or running) delegations.
131
+ */
132
+ getActive() {
133
+ return Array.from(this.delegations.values()).filter((d) => d.status === 'pending' || d.status === 'running');
134
+ }
135
+ /**
136
+ * Get all delegations.
137
+ */
138
+ getAll() {
139
+ return Array.from(this.delegations.values()).sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());
140
+ }
141
+ // ===========================================================================
142
+ // Completion Events
143
+ // ===========================================================================
144
+ /**
145
+ * Check if there are pending completion events.
146
+ */
147
+ hasCompletionEvents() {
148
+ return this.completionQueue.length > 0;
149
+ }
150
+ /**
151
+ * Drain all completion events (removes them from queue).
152
+ */
153
+ drainCompletionEvents() {
154
+ const events = [...this.completionQueue];
155
+ this.completionQueue.length = 0;
156
+ return events;
157
+ }
158
+ /**
159
+ * Peek at completion events without removing them.
160
+ */
161
+ peekCompletionEvents() {
162
+ return [...this.completionQueue];
163
+ }
164
+ // ===========================================================================
165
+ // Stats
166
+ // ===========================================================================
167
+ /**
168
+ * Get delegation statistics.
169
+ */
170
+ getStats() {
171
+ let pending = 0;
172
+ let running = 0;
173
+ let completed = 0;
174
+ let failed = 0;
175
+ let cancelled = 0;
176
+ for (const d of this.delegations.values()) {
177
+ switch (d.status) {
178
+ case 'pending':
179
+ pending++;
180
+ break;
181
+ case 'running':
182
+ running++;
183
+ break;
184
+ case 'completed':
185
+ completed++;
186
+ break;
187
+ case 'failed':
188
+ failed++;
189
+ break;
190
+ case 'cancelled':
191
+ cancelled++;
192
+ break;
193
+ }
194
+ }
195
+ return {
196
+ total: this.delegations.size,
197
+ pending,
198
+ running,
199
+ completed,
200
+ failed,
201
+ cancelled,
202
+ };
203
+ }
204
+ // ===========================================================================
205
+ // Cleanup
206
+ // ===========================================================================
207
+ /**
208
+ * Clear all delegations and completion events.
209
+ */
210
+ clear() {
211
+ this.delegations.clear();
212
+ this.completionQueue.length = 0;
213
+ this.emit('count-changed', this.getStats());
214
+ }
215
+ }
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Multi-agent team orchestration module
3
+ *
4
+ * Provides the complete team system for managing multiple persistent agents
5
+ * with shared context, artifacts, delegation tracking, and role-based access.
6
+ */
7
+ export { AgentTeam } from './team.js';
8
+ export type { AgentTeamConfig } from './team.js';
9
+ export { TeamAgent } from './team-agent.js';
10
+ export { SharedContextManager } from './shared-context.js';
11
+ export type { SharedContext, SharedProjectInfo, SharedTeamInfo, TeamRosterEntry, TeamActivity, TeamActivityType, SharedDecision, TokenBudget, SerializedSharedContext, } from './shared-context.js';
12
+ export { ArtifactStore } from './artifacts.js';
13
+ export type { Artifact, ArtifactType, ArtifactSummary, CreateArtifactOptions, UpdateArtifactOptions, SerializedArtifact, } from './artifacts.js';
14
+ export type { TeamAgentConfig, SerializedTeamAgent, TeamMetadata, SerializedTeam, TeamEvent, TeamEventType, TeamEventHandler, AgentRole, RoleMetadata, MascotExpression, ToolProfile, BackgroundSessionInfo, } from './types.js';
15
+ export { ROLE_METADATA, ROLE_EXPERTISE, PREDEFINED_ROLE_IDS } from './types.js';
16
+ export { TOOL_GROUPS, TOOL_PROFILES, PROFILE_INFO, getToolsForProfile, detectProfileFromTools, isProfileReadOnly, generateToolAwarenessPrompt, generateCoordinatorGuidance, generateSpecialistGuidance, } from './tool-config.js';
17
+ export type { ToolConfig, ToolTier, ToolGroup, ProfileInfo } from './tool-config.js';
18
+ export { createDefaultToolConfig, validateToolConfig, getAllGroupIds, getGroupInfo, getGroupsByTier, getGroupsForProfile, } from './tool-config.js';
19
+ export type { CustomAgentDefinition } from './custom-agents.js';
20
+ export { CUSTOM_MASCOTS, assignMascot, generateCustomAgentSystemPrompt, getCustomAgentToolFilter, getCustomAgentProfileLabel, validateAgentId, isAgentIdTaken, createCustomAgentDefinition, } from './custom-agents.js';
21
+ export type { ITeamPersistence, IArtifactStorage, ISessionRegistry } from './interfaces.js';
22
+ export type { ParsedMention, ParsedInput } from './mention-parser.js';
23
+ export { parseInputForMentions, getReferencedAgents, hasReferences, buildMessageWithContext, } from './mention-parser.js';
24
+ export type { ResolvedMention, ResolveOptions, ResolutionSource } from './context-resolver.js';
25
+ export { ContextResolver, buildContextMap } from './context-resolver.js';
26
+ export { findAgentForRole, findAgentById, getAvailableSpecialists, getSpecialistsSummary, hasSpecialists, } from './agent-selection.js';
27
+ export { suggestOwner, suggestOwners, matchesAgentExpertise } from './task-suggestion.js';
28
+ export { wouldCreateLoop, recordAssignment, getAssignmentHistory, clearAssignmentHistory, clearAllAssignmentHistory, canReassign, } from './task-assignment.js';
29
+ export { DelegationTracker } from './delegation-tracker.js';
30
+ export type { Delegation, DelegationStatus, DelegationResult, CompletionEvent, CreateDelegationOptions, DelegationStats, DelegationTrackerEvents, } from './delegation-tracker.js';
31
+ export { setActiveSharedContext, getActiveSharedContext, recordTeamActivity } from './activity.js';
32
+ export type { SkillToolRequirement } from './skill-requirements.js';
33
+ export { SKILL_REQUIREMENTS, getDefinedSkillNames, getSkillRequirements, checkSkillCompatibility, getCompatibleSkills, getAllRequiredTools, getSkillsByCategory, } from './skill-requirements.js';
34
+ export { resolveAgentIdCollision } from './collision-utils.js';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Multi-agent team orchestration module
3
+ *
4
+ * Provides the complete team system for managing multiple persistent agents
5
+ * with shared context, artifacts, delegation tracking, and role-based access.
6
+ */
7
+ // Core classes
8
+ export { AgentTeam } from './team.js';
9
+ export { TeamAgent } from './team-agent.js';
10
+ export { SharedContextManager } from './shared-context.js';
11
+ export { ArtifactStore } from './artifacts.js';
12
+ export { ROLE_METADATA, ROLE_EXPERTISE, PREDEFINED_ROLE_IDS } from './types.js';
13
+ // Tool configuration
14
+ export { TOOL_GROUPS, TOOL_PROFILES, PROFILE_INFO, getToolsForProfile, detectProfileFromTools, isProfileReadOnly, generateToolAwarenessPrompt, generateCoordinatorGuidance, generateSpecialistGuidance, } from './tool-config.js';
15
+ export { createDefaultToolConfig, validateToolConfig, getAllGroupIds, getGroupInfo, getGroupsByTier, getGroupsForProfile, } from './tool-config.js';
16
+ export { CUSTOM_MASCOTS, assignMascot, generateCustomAgentSystemPrompt, getCustomAgentToolFilter, getCustomAgentProfileLabel, validateAgentId, isAgentIdTaken, createCustomAgentDefinition, } from './custom-agents.js';
17
+ export { parseInputForMentions, getReferencedAgents, hasReferences, buildMessageWithContext, } from './mention-parser.js';
18
+ export { ContextResolver, buildContextMap } from './context-resolver.js';
19
+ // Agent selection
20
+ export { findAgentForRole, findAgentById, getAvailableSpecialists, getSpecialistsSummary, hasSpecialists, } from './agent-selection.js';
21
+ // Task management
22
+ export { suggestOwner, suggestOwners, matchesAgentExpertise } from './task-suggestion.js';
23
+ export { wouldCreateLoop, recordAssignment, getAssignmentHistory, clearAssignmentHistory, clearAllAssignmentHistory, canReassign, } from './task-assignment.js';
24
+ // Delegation tracking
25
+ export { DelegationTracker } from './delegation-tracker.js';
26
+ // Activity recording
27
+ export { setActiveSharedContext, getActiveSharedContext, recordTeamActivity } from './activity.js';
28
+ export { SKILL_REQUIREMENTS, getDefinedSkillNames, getSkillRequirements, checkSkillCompatibility, getCompatibleSkills, getAllRequiredTools, getSkillsByCategory, } from './skill-requirements.js';
29
+ // Collision utils
30
+ export { resolveAgentIdCollision } from './collision-utils.js';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Abstraction interfaces for team persistence and storage.
3
+ *
4
+ * Consumers (CLI, Desktop) implement these to provide
5
+ * platform-specific persistence (filesystem, SQLite, IDB, etc.)
6
+ */
7
+ import type { SerializedTeam } from './types.js';
8
+ import type { Artifact, SerializedArtifact } from './artifacts.js';
9
+ /**
10
+ * Persistence for team state (serialization/restore)
11
+ */
12
+ export interface ITeamPersistence {
13
+ saveTeam(team: SerializedTeam): Promise<void>;
14
+ loadTeam(teamId: string): Promise<SerializedTeam | null>;
15
+ }
16
+ /**
17
+ * Storage for team artifacts
18
+ */
19
+ export interface IArtifactStorage {
20
+ read(id: string): Promise<Artifact | null>;
21
+ write(artifact: Artifact): Promise<void>;
22
+ list(): Promise<Artifact[]>;
23
+ delete(id: string): Promise<void>;
24
+ }
25
+ /**
26
+ * Serialized artifact data for persistence
27
+ */
28
+ export type { SerializedArtifact };
29
+ /**
30
+ * Session registry for cross-terminal collision detection.
31
+ * CLI provides this via SQLite; desktop/other consumers may omit it.
32
+ */
33
+ export interface ISessionRegistry {
34
+ /** Get all agent IDs currently in use across all terminals */
35
+ getGlobalAgentIds(): string[];
36
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Abstraction interfaces for team persistence and storage.
3
+ *
4
+ * Consumers (CLI, Desktop) implement these to provide
5
+ * platform-specific persistence (filesystem, SQLite, IDB, etc.)
6
+ */
7
+ export {};
@@ -0,0 +1,64 @@
1
+ /**
2
+ * MentionParser - Parse $agent references in user input
3
+ *
4
+ * Two types of $agent usage:
5
+ * 1. Switch: "$arch message" at start of input → switch to arch, send message
6
+ * 2. Reference: "what did $arch propose" mid-sentence → inject arch's context
7
+ *
8
+ * Detection rule: $name at START of trimmed input = switch. Otherwise = reference.
9
+ */
10
+ /**
11
+ * A parsed mention in the input
12
+ */
13
+ export interface ParsedMention {
14
+ /** Agent ID without $ prefix */
15
+ agentId: string;
16
+ /** Position in original input */
17
+ startIndex: number;
18
+ endIndex: number;
19
+ /** The full match including $ prefix */
20
+ raw: string;
21
+ /** Optional query/context after the agent name */
22
+ context?: string;
23
+ }
24
+ /**
25
+ * Result of parsing user input for mentions
26
+ */
27
+ export interface ParsedInput {
28
+ /** Original input text */
29
+ original: string;
30
+ /** Whether the input starts with a switch ($agent at beginning) */
31
+ hasSwitch: boolean;
32
+ /** The switch target agent (if hasSwitch is true) */
33
+ switchTarget?: string;
34
+ /** Message to send after switching (if hasSwitch is true) */
35
+ messageAfterSwitch?: string;
36
+ /** All reference mentions (mid-sentence $agent) */
37
+ references: ParsedMention[];
38
+ /** Input with mentions replaced by placeholders for context injection */
39
+ normalizedInput: string;
40
+ }
41
+ /**
42
+ * Parse user input for $agent mentions
43
+ *
44
+ * @param input - User input string
45
+ * @param validAgents - Set of valid agent IDs (for validation)
46
+ * @returns Parsed input with mentions identified
47
+ */
48
+ export declare function parseInputForMentions(input: string, validAgents?: Set<string>): ParsedInput;
49
+ /**
50
+ * Get unique agent IDs from references
51
+ */
52
+ export declare function getReferencedAgents(parsed: ParsedInput): string[];
53
+ /**
54
+ * Check if input contains any references (not just switch)
55
+ */
56
+ export declare function hasReferences(parsed: ParsedInput): boolean;
57
+ /**
58
+ * Build a message with context injected for mentions
59
+ *
60
+ * @param parsed - Parsed input
61
+ * @param contextMap - Map of agentId → resolved context string
62
+ * @returns Message with context prepended or injected
63
+ */
64
+ export declare function buildMessageWithContext(parsed: ParsedInput, contextMap: Map<string, string>): string;
@@ -0,0 +1,138 @@
1
+ /**
2
+ * MentionParser - Parse $agent references in user input
3
+ *
4
+ * Two types of $agent usage:
5
+ * 1. Switch: "$arch message" at start of input → switch to arch, send message
6
+ * 2. Reference: "what did $arch propose" mid-sentence → inject arch's context
7
+ *
8
+ * Detection rule: $name at START of trimmed input = switch. Otherwise = reference.
9
+ */
10
+ // =============================================================================
11
+ // Constants
12
+ // =============================================================================
13
+ // Match $agentname pattern - alphanumeric and underscore/hyphen
14
+ const MENTION_PATTERN = /\$([a-zA-Z][a-zA-Z0-9_-]*)/g;
15
+ // Match $agent at start of input (for switch detection)
16
+ const SWITCH_PATTERN = /^\$([a-zA-Z][a-zA-Z0-9_-]*)\s*/;
17
+ // =============================================================================
18
+ // Parser
19
+ // =============================================================================
20
+ /**
21
+ * Parse user input for $agent mentions
22
+ *
23
+ * @param input - User input string
24
+ * @param validAgents - Set of valid agent IDs (for validation)
25
+ * @returns Parsed input with mentions identified
26
+ */
27
+ export function parseInputForMentions(input, validAgents) {
28
+ const trimmed = input.trim();
29
+ // Check for switch pattern at start
30
+ const switchMatch = trimmed.match(SWITCH_PATTERN);
31
+ let hasSwitch = false;
32
+ let switchTarget;
33
+ let messageAfterSwitch;
34
+ let searchStart = 0;
35
+ if (switchMatch) {
36
+ const agentId = switchMatch[1].toLowerCase();
37
+ // Only treat as switch if it's a valid agent
38
+ if (!validAgents || validAgents.has(agentId)) {
39
+ hasSwitch = true;
40
+ switchTarget = agentId;
41
+ messageAfterSwitch = trimmed.slice(switchMatch[0].length).trim();
42
+ searchStart = switchMatch[0].length; // Skip switch when looking for references
43
+ }
44
+ }
45
+ // Find all reference mentions (excluding the switch)
46
+ const references = [];
47
+ MENTION_PATTERN.lastIndex = searchStart;
48
+ let match;
49
+ while ((match = MENTION_PATTERN.exec(trimmed)) !== null) {
50
+ const agentId = match[1].toLowerCase();
51
+ // Skip if not a valid agent (if validation set provided)
52
+ if (validAgents && !validAgents.has(agentId)) {
53
+ continue;
54
+ }
55
+ // Skip if this is the switch mention
56
+ if (hasSwitch && match.index === 0) {
57
+ continue;
58
+ }
59
+ references.push({
60
+ agentId,
61
+ startIndex: match.index,
62
+ endIndex: match.index + match[0].length,
63
+ raw: match[0],
64
+ });
65
+ }
66
+ // Extract context hints for each reference
67
+ for (const ref of references) {
68
+ ref.context = extractContextHint(trimmed, ref.endIndex);
69
+ }
70
+ // Build normalized input (with mention placeholders)
71
+ const normalizedInput = hasSwitch ? (messageAfterSwitch ?? '') : trimmed;
72
+ return {
73
+ original: input,
74
+ hasSwitch,
75
+ switchTarget,
76
+ messageAfterSwitch,
77
+ references,
78
+ normalizedInput,
79
+ };
80
+ }
81
+ /**
82
+ * Extract a context hint following a mention
83
+ *
84
+ * Examples:
85
+ * - "what did $arch propose for the API" → "propose for the API"
86
+ * - "review $qa's feedback on the PR" → "'s feedback on the PR"
87
+ * - "based on $arch" → undefined
88
+ */
89
+ function extractContextHint(text, afterIndex) {
90
+ const remaining = text.slice(afterIndex);
91
+ // Get up to end of sentence or 50 chars
92
+ const endMatch = remaining.match(/^[^.!?\n]{0,50}/);
93
+ if (!endMatch || endMatch[0].trim().length < 3) {
94
+ return undefined;
95
+ }
96
+ return endMatch[0].trim();
97
+ }
98
+ /**
99
+ * Get unique agent IDs from references
100
+ */
101
+ export function getReferencedAgents(parsed) {
102
+ const agents = new Set();
103
+ for (const ref of parsed.references) {
104
+ agents.add(ref.agentId);
105
+ }
106
+ return Array.from(agents);
107
+ }
108
+ /**
109
+ * Check if input contains any references (not just switch)
110
+ */
111
+ export function hasReferences(parsed) {
112
+ return parsed.references.length > 0;
113
+ }
114
+ /**
115
+ * Build a message with context injected for mentions
116
+ *
117
+ * @param parsed - Parsed input
118
+ * @param contextMap - Map of agentId → resolved context string
119
+ * @returns Message with context prepended or injected
120
+ */
121
+ export function buildMessageWithContext(parsed, contextMap) {
122
+ if (parsed.references.length === 0) {
123
+ return parsed.normalizedInput;
124
+ }
125
+ // Collect context blocks
126
+ const contextBlocks = [];
127
+ for (const ref of parsed.references) {
128
+ const context = contextMap.get(ref.agentId);
129
+ if (context) {
130
+ contextBlocks.push(`[Context from $${ref.agentId}:\n${context}\n]`);
131
+ }
132
+ }
133
+ if (contextBlocks.length === 0) {
134
+ return parsed.normalizedInput;
135
+ }
136
+ // Prepend context blocks to the message
137
+ return `${contextBlocks.join('\n\n')}\n\n${parsed.normalizedInput}`;
138
+ }