@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,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TeamAgent - Wrapper for persistent team agents
|
|
3
|
+
*
|
|
4
|
+
* Each team agent has:
|
|
5
|
+
* - Unique identity (id, name, mascot)
|
|
6
|
+
* - Isolated conversation history
|
|
7
|
+
* - Role-specific system prompt additions
|
|
8
|
+
* - Optional tool filtering
|
|
9
|
+
*/
|
|
10
|
+
import type { Agent, AgentConfig, ContextManager } from '@compilr-dev/agents';
|
|
11
|
+
import type { TeamAgentConfig, SerializedTeamAgent, MascotExpression, AgentRole } from './types.js';
|
|
12
|
+
import type { ModelTier } from '../models/index.js';
|
|
13
|
+
import type { ProviderType } from '../config.js';
|
|
14
|
+
import type { SharedContextManager } from './shared-context.js';
|
|
15
|
+
import type { CustomAgentDefinition } from './custom-agents.js';
|
|
16
|
+
/**
|
|
17
|
+
* TeamAgent wraps an Agent instance with team-specific metadata
|
|
18
|
+
*/
|
|
19
|
+
export declare class TeamAgent {
|
|
20
|
+
/**
|
|
21
|
+
* Unique identifier (e.g., 'pm', 'arch', 'qa')
|
|
22
|
+
*/
|
|
23
|
+
readonly id: string;
|
|
24
|
+
/**
|
|
25
|
+
* Display name shown in UI
|
|
26
|
+
*/
|
|
27
|
+
readonly displayName: string;
|
|
28
|
+
/**
|
|
29
|
+
* Mascot expression for visual differentiation
|
|
30
|
+
*/
|
|
31
|
+
readonly mascot: MascotExpression;
|
|
32
|
+
/**
|
|
33
|
+
* Role type
|
|
34
|
+
*/
|
|
35
|
+
readonly role: AgentRole;
|
|
36
|
+
/**
|
|
37
|
+
* Optional description
|
|
38
|
+
*/
|
|
39
|
+
readonly description?: string;
|
|
40
|
+
/**
|
|
41
|
+
* System prompt addition specific to this agent
|
|
42
|
+
*/
|
|
43
|
+
readonly systemPromptAddition?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Use minimal system prompt - skip all modules
|
|
46
|
+
*/
|
|
47
|
+
readonly useMinimalSystemPrompt?: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* Skip all tool registration - agent has no tools
|
|
50
|
+
*/
|
|
51
|
+
readonly noTools?: boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Tool filter (tool names this agent can use)
|
|
54
|
+
*/
|
|
55
|
+
readonly toolFilter?: string[];
|
|
56
|
+
/**
|
|
57
|
+
* Tool profile name (for display)
|
|
58
|
+
*/
|
|
59
|
+
readonly toolProfile?: TeamAgentConfig['toolProfile'];
|
|
60
|
+
/**
|
|
61
|
+
* Enabled skills (empty = all skills)
|
|
62
|
+
*/
|
|
63
|
+
readonly enabledSkills?: string[];
|
|
64
|
+
/**
|
|
65
|
+
* Auto-approve handoffs from this agent without user confirmation
|
|
66
|
+
*/
|
|
67
|
+
readonly autoApproveHandoff?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Model tier (fast/balanced/powerful)
|
|
70
|
+
* Determines which model to use based on provider
|
|
71
|
+
*/
|
|
72
|
+
private _modelTier?;
|
|
73
|
+
/**
|
|
74
|
+
* The underlying agent instance
|
|
75
|
+
*/
|
|
76
|
+
private _agent;
|
|
77
|
+
/**
|
|
78
|
+
* Agent configuration for lazy initialization
|
|
79
|
+
*/
|
|
80
|
+
private readonly agentConfig;
|
|
81
|
+
/**
|
|
82
|
+
* Stored agent state (for persistence before agent is created)
|
|
83
|
+
*/
|
|
84
|
+
private storedState?;
|
|
85
|
+
/**
|
|
86
|
+
* Token usage tracking
|
|
87
|
+
*/
|
|
88
|
+
private _tokenUsage;
|
|
89
|
+
/**
|
|
90
|
+
* Last activity timestamp
|
|
91
|
+
*/
|
|
92
|
+
private _lastActivity;
|
|
93
|
+
constructor(config: TeamAgentConfig);
|
|
94
|
+
/**
|
|
95
|
+
* Get the underlying agent instance
|
|
96
|
+
*/
|
|
97
|
+
get agent(): Agent | null;
|
|
98
|
+
/**
|
|
99
|
+
* Check if agent is initialized
|
|
100
|
+
*/
|
|
101
|
+
get isInitialized(): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Get token usage
|
|
104
|
+
*/
|
|
105
|
+
get tokenUsage(): {
|
|
106
|
+
input: number;
|
|
107
|
+
output: number;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Get last activity timestamp
|
|
111
|
+
*/
|
|
112
|
+
get lastActivity(): Date;
|
|
113
|
+
/**
|
|
114
|
+
* Get model tier
|
|
115
|
+
*/
|
|
116
|
+
get modelTier(): ModelTier | undefined;
|
|
117
|
+
/**
|
|
118
|
+
* Change the model tier
|
|
119
|
+
* This preserves conversation history but strips thinking blocks
|
|
120
|
+
* (which contain provider-specific signatures that don't transfer).
|
|
121
|
+
*
|
|
122
|
+
* @param newTier - The new model tier to use
|
|
123
|
+
*/
|
|
124
|
+
setModelTier(newTier: ModelTier): void;
|
|
125
|
+
/**
|
|
126
|
+
* Initialize the agent with the given factory
|
|
127
|
+
* This allows the team to control agent creation
|
|
128
|
+
*
|
|
129
|
+
* @param agentFactory Factory function to create the agent
|
|
130
|
+
* @param sharedContext Optional shared context to inject into system prompt
|
|
131
|
+
*/
|
|
132
|
+
initialize(agentFactory: (config: Partial<AgentConfig>, systemPromptAddition?: string, useMinimalSystemPrompt?: boolean, noTools?: boolean, toolFilter?: string[], modelTier?: ModelTier) => Promise<Agent>, sharedContext?: SharedContextManager): Promise<void>;
|
|
133
|
+
/**
|
|
134
|
+
* Set the agent instance directly
|
|
135
|
+
* Used for the default agent when an agent is created before the team
|
|
136
|
+
*/
|
|
137
|
+
setAgent(agent: Agent): void;
|
|
138
|
+
/**
|
|
139
|
+
* Update token usage after a turn
|
|
140
|
+
*/
|
|
141
|
+
updateTokenUsage(input: number, output: number): void;
|
|
142
|
+
/**
|
|
143
|
+
* Reset token usage (e.g., after compaction)
|
|
144
|
+
*/
|
|
145
|
+
resetTokenUsage(): void;
|
|
146
|
+
/**
|
|
147
|
+
* Clear conversation history (for /reset command)
|
|
148
|
+
* Clears both the underlying agent and stored state
|
|
149
|
+
*/
|
|
150
|
+
clearHistory(): void;
|
|
151
|
+
/**
|
|
152
|
+
* Get context manager from the agent (if available)
|
|
153
|
+
*/
|
|
154
|
+
getContextManager(): ContextManager | undefined;
|
|
155
|
+
/**
|
|
156
|
+
* Get context utilization percentage
|
|
157
|
+
*/
|
|
158
|
+
getContextUtilization(): number;
|
|
159
|
+
/**
|
|
160
|
+
* Get the max context window for this agent's model.
|
|
161
|
+
* Resolves: modelTier → modelId → contextWindow from MODEL_REGISTRY.
|
|
162
|
+
*/
|
|
163
|
+
getMaxContextTokens(provider: ProviderType): number;
|
|
164
|
+
/**
|
|
165
|
+
* Get context stats (works even when agent is not initialized)
|
|
166
|
+
* Returns data from either the live agent or stored state.
|
|
167
|
+
* Includes maxTokens for per-agent context window display.
|
|
168
|
+
*/
|
|
169
|
+
getContextStats(provider?: ProviderType): {
|
|
170
|
+
messageCount: number;
|
|
171
|
+
estimatedTokens: number;
|
|
172
|
+
maxTokens: number;
|
|
173
|
+
};
|
|
174
|
+
/**
|
|
175
|
+
* Serialize the team agent for persistence
|
|
176
|
+
*/
|
|
177
|
+
serialize(): SerializedTeamAgent;
|
|
178
|
+
/**
|
|
179
|
+
* Create a TeamAgent from serialized state
|
|
180
|
+
*/
|
|
181
|
+
static fromSerialized(data: SerializedTeamAgent): TeamAgent;
|
|
182
|
+
/**
|
|
183
|
+
* Create a TeamAgent from a predefined role
|
|
184
|
+
* @param role - The predefined role
|
|
185
|
+
* @param id - Optional custom ID (defaults to role name)
|
|
186
|
+
* @param modelTier - Optional model tier override (defaults to role's default tier)
|
|
187
|
+
*/
|
|
188
|
+
static fromRole(role: AgentRole, id?: string, modelTier?: ModelTier): TeamAgent;
|
|
189
|
+
/**
|
|
190
|
+
* Create a TeamAgent from a custom agent definition
|
|
191
|
+
*/
|
|
192
|
+
static fromCustomDefinition(def: CustomAgentDefinition): TeamAgent;
|
|
193
|
+
/**
|
|
194
|
+
* Get a formatted label for display (e.g., "[◈_◈] $arch")
|
|
195
|
+
*/
|
|
196
|
+
getLabel(): string;
|
|
197
|
+
/**
|
|
198
|
+
* Get a full label with display name (e.g., "[◈_◈] $arch (Solution Architect)")
|
|
199
|
+
*/
|
|
200
|
+
getFullLabel(): string;
|
|
201
|
+
}
|
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TeamAgent - Wrapper for persistent team agents
|
|
3
|
+
*
|
|
4
|
+
* Each team agent has:
|
|
5
|
+
* - Unique identity (id, name, mascot)
|
|
6
|
+
* - Isolated conversation history
|
|
7
|
+
* - Role-specific system prompt additions
|
|
8
|
+
* - Optional tool filtering
|
|
9
|
+
*/
|
|
10
|
+
import { ROLE_METADATA } from './types.js';
|
|
11
|
+
import { getModelForTier, getModelContextWindow } from '../models/index.js';
|
|
12
|
+
import { generateCustomAgentSystemPrompt, getCustomAgentToolFilter } from './custom-agents.js';
|
|
13
|
+
import { getToolsForProfile, generateToolAwarenessPrompt, generateCoordinatorGuidance, generateSpecialistGuidance, } from './tool-config.js';
|
|
14
|
+
/**
|
|
15
|
+
* Estimate token count from text (approximate: ~4 chars per token)
|
|
16
|
+
*/
|
|
17
|
+
function estimateTokens(text) {
|
|
18
|
+
return Math.ceil(text.length / 4);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* TeamAgent wraps an Agent instance with team-specific metadata
|
|
22
|
+
*/
|
|
23
|
+
export class TeamAgent {
|
|
24
|
+
/**
|
|
25
|
+
* Unique identifier (e.g., 'pm', 'arch', 'qa')
|
|
26
|
+
*/
|
|
27
|
+
id;
|
|
28
|
+
/**
|
|
29
|
+
* Display name shown in UI
|
|
30
|
+
*/
|
|
31
|
+
displayName;
|
|
32
|
+
/**
|
|
33
|
+
* Mascot expression for visual differentiation
|
|
34
|
+
*/
|
|
35
|
+
mascot;
|
|
36
|
+
/**
|
|
37
|
+
* Role type
|
|
38
|
+
*/
|
|
39
|
+
role;
|
|
40
|
+
/**
|
|
41
|
+
* Optional description
|
|
42
|
+
*/
|
|
43
|
+
description;
|
|
44
|
+
/**
|
|
45
|
+
* System prompt addition specific to this agent
|
|
46
|
+
*/
|
|
47
|
+
systemPromptAddition;
|
|
48
|
+
/**
|
|
49
|
+
* Use minimal system prompt - skip all modules
|
|
50
|
+
*/
|
|
51
|
+
useMinimalSystemPrompt;
|
|
52
|
+
/**
|
|
53
|
+
* Skip all tool registration - agent has no tools
|
|
54
|
+
*/
|
|
55
|
+
noTools;
|
|
56
|
+
/**
|
|
57
|
+
* Tool filter (tool names this agent can use)
|
|
58
|
+
*/
|
|
59
|
+
toolFilter;
|
|
60
|
+
/**
|
|
61
|
+
* Tool profile name (for display)
|
|
62
|
+
*/
|
|
63
|
+
toolProfile;
|
|
64
|
+
/**
|
|
65
|
+
* Enabled skills (empty = all skills)
|
|
66
|
+
*/
|
|
67
|
+
enabledSkills;
|
|
68
|
+
/**
|
|
69
|
+
* Auto-approve handoffs from this agent without user confirmation
|
|
70
|
+
*/
|
|
71
|
+
autoApproveHandoff;
|
|
72
|
+
/**
|
|
73
|
+
* Model tier (fast/balanced/powerful)
|
|
74
|
+
* Determines which model to use based on provider
|
|
75
|
+
*/
|
|
76
|
+
_modelTier;
|
|
77
|
+
/**
|
|
78
|
+
* The underlying agent instance
|
|
79
|
+
*/
|
|
80
|
+
_agent = null;
|
|
81
|
+
/**
|
|
82
|
+
* Agent configuration for lazy initialization
|
|
83
|
+
*/
|
|
84
|
+
agentConfig;
|
|
85
|
+
/**
|
|
86
|
+
* Stored agent state (for persistence before agent is created)
|
|
87
|
+
*/
|
|
88
|
+
storedState;
|
|
89
|
+
/**
|
|
90
|
+
* Token usage tracking
|
|
91
|
+
*/
|
|
92
|
+
_tokenUsage = {
|
|
93
|
+
input: 0,
|
|
94
|
+
output: 0,
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Last activity timestamp
|
|
98
|
+
*/
|
|
99
|
+
_lastActivity = new Date();
|
|
100
|
+
constructor(config) {
|
|
101
|
+
this.id = config.id;
|
|
102
|
+
this.displayName = config.displayName;
|
|
103
|
+
this.mascot = config.mascot;
|
|
104
|
+
this.role = config.role;
|
|
105
|
+
this.description = config.description;
|
|
106
|
+
this.systemPromptAddition = config.systemPromptAddition;
|
|
107
|
+
this.useMinimalSystemPrompt = config.useMinimalSystemPrompt;
|
|
108
|
+
this.noTools = config.noTools;
|
|
109
|
+
this.toolFilter = config.toolFilter;
|
|
110
|
+
this.toolProfile = config.toolProfile;
|
|
111
|
+
this.enabledSkills = config.enabledSkills;
|
|
112
|
+
this.autoApproveHandoff = config.autoApproveHandoff;
|
|
113
|
+
this._modelTier = config.modelTier;
|
|
114
|
+
this.agentConfig = config.agentConfig ?? {};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Get the underlying agent instance
|
|
118
|
+
*/
|
|
119
|
+
get agent() {
|
|
120
|
+
return this._agent;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Check if agent is initialized
|
|
124
|
+
*/
|
|
125
|
+
get isInitialized() {
|
|
126
|
+
return this._agent !== null;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get token usage
|
|
130
|
+
*/
|
|
131
|
+
get tokenUsage() {
|
|
132
|
+
return { ...this._tokenUsage };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Get last activity timestamp
|
|
136
|
+
*/
|
|
137
|
+
get lastActivity() {
|
|
138
|
+
return this._lastActivity;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Get model tier
|
|
142
|
+
*/
|
|
143
|
+
get modelTier() {
|
|
144
|
+
return this._modelTier;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Change the model tier
|
|
148
|
+
* This preserves conversation history but strips thinking blocks
|
|
149
|
+
* (which contain provider-specific signatures that don't transfer).
|
|
150
|
+
*
|
|
151
|
+
* @param newTier - The new model tier to use
|
|
152
|
+
*/
|
|
153
|
+
setModelTier(newTier) {
|
|
154
|
+
if (newTier === this._modelTier) {
|
|
155
|
+
return; // No change needed
|
|
156
|
+
}
|
|
157
|
+
// Store current state if agent is initialized
|
|
158
|
+
if (this._agent) {
|
|
159
|
+
const state = this._agent.serialize();
|
|
160
|
+
// Strip thinking blocks from messages - they contain provider-specific
|
|
161
|
+
// signatures (e.g., Gemini's thought_signature) that don't transfer
|
|
162
|
+
// between sessions or model changes
|
|
163
|
+
state.messages = state.messages.map((msg) => {
|
|
164
|
+
// Content can be string or ContentBlock[]
|
|
165
|
+
if (typeof msg.content === 'string') {
|
|
166
|
+
return msg;
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
...msg,
|
|
170
|
+
content: msg.content.filter((block) => block.type !== 'thinking'),
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
this.storedState = state;
|
|
174
|
+
this._agent = null; // Clear agent so it will be reinitialized
|
|
175
|
+
}
|
|
176
|
+
this._modelTier = newTier;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Initialize the agent with the given factory
|
|
180
|
+
* This allows the team to control agent creation
|
|
181
|
+
*
|
|
182
|
+
* @param agentFactory Factory function to create the agent
|
|
183
|
+
* @param sharedContext Optional shared context to inject into system prompt
|
|
184
|
+
*/
|
|
185
|
+
async initialize(agentFactory, sharedContext) {
|
|
186
|
+
if (this._agent) {
|
|
187
|
+
return; // Already initialized
|
|
188
|
+
}
|
|
189
|
+
// Build system prompt addition with shared context
|
|
190
|
+
let finalSystemPromptAddition = this.systemPromptAddition ?? '';
|
|
191
|
+
// Inject shared context if provided (excluding roster — that goes via anchor for live updates)
|
|
192
|
+
if (sharedContext) {
|
|
193
|
+
const sharedContextBlock = sharedContext.format({ excludeRoster: true });
|
|
194
|
+
if (sharedContextBlock) {
|
|
195
|
+
// Prepend shared context to role-specific prompt
|
|
196
|
+
finalSystemPromptAddition = finalSystemPromptAddition
|
|
197
|
+
? `${sharedContextBlock}\n\n${finalSystemPromptAddition}`
|
|
198
|
+
: sharedContextBlock;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
this._agent = await agentFactory(this.agentConfig, finalSystemPromptAddition || undefined, this.useMinimalSystemPrompt, this.noTools, this.toolFilter, // Pass tool filter to factory
|
|
202
|
+
this._modelTier // Pass model tier to factory
|
|
203
|
+
);
|
|
204
|
+
// Set the team roster as an anchor (dynamically re-injected on every LLM call).
|
|
205
|
+
// This ensures roster updates (agent added/removed) are always visible.
|
|
206
|
+
if (sharedContext && sharedContext.hasTeamRoster() && this._agent.hasAnchors()) {
|
|
207
|
+
this._agent.addAnchor({
|
|
208
|
+
id: 'team-roster',
|
|
209
|
+
content: sharedContext.formatTeamRoster(),
|
|
210
|
+
priority: 'info',
|
|
211
|
+
scope: 'session',
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
// Restore state if we have stored state
|
|
215
|
+
if (this.storedState && this.storedState.messages.length > 0) {
|
|
216
|
+
// Strip thinking blocks - they contain provider-specific signatures
|
|
217
|
+
// (e.g., Gemini's thought_signature) that don't transfer between sessions
|
|
218
|
+
const messagesWithoutThinking = this.storedState.messages.map((msg) => {
|
|
219
|
+
if (typeof msg.content === 'string') {
|
|
220
|
+
return msg;
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
...msg,
|
|
224
|
+
content: msg.content.filter((block) => block.type !== 'thinking'),
|
|
225
|
+
};
|
|
226
|
+
});
|
|
227
|
+
await this._agent.setHistory(messagesWithoutThinking, {
|
|
228
|
+
turnCount: this.storedState.turnCount,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Set the agent instance directly
|
|
234
|
+
* Used for the default agent when an agent is created before the team
|
|
235
|
+
*/
|
|
236
|
+
setAgent(agent) {
|
|
237
|
+
this._agent = agent;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Update token usage after a turn
|
|
241
|
+
*/
|
|
242
|
+
updateTokenUsage(input, output) {
|
|
243
|
+
this._tokenUsage.input += input;
|
|
244
|
+
this._tokenUsage.output += output;
|
|
245
|
+
this._lastActivity = new Date();
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Reset token usage (e.g., after compaction)
|
|
249
|
+
*/
|
|
250
|
+
resetTokenUsage() {
|
|
251
|
+
this._tokenUsage = { input: 0, output: 0 };
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Clear conversation history (for /reset command)
|
|
255
|
+
* Clears both the underlying agent and stored state
|
|
256
|
+
*/
|
|
257
|
+
clearHistory() {
|
|
258
|
+
// Clear underlying agent if initialized
|
|
259
|
+
if (this._agent) {
|
|
260
|
+
this._agent.clearHistory();
|
|
261
|
+
}
|
|
262
|
+
// Clear stored state messages
|
|
263
|
+
if (this.storedState) {
|
|
264
|
+
this.storedState.messages = [];
|
|
265
|
+
this.storedState.todos = [];
|
|
266
|
+
this.storedState.turnCount = 0;
|
|
267
|
+
}
|
|
268
|
+
// Reset token usage
|
|
269
|
+
this._tokenUsage = { input: 0, output: 0 };
|
|
270
|
+
this._lastActivity = new Date();
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get context manager from the agent (if available)
|
|
274
|
+
*/
|
|
275
|
+
getContextManager() {
|
|
276
|
+
return this._agent?.getContextManager();
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get context utilization percentage
|
|
280
|
+
*/
|
|
281
|
+
getContextUtilization() {
|
|
282
|
+
const cm = this.getContextManager();
|
|
283
|
+
if (!cm)
|
|
284
|
+
return 0;
|
|
285
|
+
const messageCount = this._agent?.serialize().messages.length ?? 0;
|
|
286
|
+
const stats = cm.getStats(messageCount);
|
|
287
|
+
return Math.round((stats.currentTokens / stats.maxTokens) * 100);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Get the max context window for this agent's model.
|
|
291
|
+
* Resolves: modelTier → modelId → contextWindow from MODEL_REGISTRY.
|
|
292
|
+
*/
|
|
293
|
+
getMaxContextTokens(provider) {
|
|
294
|
+
// If agent is initialized, get from ContextManager
|
|
295
|
+
if (this._agent) {
|
|
296
|
+
const cm = this.getContextManager();
|
|
297
|
+
if (cm) {
|
|
298
|
+
const state = this._agent.serialize();
|
|
299
|
+
const stats = cm.getStats(state.messages.length);
|
|
300
|
+
return stats.maxTokens;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
// Fall back to model-based lookup
|
|
304
|
+
if (this._modelTier) {
|
|
305
|
+
const modelId = getModelForTier(provider, this._modelTier);
|
|
306
|
+
return getModelContextWindow(modelId, provider);
|
|
307
|
+
}
|
|
308
|
+
return getModelContextWindow('', provider); // provider fallback
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Get context stats (works even when agent is not initialized)
|
|
312
|
+
* Returns data from either the live agent or stored state.
|
|
313
|
+
* Includes maxTokens for per-agent context window display.
|
|
314
|
+
*/
|
|
315
|
+
getContextStats(provider) {
|
|
316
|
+
// Try live agent first — use ContextManager stats (includes overhead)
|
|
317
|
+
if (this._agent) {
|
|
318
|
+
const cm = this.getContextManager();
|
|
319
|
+
if (cm) {
|
|
320
|
+
const state = this._agent.serialize();
|
|
321
|
+
const stats = cm.getStats(state.messages.length);
|
|
322
|
+
return {
|
|
323
|
+
messageCount: state.messages.length,
|
|
324
|
+
estimatedTokens: stats.currentTokens,
|
|
325
|
+
maxTokens: stats.maxTokens,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
// Agent exists but no context manager — estimate
|
|
329
|
+
const state = this._agent.serialize();
|
|
330
|
+
const messagesStr = JSON.stringify(state.messages);
|
|
331
|
+
return {
|
|
332
|
+
messageCount: state.messages.length,
|
|
333
|
+
estimatedTokens: estimateTokens(messagesStr),
|
|
334
|
+
maxTokens: provider ? this.getMaxContextTokens(provider) : 200000,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
// Fall back to stored state
|
|
338
|
+
if (this.storedState && this.storedState.messages.length > 0) {
|
|
339
|
+
const messagesStr = JSON.stringify(this.storedState.messages);
|
|
340
|
+
return {
|
|
341
|
+
messageCount: this.storedState.messages.length,
|
|
342
|
+
estimatedTokens: estimateTokens(messagesStr),
|
|
343
|
+
maxTokens: provider ? this.getMaxContextTokens(provider) : 200000,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
messageCount: 0,
|
|
348
|
+
estimatedTokens: 0,
|
|
349
|
+
maxTokens: provider ? this.getMaxContextTokens(provider) : 200000,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Serialize the team agent for persistence
|
|
354
|
+
*/
|
|
355
|
+
serialize() {
|
|
356
|
+
const now = new Date().toISOString();
|
|
357
|
+
const agentState = this._agent?.serialize() ??
|
|
358
|
+
this.storedState ?? {
|
|
359
|
+
sessionId: '',
|
|
360
|
+
messages: [],
|
|
361
|
+
systemPrompt: '',
|
|
362
|
+
todos: [],
|
|
363
|
+
currentIteration: 0,
|
|
364
|
+
turnCount: 0,
|
|
365
|
+
totalTokensUsed: 0,
|
|
366
|
+
createdAt: now,
|
|
367
|
+
updatedAt: now,
|
|
368
|
+
version: 1,
|
|
369
|
+
};
|
|
370
|
+
return {
|
|
371
|
+
id: this.id,
|
|
372
|
+
displayName: this.displayName,
|
|
373
|
+
mascot: this.mascot,
|
|
374
|
+
role: this.role,
|
|
375
|
+
description: this.description,
|
|
376
|
+
systemPromptAddition: this.systemPromptAddition,
|
|
377
|
+
useMinimalSystemPrompt: this.useMinimalSystemPrompt,
|
|
378
|
+
noTools: this.noTools,
|
|
379
|
+
toolFilter: this.toolFilter,
|
|
380
|
+
toolProfile: this.toolProfile,
|
|
381
|
+
enabledSkills: this.enabledSkills,
|
|
382
|
+
modelTier: this.modelTier,
|
|
383
|
+
autoApproveHandoff: this.autoApproveHandoff,
|
|
384
|
+
agentState,
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Create a TeamAgent from serialized state
|
|
389
|
+
*/
|
|
390
|
+
static fromSerialized(data) {
|
|
391
|
+
// Refresh tool filter from profile if available (ensures new tools are picked up)
|
|
392
|
+
// This handles the case where tools were added after the agent was created
|
|
393
|
+
const toolFilter = data.toolProfile ? getToolsForProfile(data.toolProfile) : data.toolFilter;
|
|
394
|
+
const agent = new TeamAgent({
|
|
395
|
+
id: data.id,
|
|
396
|
+
displayName: data.displayName,
|
|
397
|
+
mascot: data.mascot,
|
|
398
|
+
role: data.role,
|
|
399
|
+
description: data.description,
|
|
400
|
+
systemPromptAddition: data.systemPromptAddition,
|
|
401
|
+
useMinimalSystemPrompt: data.useMinimalSystemPrompt,
|
|
402
|
+
noTools: data.noTools,
|
|
403
|
+
toolFilter,
|
|
404
|
+
toolProfile: data.toolProfile,
|
|
405
|
+
enabledSkills: data.enabledSkills,
|
|
406
|
+
modelTier: data.modelTier,
|
|
407
|
+
autoApproveHandoff: data.autoApproveHandoff,
|
|
408
|
+
});
|
|
409
|
+
// Store the state for restoration when agent is initialized
|
|
410
|
+
agent.storedState = data.agentState;
|
|
411
|
+
return agent;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Create a TeamAgent from a predefined role
|
|
415
|
+
* @param role - The predefined role
|
|
416
|
+
* @param id - Optional custom ID (defaults to role name)
|
|
417
|
+
* @param modelTier - Optional model tier override (defaults to role's default tier)
|
|
418
|
+
*/
|
|
419
|
+
static fromRole(role, id, modelTier) {
|
|
420
|
+
const metadata = ROLE_METADATA[role];
|
|
421
|
+
// Get tool filter from default profile (if specified)
|
|
422
|
+
const profile = metadata.defaultToolProfile;
|
|
423
|
+
const toolFilter = profile ? getToolsForProfile(profile) : undefined;
|
|
424
|
+
// Build system prompt with tool awareness (for non-full profiles)
|
|
425
|
+
let systemPromptAddition = metadata.defaultSystemPromptAddition ?? '';
|
|
426
|
+
if (profile && profile !== 'full') {
|
|
427
|
+
const toolAwareness = generateToolAwarenessPrompt({ profile });
|
|
428
|
+
systemPromptAddition = systemPromptAddition
|
|
429
|
+
? `${systemPromptAddition}\n\n${toolAwareness}`
|
|
430
|
+
: toolAwareness;
|
|
431
|
+
}
|
|
432
|
+
// Add delegation guidance based on role
|
|
433
|
+
if (role === 'default') {
|
|
434
|
+
// Coordinator gets delegation tool guidance
|
|
435
|
+
const coordinatorGuidance = generateCoordinatorGuidance();
|
|
436
|
+
systemPromptAddition = systemPromptAddition
|
|
437
|
+
? `${systemPromptAddition}\n\n${coordinatorGuidance}`
|
|
438
|
+
: coordinatorGuidance;
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
// Specialists get collaboration guidance
|
|
442
|
+
const specialistGuidance = generateSpecialistGuidance(role);
|
|
443
|
+
systemPromptAddition = systemPromptAddition
|
|
444
|
+
? `${systemPromptAddition}\n\n${specialistGuidance}`
|
|
445
|
+
: specialistGuidance;
|
|
446
|
+
}
|
|
447
|
+
return new TeamAgent({
|
|
448
|
+
id: id ?? role,
|
|
449
|
+
displayName: metadata.displayName,
|
|
450
|
+
mascot: metadata.mascot,
|
|
451
|
+
role,
|
|
452
|
+
description: metadata.description,
|
|
453
|
+
systemPromptAddition: systemPromptAddition || undefined,
|
|
454
|
+
useMinimalSystemPrompt: metadata.useMinimalSystemPrompt,
|
|
455
|
+
noTools: metadata.noTools,
|
|
456
|
+
toolFilter,
|
|
457
|
+
toolProfile: profile,
|
|
458
|
+
modelTier: modelTier ?? metadata.defaultModelTier,
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Create a TeamAgent from a custom agent definition
|
|
463
|
+
*/
|
|
464
|
+
static fromCustomDefinition(def) {
|
|
465
|
+
// Get tool filter from custom agent config
|
|
466
|
+
const toolFilter = getCustomAgentToolFilter(def);
|
|
467
|
+
return new TeamAgent({
|
|
468
|
+
id: def.id,
|
|
469
|
+
displayName: def.displayName,
|
|
470
|
+
mascot: def.mascot,
|
|
471
|
+
role: 'custom',
|
|
472
|
+
description: def.specialty,
|
|
473
|
+
systemPromptAddition: generateCustomAgentSystemPrompt(def),
|
|
474
|
+
toolFilter, // Pass tool filter from custom agent config
|
|
475
|
+
toolProfile: def.toolConfig?.profile, // Store profile for display
|
|
476
|
+
enabledSkills: def.enabledSkills, // Store skills for display
|
|
477
|
+
modelTier: def.modelTier, // Store model tier
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Get a formatted label for display (e.g., "[◈_◈] $arch")
|
|
482
|
+
*/
|
|
483
|
+
getLabel() {
|
|
484
|
+
return `${this.mascot} $${this.id}`;
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Get a full label with display name (e.g., "[◈_◈] $arch (Solution Architect)")
|
|
488
|
+
*/
|
|
489
|
+
getFullLabel() {
|
|
490
|
+
return `${this.mascot} $${this.id} (${this.displayName})`;
|
|
491
|
+
}
|
|
492
|
+
}
|