@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.
- package/dist/index.d.ts +6 -2
- package/dist/index.js +27 -1
- package/dist/meta-tools/registry.js +4 -2
- package/dist/team/activity.d.ts +21 -0
- package/dist/team/activity.js +34 -0
- package/dist/team/agent-selection.d.ts +53 -0
- package/dist/team/agent-selection.js +88 -0
- package/dist/team/artifacts.d.ts +175 -0
- package/dist/team/artifacts.js +279 -0
- package/dist/team/collision-utils.d.ts +16 -0
- package/dist/team/collision-utils.js +28 -0
- package/dist/team/context-resolver.d.ts +97 -0
- package/dist/team/context-resolver.js +322 -0
- package/dist/team/custom-agents.d.ts +68 -0
- package/dist/team/custom-agents.js +150 -0
- package/dist/team/delegation-tracker.d.ts +147 -0
- package/dist/team/delegation-tracker.js +215 -0
- package/dist/team/index.d.ts +34 -0
- package/dist/team/index.js +30 -0
- package/dist/team/interfaces.d.ts +36 -0
- package/dist/team/interfaces.js +7 -0
- package/dist/team/mention-parser.d.ts +64 -0
- package/dist/team/mention-parser.js +138 -0
- package/dist/team/shared-context.d.ts +293 -0
- package/dist/team/shared-context.js +673 -0
- package/dist/team/skill-requirements.d.ts +66 -0
- package/dist/team/skill-requirements.js +178 -0
- package/dist/team/task-assignment.d.ts +69 -0
- package/dist/team/task-assignment.js +123 -0
- package/dist/team/task-suggestion.d.ts +31 -0
- package/dist/team/task-suggestion.js +84 -0
- package/dist/team/team-agent.d.ts +201 -0
- package/dist/team/team-agent.js +492 -0
- package/dist/team/team.d.ts +297 -0
- package/dist/team/team.js +615 -0
- package/dist/team/tool-config.d.ts +110 -0
- package/dist/team/tool-config.js +739 -0
- package/dist/team/types.d.ts +211 -0
- package/dist/team/types.js +638 -0
- 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,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
|
+
}
|