@defai.digital/agent-domain 13.0.3
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/LICENSE +214 -0
- package/dist/enhanced-executor.d.ts +170 -0
- package/dist/enhanced-executor.d.ts.map +1 -0
- package/dist/enhanced-executor.js +1072 -0
- package/dist/enhanced-executor.js.map +1 -0
- package/dist/executor.d.ts +120 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +929 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +50 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +160 -0
- package/dist/loader.js.map +1 -0
- package/dist/persistent-registry.d.ts +105 -0
- package/dist/persistent-registry.d.ts.map +1 -0
- package/dist/persistent-registry.js +183 -0
- package/dist/persistent-registry.js.map +1 -0
- package/dist/production-factories.d.ts +70 -0
- package/dist/production-factories.d.ts.map +1 -0
- package/dist/production-factories.js +434 -0
- package/dist/production-factories.js.map +1 -0
- package/dist/prompt-executor.d.ts +119 -0
- package/dist/prompt-executor.d.ts.map +1 -0
- package/dist/prompt-executor.js +211 -0
- package/dist/prompt-executor.js.map +1 -0
- package/dist/registry.d.ts +57 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +123 -0
- package/dist/registry.js.map +1 -0
- package/dist/selection-service.d.ts +74 -0
- package/dist/selection-service.d.ts.map +1 -0
- package/dist/selection-service.js +322 -0
- package/dist/selection-service.js.map +1 -0
- package/dist/selector.d.ts +51 -0
- package/dist/selector.d.ts.map +1 -0
- package/dist/selector.js +249 -0
- package/dist/selector.js.map +1 -0
- package/dist/stub-checkpoint.d.ts +23 -0
- package/dist/stub-checkpoint.d.ts.map +1 -0
- package/dist/stub-checkpoint.js +137 -0
- package/dist/stub-checkpoint.js.map +1 -0
- package/dist/stub-delegation-tracker.d.ts +25 -0
- package/dist/stub-delegation-tracker.d.ts.map +1 -0
- package/dist/stub-delegation-tracker.js +118 -0
- package/dist/stub-delegation-tracker.js.map +1 -0
- package/dist/stub-parallel-executor.d.ts +19 -0
- package/dist/stub-parallel-executor.d.ts.map +1 -0
- package/dist/stub-parallel-executor.js +176 -0
- package/dist/stub-parallel-executor.js.map +1 -0
- package/dist/types.d.ts +614 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +15 -0
- package/dist/types.js.map +1 -0
- package/dist/workflow-templates.d.ts +117 -0
- package/dist/workflow-templates.d.ts.map +1 -0
- package/dist/workflow-templates.js +342 -0
- package/dist/workflow-templates.js.map +1 -0
- package/package.json +51 -0
- package/src/enhanced-executor.ts +1395 -0
- package/src/executor.ts +1153 -0
- package/src/index.ts +172 -0
- package/src/loader.ts +191 -0
- package/src/persistent-registry.ts +235 -0
- package/src/production-factories.ts +613 -0
- package/src/prompt-executor.ts +310 -0
- package/src/registry.ts +167 -0
- package/src/selection-service.ts +411 -0
- package/src/selector.ts +299 -0
- package/src/stub-checkpoint.ts +187 -0
- package/src/stub-delegation-tracker.ts +161 -0
- package/src/stub-parallel-executor.ts +224 -0
- package/src/types.ts +784 -0
- package/src/workflow-templates.ts +393 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prompt Executor Implementation
|
|
3
|
+
*
|
|
4
|
+
* Bridges the agent domain with LLM providers for real prompt execution.
|
|
5
|
+
* This file provides both a stub executor for testing and a factory
|
|
6
|
+
* for creating real executors with provider integration.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type {
|
|
10
|
+
PromptExecutor,
|
|
11
|
+
PromptExecutionRequest,
|
|
12
|
+
PromptExecutionResponse,
|
|
13
|
+
} from './types.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Stub prompt executor for testing and development
|
|
17
|
+
* Returns mock responses without calling real providers
|
|
18
|
+
*
|
|
19
|
+
* WARNING: This executor returns fake responses. For production use,
|
|
20
|
+
* inject a real PromptExecutor via config.promptExecutor.
|
|
21
|
+
*/
|
|
22
|
+
export class StubPromptExecutor implements PromptExecutor {
|
|
23
|
+
private readonly defaultProvider: string;
|
|
24
|
+
private hasWarnedOnce = false;
|
|
25
|
+
|
|
26
|
+
constructor(defaultProvider = 'claude') {
|
|
27
|
+
this.defaultProvider = defaultProvider;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async execute(request: PromptExecutionRequest): Promise<PromptExecutionResponse> {
|
|
31
|
+
// Warn once on first use (not on every call to avoid log spam)
|
|
32
|
+
if (!this.hasWarnedOnce) {
|
|
33
|
+
console.warn(
|
|
34
|
+
'[WARN] StubPromptExecutor: Using mock responses. ' +
|
|
35
|
+
'For production, inject a real PromptExecutor via config.promptExecutor.'
|
|
36
|
+
);
|
|
37
|
+
this.hasWarnedOnce = true;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const startTime = Date.now();
|
|
41
|
+
|
|
42
|
+
// Simulate some processing time
|
|
43
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
success: true,
|
|
47
|
+
content: `[Stub Response] This is a mock response for prompt: "${request.prompt.substring(0, 100)}..."`,
|
|
48
|
+
provider: request.provider ?? this.defaultProvider,
|
|
49
|
+
model: request.model ?? 'stub-model',
|
|
50
|
+
latencyMs: Date.now() - startTime,
|
|
51
|
+
usage: {
|
|
52
|
+
inputTokens: Math.ceil(request.prompt.length / 4),
|
|
53
|
+
outputTokens: 50,
|
|
54
|
+
totalTokens: Math.ceil(request.prompt.length / 4) + 50,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async isProviderAvailable(_providerId: string): Promise<boolean> {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async getAvailableProviders(): Promise<string[]> {
|
|
64
|
+
return [this.defaultProvider];
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getDefaultProvider(): string {
|
|
68
|
+
return this.defaultProvider;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Provider-based prompt executor configuration
|
|
74
|
+
*/
|
|
75
|
+
export interface ProviderPromptExecutorConfig {
|
|
76
|
+
/**
|
|
77
|
+
* Default provider to use when none specified
|
|
78
|
+
*/
|
|
79
|
+
defaultProvider: string;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Default model to use when none specified (per provider)
|
|
83
|
+
*/
|
|
84
|
+
defaultModels?: Record<string, string>;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Default timeout in milliseconds
|
|
88
|
+
*/
|
|
89
|
+
defaultTimeout?: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Interface that matches the provider registry from @defai.digital/providers
|
|
94
|
+
* This allows loose coupling without direct dependency
|
|
95
|
+
*/
|
|
96
|
+
export interface ProviderRegistryLike {
|
|
97
|
+
get(providerId: string): ProviderLike | undefined;
|
|
98
|
+
getProviderIds(): string[];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Interface that matches a provider from @defai.digital/providers
|
|
103
|
+
*/
|
|
104
|
+
export interface ProviderLike {
|
|
105
|
+
providerId: string;
|
|
106
|
+
complete(request: {
|
|
107
|
+
requestId: string;
|
|
108
|
+
model: string;
|
|
109
|
+
messages: { role: 'user' | 'assistant' | 'system'; content: string }[];
|
|
110
|
+
systemPrompt?: string;
|
|
111
|
+
maxTokens?: number;
|
|
112
|
+
temperature?: number;
|
|
113
|
+
timeout?: number;
|
|
114
|
+
}): Promise<{
|
|
115
|
+
success: boolean;
|
|
116
|
+
content?: string;
|
|
117
|
+
error?: { message: string; category: string };
|
|
118
|
+
latencyMs: number;
|
|
119
|
+
usage?: { inputTokens: number; outputTokens: number; totalTokens: number };
|
|
120
|
+
model?: string;
|
|
121
|
+
}>;
|
|
122
|
+
isAvailable(): Promise<boolean>;
|
|
123
|
+
getModels(): readonly { modelId: string; isDefault?: boolean | undefined }[];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Real prompt executor that uses the provider registry
|
|
128
|
+
*/
|
|
129
|
+
export class ProviderPromptExecutor implements PromptExecutor {
|
|
130
|
+
private readonly registry: ProviderRegistryLike;
|
|
131
|
+
private readonly config: ProviderPromptExecutorConfig;
|
|
132
|
+
|
|
133
|
+
constructor(registry: ProviderRegistryLike, config: ProviderPromptExecutorConfig) {
|
|
134
|
+
this.registry = registry;
|
|
135
|
+
this.config = config;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async execute(request: PromptExecutionRequest): Promise<PromptExecutionResponse> {
|
|
139
|
+
const startTime = Date.now();
|
|
140
|
+
const providerId = request.provider ?? this.config.defaultProvider;
|
|
141
|
+
|
|
142
|
+
// Get the provider
|
|
143
|
+
const provider = this.registry.get(providerId);
|
|
144
|
+
if (provider === undefined) {
|
|
145
|
+
return {
|
|
146
|
+
success: false,
|
|
147
|
+
error: `Provider "${providerId}" not found`,
|
|
148
|
+
errorCode: 'PROVIDER_NOT_FOUND',
|
|
149
|
+
latencyMs: Date.now() - startTime,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Check if provider is available
|
|
154
|
+
const isAvailable = await provider.isAvailable();
|
|
155
|
+
if (!isAvailable) {
|
|
156
|
+
return {
|
|
157
|
+
success: false,
|
|
158
|
+
error: `Provider "${providerId}" is not available (CLI not installed or not in PATH)`,
|
|
159
|
+
errorCode: 'PROVIDER_UNAVAILABLE',
|
|
160
|
+
provider: providerId,
|
|
161
|
+
latencyMs: Date.now() - startTime,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Determine model to use
|
|
166
|
+
let model = request.model;
|
|
167
|
+
if (!model) {
|
|
168
|
+
// Use configured default for this provider, or provider's default model
|
|
169
|
+
model = this.config.defaultModels?.[providerId];
|
|
170
|
+
if (!model) {
|
|
171
|
+
const models = provider.getModels();
|
|
172
|
+
const defaultModel = models.find((m) => m.isDefault) ?? models[0];
|
|
173
|
+
model = defaultModel?.modelId;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (!model) {
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
error: `No model specified and no default model available for provider "${providerId}"`,
|
|
181
|
+
errorCode: 'NO_MODEL',
|
|
182
|
+
provider: providerId,
|
|
183
|
+
latencyMs: Date.now() - startTime,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
try {
|
|
188
|
+
// Build completion request with only defined properties
|
|
189
|
+
const completionRequest: {
|
|
190
|
+
requestId: string;
|
|
191
|
+
model: string;
|
|
192
|
+
messages: { role: 'user' | 'assistant' | 'system'; content: string }[];
|
|
193
|
+
systemPrompt?: string;
|
|
194
|
+
maxTokens?: number;
|
|
195
|
+
temperature?: number;
|
|
196
|
+
timeout?: number;
|
|
197
|
+
} = {
|
|
198
|
+
requestId: crypto.randomUUID(),
|
|
199
|
+
model,
|
|
200
|
+
messages: [{ role: 'user', content: request.prompt }],
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
if (request.systemPrompt !== undefined) {
|
|
204
|
+
completionRequest.systemPrompt = request.systemPrompt;
|
|
205
|
+
}
|
|
206
|
+
if (request.maxTokens !== undefined) {
|
|
207
|
+
completionRequest.maxTokens = request.maxTokens;
|
|
208
|
+
}
|
|
209
|
+
if (request.temperature !== undefined) {
|
|
210
|
+
completionRequest.temperature = request.temperature;
|
|
211
|
+
}
|
|
212
|
+
const timeout = request.timeout ?? this.config.defaultTimeout;
|
|
213
|
+
if (timeout !== undefined) {
|
|
214
|
+
completionRequest.timeout = timeout;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Execute the completion
|
|
218
|
+
const response = await provider.complete(completionRequest);
|
|
219
|
+
|
|
220
|
+
if (response.success) {
|
|
221
|
+
return {
|
|
222
|
+
success: true,
|
|
223
|
+
content: response.content,
|
|
224
|
+
provider: providerId,
|
|
225
|
+
model: response.model ?? model,
|
|
226
|
+
latencyMs: response.latencyMs,
|
|
227
|
+
usage: response.usage,
|
|
228
|
+
};
|
|
229
|
+
} else {
|
|
230
|
+
return {
|
|
231
|
+
success: false,
|
|
232
|
+
error: response.error?.message ?? 'Unknown error',
|
|
233
|
+
errorCode: response.error?.category ?? 'UNKNOWN',
|
|
234
|
+
provider: providerId,
|
|
235
|
+
model,
|
|
236
|
+
latencyMs: response.latencyMs,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
} catch (error) {
|
|
240
|
+
return {
|
|
241
|
+
success: false,
|
|
242
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
243
|
+
errorCode: 'EXECUTION_ERROR',
|
|
244
|
+
provider: providerId,
|
|
245
|
+
model,
|
|
246
|
+
latencyMs: Date.now() - startTime,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async isProviderAvailable(providerId: string): Promise<boolean> {
|
|
252
|
+
const provider = this.registry.get(providerId);
|
|
253
|
+
if (provider === undefined) {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
return provider.isAvailable();
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async getAvailableProviders(): Promise<string[]> {
|
|
260
|
+
const providerIds = this.registry.getProviderIds();
|
|
261
|
+
const available: string[] = [];
|
|
262
|
+
|
|
263
|
+
for (const providerId of providerIds) {
|
|
264
|
+
const provider = this.registry.get(providerId);
|
|
265
|
+
if (provider !== undefined) {
|
|
266
|
+
const isAvailable = await provider.isAvailable();
|
|
267
|
+
if (isAvailable) {
|
|
268
|
+
available.push(providerId);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return available;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
getDefaultProvider(): string {
|
|
277
|
+
return this.config.defaultProvider;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Creates a stub prompt executor for testing
|
|
283
|
+
*/
|
|
284
|
+
export function createStubPromptExecutor(
|
|
285
|
+
defaultProvider = 'claude'
|
|
286
|
+
): PromptExecutor {
|
|
287
|
+
return new StubPromptExecutor(defaultProvider);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Creates a real prompt executor using a provider registry
|
|
292
|
+
*
|
|
293
|
+
* @example
|
|
294
|
+
* ```typescript
|
|
295
|
+
* import { createProviderRegistry } from '@defai.digital/providers';
|
|
296
|
+
* import { createProviderPromptExecutor } from '@defai.digital/agent-domain';
|
|
297
|
+
*
|
|
298
|
+
* const registry = createProviderRegistry();
|
|
299
|
+
* const executor = createProviderPromptExecutor(registry, {
|
|
300
|
+
* defaultProvider: 'claude',
|
|
301
|
+
* defaultTimeout: 120000,
|
|
302
|
+
* });
|
|
303
|
+
* ```
|
|
304
|
+
*/
|
|
305
|
+
export function createProviderPromptExecutor(
|
|
306
|
+
registry: ProviderRegistryLike,
|
|
307
|
+
config: ProviderPromptExecutorConfig
|
|
308
|
+
): PromptExecutor {
|
|
309
|
+
return new ProviderPromptExecutor(registry, config);
|
|
310
|
+
}
|
package/src/registry.ts
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Registry Implementation
|
|
3
|
+
*
|
|
4
|
+
* Manages agent profile registration, lookup, and lifecycle.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
type AgentProfile,
|
|
9
|
+
validateAgentProfile,
|
|
10
|
+
AgentErrorCode,
|
|
11
|
+
} from '@defai.digital/contracts';
|
|
12
|
+
import type { AgentRegistry, AgentFilter } from './types.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* In-memory agent registry implementation
|
|
16
|
+
*/
|
|
17
|
+
export class InMemoryAgentRegistry implements AgentRegistry {
|
|
18
|
+
private readonly agents = new Map<string, AgentProfile>();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Register a new agent profile
|
|
22
|
+
*/
|
|
23
|
+
async register(profile: AgentProfile): Promise<void> {
|
|
24
|
+
// Validate the profile
|
|
25
|
+
const validated = validateAgentProfile(profile);
|
|
26
|
+
|
|
27
|
+
// Check for duplicate
|
|
28
|
+
if (this.agents.has(validated.agentId)) {
|
|
29
|
+
throw new AgentRegistryError(
|
|
30
|
+
AgentErrorCode.AGENT_VALIDATION_ERROR,
|
|
31
|
+
`Agent with ID "${validated.agentId}" already exists`
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Add timestamps
|
|
36
|
+
const now = new Date().toISOString();
|
|
37
|
+
const withTimestamps: AgentProfile = {
|
|
38
|
+
...validated,
|
|
39
|
+
createdAt: now,
|
|
40
|
+
updatedAt: now,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
this.agents.set(validated.agentId, withTimestamps);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get an agent by ID
|
|
48
|
+
*/
|
|
49
|
+
async get(agentId: string): Promise<AgentProfile | undefined> {
|
|
50
|
+
return this.agents.get(agentId);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* List all registered agents with optional filtering
|
|
55
|
+
*/
|
|
56
|
+
async list(filter?: AgentFilter): Promise<AgentProfile[]> {
|
|
57
|
+
let agents = Array.from(this.agents.values());
|
|
58
|
+
|
|
59
|
+
if (filter !== undefined) {
|
|
60
|
+
if (filter.team !== undefined) {
|
|
61
|
+
agents = agents.filter((a) => a.team === filter.team);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (filter.tags !== undefined && filter.tags.length > 0) {
|
|
65
|
+
agents = agents.filter(
|
|
66
|
+
(a) =>
|
|
67
|
+
a.tags !== undefined &&
|
|
68
|
+
filter.tags!.some((tag) => a.tags!.includes(tag))
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (filter.enabled !== undefined) {
|
|
73
|
+
agents = agents.filter((a) => a.enabled === filter.enabled);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (filter.capability !== undefined) {
|
|
77
|
+
agents = agents.filter(
|
|
78
|
+
(a) =>
|
|
79
|
+
a.capabilities !== undefined &&
|
|
80
|
+
a.capabilities.includes(filter.capability!)
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return agents;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Update an agent profile
|
|
90
|
+
*/
|
|
91
|
+
async update(agentId: string, updates: Partial<AgentProfile>): Promise<void> {
|
|
92
|
+
const existing = this.agents.get(agentId);
|
|
93
|
+
|
|
94
|
+
if (existing === undefined) {
|
|
95
|
+
throw new AgentRegistryError(
|
|
96
|
+
AgentErrorCode.AGENT_NOT_FOUND,
|
|
97
|
+
`Agent with ID "${agentId}" not found`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Merge and validate
|
|
102
|
+
const merged = {
|
|
103
|
+
...existing,
|
|
104
|
+
...updates,
|
|
105
|
+
agentId, // Cannot change ID
|
|
106
|
+
updatedAt: new Date().toISOString(),
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
const validated = validateAgentProfile(merged);
|
|
110
|
+
this.agents.set(agentId, validated);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Remove an agent
|
|
115
|
+
*/
|
|
116
|
+
async remove(agentId: string): Promise<void> {
|
|
117
|
+
if (!this.agents.has(agentId)) {
|
|
118
|
+
throw new AgentRegistryError(
|
|
119
|
+
AgentErrorCode.AGENT_NOT_FOUND,
|
|
120
|
+
`Agent with ID "${agentId}" not found`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
this.agents.delete(agentId);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Check if an agent exists
|
|
129
|
+
*/
|
|
130
|
+
async exists(agentId: string): Promise<boolean> {
|
|
131
|
+
return this.agents.has(agentId);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Clear all agents (useful for testing)
|
|
136
|
+
*/
|
|
137
|
+
clear(): void {
|
|
138
|
+
this.agents.clear();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Get the count of registered agents
|
|
143
|
+
*/
|
|
144
|
+
get size(): number {
|
|
145
|
+
return this.agents.size;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Agent registry error
|
|
151
|
+
*/
|
|
152
|
+
export class AgentRegistryError extends Error {
|
|
153
|
+
constructor(
|
|
154
|
+
public readonly code: string,
|
|
155
|
+
message: string
|
|
156
|
+
) {
|
|
157
|
+
super(message);
|
|
158
|
+
this.name = 'AgentRegistryError';
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Creates a new in-memory agent registry
|
|
164
|
+
*/
|
|
165
|
+
export function createAgentRegistry(): AgentRegistry {
|
|
166
|
+
return new InMemoryAgentRegistry();
|
|
167
|
+
}
|