@anastops/mcp-server 1.1.2 → 2.0.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.
- package/dist/handlers/handlers.base.d.ts +20 -4
- package/dist/handlers/handlers.base.d.ts.map +1 -1
- package/dist/handlers/handlers.base.js +32 -17
- package/dist/handlers/handlers.base.js.map +1 -1
- package/dist/handlers/index.d.ts +5 -4
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/index.js +126 -135
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/tool-definitions.d.ts +1016 -1564
- package/dist/handlers/tool-definitions.d.ts.map +1 -1
- package/dist/handlers/tool-definitions.js +617 -388
- package/dist/handlers/tool-definitions.js.map +1 -1
- package/dist/handlers/types.d.ts +34 -0
- package/dist/handlers/types.d.ts.map +1 -1
- package/dist/handlers/v3/agent-tools.d.ts +280 -0
- package/dist/handlers/v3/agent-tools.d.ts.map +1 -0
- package/dist/handlers/v3/agent-tools.js +460 -0
- package/dist/handlers/v3/agent-tools.js.map +1 -0
- package/dist/handlers/v3/index.d.ts +31 -0
- package/dist/handlers/v3/index.d.ts.map +1 -0
- package/dist/handlers/v3/index.js +56 -0
- package/dist/handlers/v3/index.js.map +1 -0
- package/dist/handlers/v3/routing-integration-example.d.ts +258 -0
- package/dist/handlers/v3/routing-integration-example.d.ts.map +1 -0
- package/dist/handlers/v3/routing-integration-example.js +454 -0
- package/dist/handlers/v3/routing-integration-example.js.map +1 -0
- package/dist/handlers/v3/routing-middleware.d.ts +191 -0
- package/dist/handlers/v3/routing-middleware.d.ts.map +1 -0
- package/dist/handlers/v3/routing-middleware.js +425 -0
- package/dist/handlers/v3/routing-middleware.js.map +1 -0
- package/dist/handlers/v3/session-tools.d.ts +303 -0
- package/dist/handlers/v3/session-tools.d.ts.map +1 -0
- package/dist/handlers/v3/session-tools.js +945 -0
- package/dist/handlers/v3/session-tools.js.map +1 -0
- package/dist/handlers/v3/task-tools.d.ts +18 -0
- package/dist/handlers/v3/task-tools.d.ts.map +1 -0
- package/dist/handlers/v3/task-tools.js +1947 -0
- package/dist/handlers/v3/task-tools.js.map +1 -0
- package/dist/handlers/v3/utility-tools.d.ts +99 -0
- package/dist/handlers/v3/utility-tools.d.ts.map +1 -0
- package/dist/handlers/v3/utility-tools.js +878 -0
- package/dist/handlers/v3/utility-tools.js.map +1 -0
- package/dist/handlers.d.ts +1 -1
- package/dist/handlers.d.ts.map +1 -1
- package/dist/handlers.js +1 -1
- package/dist/handlers.js.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/persistence.d.ts +11 -0
- package/dist/persistence.d.ts.map +1 -1
- package/dist/persistence.js +77 -0
- package/dist/persistence.js.map +1 -1
- package/dist/schemas.d.ts +95 -8
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +97 -2
- package/dist/schemas.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,878 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anastops MCP v3.0 - Consolidated Utility and Data Management Tools
|
|
3
|
+
*
|
|
4
|
+
* This module implements the aggressive consolidation plan for v3.0:
|
|
5
|
+
* - Data tools: 6 → 2 (data_manage, data_query)
|
|
6
|
+
* - Utility tools: 3 → 1 (system_query)
|
|
7
|
+
* - Lock tools: 3 → 1 (lock_manage)
|
|
8
|
+
* - Monitoring tools: 3 → 1 (session_monitoring)
|
|
9
|
+
* - Config tools: 2 → 1 (config_manage)
|
|
10
|
+
*
|
|
11
|
+
* Total reduction: 17 tools → 6 tools (65% reduction)
|
|
12
|
+
*/
|
|
13
|
+
import { nanoid } from 'nanoid';
|
|
14
|
+
import { getArtifact, safePersist } from '../utils.js';
|
|
15
|
+
/* ========================================================================
|
|
16
|
+
* DATA MANAGEMENT TOOLS (2 tools)
|
|
17
|
+
* Consolidates: memory_store, memory_retrieve, artifact_save, artifact_get,
|
|
18
|
+
* artifact_list, context_optimize
|
|
19
|
+
* ======================================================================== */
|
|
20
|
+
/**
|
|
21
|
+
* Data Management Tool - Write Operations
|
|
22
|
+
*
|
|
23
|
+
* Handles all data write operations:
|
|
24
|
+
* - store: Store data in memory (replaces memory_store)
|
|
25
|
+
* - save: Save artifact (replaces artifact_save)
|
|
26
|
+
* - optimize: Optimize context for token reduction (replaces context_optimize)
|
|
27
|
+
*/
|
|
28
|
+
export const dataManageTool = {
|
|
29
|
+
name: 'data_manage',
|
|
30
|
+
description: 'Manage data operations: store memory, save artifacts, or optimize context. Use operation="store" for memory storage, operation="save" for artifact creation, operation="optimize" for context token reduction.',
|
|
31
|
+
inputSchema: {
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
operation: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
enum: ['store', 'save', 'optimize'],
|
|
37
|
+
description: 'Operation type: store=memory storage, save=artifact creation, optimize=context optimization',
|
|
38
|
+
},
|
|
39
|
+
// For memory_store operation
|
|
40
|
+
key: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
description: 'For store operation: memory key to store value under',
|
|
43
|
+
},
|
|
44
|
+
value: {
|
|
45
|
+
description: 'For store operation: value to store (any JSON-serializable type)',
|
|
46
|
+
},
|
|
47
|
+
// For artifact_save operation
|
|
48
|
+
session_id: {
|
|
49
|
+
type: 'string',
|
|
50
|
+
description: 'Required for save/optimize operations: session ID',
|
|
51
|
+
},
|
|
52
|
+
artifact_type: {
|
|
53
|
+
type: 'string',
|
|
54
|
+
enum: ['code', 'document', 'data', 'config', 'test', 'other'],
|
|
55
|
+
description: 'For save operation: artifact type classification',
|
|
56
|
+
},
|
|
57
|
+
name: {
|
|
58
|
+
type: 'string',
|
|
59
|
+
description: 'For save operation: artifact name/filename',
|
|
60
|
+
},
|
|
61
|
+
content: {
|
|
62
|
+
type: 'string',
|
|
63
|
+
description: 'For save operation: artifact content',
|
|
64
|
+
},
|
|
65
|
+
// For context_optimize operation
|
|
66
|
+
objective: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: 'For optimize operation: session objective for context optimization',
|
|
69
|
+
},
|
|
70
|
+
phase: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
description: 'For optimize operation: current phase of work',
|
|
73
|
+
},
|
|
74
|
+
progress: {
|
|
75
|
+
type: 'number',
|
|
76
|
+
description: 'For optimize operation: progress percentage (0-1)',
|
|
77
|
+
},
|
|
78
|
+
messages: {
|
|
79
|
+
type: 'array',
|
|
80
|
+
description: 'For optimize operation: messages to optimize',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
required: ['operation'],
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Data Query Tool - Read Operations
|
|
88
|
+
*
|
|
89
|
+
* Handles all data read operations:
|
|
90
|
+
* - retrieve: Retrieve data from memory (replaces memory_retrieve)
|
|
91
|
+
* - get: Get single artifact by ID (replaces artifact_get)
|
|
92
|
+
* - list: List all artifacts for session (replaces artifact_list)
|
|
93
|
+
*/
|
|
94
|
+
export const dataQueryTool = {
|
|
95
|
+
name: 'data_query',
|
|
96
|
+
description: 'Query data: retrieve memory, get artifacts, or list artifacts. Use operation="retrieve" for memory lookup, operation="get" for single artifact, operation="list" for all session artifacts.',
|
|
97
|
+
inputSchema: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
operation: {
|
|
101
|
+
type: 'string',
|
|
102
|
+
enum: ['retrieve', 'get', 'list'],
|
|
103
|
+
description: 'Operation type: retrieve=memory lookup, get=single artifact, list=all artifacts',
|
|
104
|
+
},
|
|
105
|
+
// For memory_retrieve operation
|
|
106
|
+
key: {
|
|
107
|
+
type: 'string',
|
|
108
|
+
description: 'For retrieve operation: memory key to lookup',
|
|
109
|
+
},
|
|
110
|
+
// For artifact_get operation
|
|
111
|
+
artifact_id: {
|
|
112
|
+
type: 'string',
|
|
113
|
+
description: 'For get operation: artifact ID to retrieve',
|
|
114
|
+
},
|
|
115
|
+
// For artifact_list operation
|
|
116
|
+
session_id: {
|
|
117
|
+
type: 'string',
|
|
118
|
+
description: 'Required for list operation: session ID to list artifacts from',
|
|
119
|
+
},
|
|
120
|
+
artifact_type: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
enum: ['code', 'document', 'data', 'config', 'test', 'other'],
|
|
123
|
+
description: 'For list operation: optional filter by artifact type',
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
required: ['operation'],
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
/* ========================================================================
|
|
130
|
+
* UTILITY TOOLS (4 tools)
|
|
131
|
+
* Consolidates system utilities, locks, monitoring, and config
|
|
132
|
+
* ======================================================================== */
|
|
133
|
+
/**
|
|
134
|
+
* System Query Tool
|
|
135
|
+
*
|
|
136
|
+
* Handles all system-level query operations:
|
|
137
|
+
* - health: Check system health (replaces health_check)
|
|
138
|
+
* - providers: List available AI providers (replaces provider_list)
|
|
139
|
+
* - metrics: Get system metrics (replaces metrics_get)
|
|
140
|
+
*/
|
|
141
|
+
export const systemQueryTool = {
|
|
142
|
+
name: 'system_query',
|
|
143
|
+
description: 'Query system information: health status, available providers, or system metrics. Use operation="health" for health checks, operation="providers" for provider list, operation="metrics" for system metrics.',
|
|
144
|
+
inputSchema: {
|
|
145
|
+
type: 'object',
|
|
146
|
+
properties: {
|
|
147
|
+
operation: {
|
|
148
|
+
type: 'string',
|
|
149
|
+
enum: ['health', 'providers', 'metrics'],
|
|
150
|
+
description: 'Operation type: health=system health, providers=available providers, metrics=system metrics',
|
|
151
|
+
},
|
|
152
|
+
// For health_check operation
|
|
153
|
+
include_providers: {
|
|
154
|
+
type: 'boolean',
|
|
155
|
+
description: 'For health operation: include provider status in health check',
|
|
156
|
+
},
|
|
157
|
+
// For provider_list operation
|
|
158
|
+
filter_healthy: {
|
|
159
|
+
type: 'boolean',
|
|
160
|
+
description: 'For providers operation: only show healthy providers',
|
|
161
|
+
},
|
|
162
|
+
include_capabilities: {
|
|
163
|
+
type: 'boolean',
|
|
164
|
+
description: 'For providers operation: include provider capabilities',
|
|
165
|
+
},
|
|
166
|
+
// For metrics_get operation
|
|
167
|
+
metric_type: {
|
|
168
|
+
type: 'string',
|
|
169
|
+
enum: ['routing', 'tokens', 'costs', 'all'],
|
|
170
|
+
description: 'For metrics operation: type of metrics to retrieve',
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Lock Management Tool
|
|
177
|
+
*
|
|
178
|
+
* Handles all file lock operations:
|
|
179
|
+
* - acquire: Acquire a file lock (replaces lock_acquire)
|
|
180
|
+
* - release: Release a file lock (replaces lock_release)
|
|
181
|
+
* - status: Check lock status (replaces lock_status)
|
|
182
|
+
*/
|
|
183
|
+
export const lockManageTool = {
|
|
184
|
+
name: 'lock_manage',
|
|
185
|
+
description: 'Manage file locks: acquire, release, or check status. Use operation="acquire" to lock a file, operation="release" to unlock, operation="status" to check lock state.',
|
|
186
|
+
inputSchema: {
|
|
187
|
+
type: 'object',
|
|
188
|
+
properties: {
|
|
189
|
+
operation: {
|
|
190
|
+
type: 'string',
|
|
191
|
+
enum: ['acquire', 'release', 'status'],
|
|
192
|
+
description: 'Operation type: acquire=lock file, release=unlock file, status=check lock',
|
|
193
|
+
},
|
|
194
|
+
session_id: {
|
|
195
|
+
type: 'string',
|
|
196
|
+
description: 'Required for acquire/release, optional for status: session ID',
|
|
197
|
+
},
|
|
198
|
+
file_path: {
|
|
199
|
+
type: 'string',
|
|
200
|
+
description: 'Required for acquire/release, optional for status: file path to lock',
|
|
201
|
+
},
|
|
202
|
+
ttl: {
|
|
203
|
+
type: 'number',
|
|
204
|
+
description: 'For acquire operation: lock TTL in milliseconds (default: 300000)',
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
required: ['operation'],
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
/**
|
|
211
|
+
* Session Monitoring Tool
|
|
212
|
+
*
|
|
213
|
+
* Handles all session monitoring operations:
|
|
214
|
+
* - cost: Get cost breakdown (replaces session_cost)
|
|
215
|
+
* - metrics: Get request/token metrics (replaces session_metrics)
|
|
216
|
+
* - throttle: Check rate limit status (replaces session_throttle)
|
|
217
|
+
*/
|
|
218
|
+
export const sessionMonitoringTool = {
|
|
219
|
+
name: 'session_monitoring',
|
|
220
|
+
description: 'Monitor session activity: cost breakdown, token metrics, or rate limits. Use operation="cost" for costs, operation="metrics" for token usage, operation="throttle" for rate limits.',
|
|
221
|
+
inputSchema: {
|
|
222
|
+
type: 'object',
|
|
223
|
+
properties: {
|
|
224
|
+
operation: {
|
|
225
|
+
type: 'string',
|
|
226
|
+
enum: ['cost', 'metrics', 'throttle'],
|
|
227
|
+
description: 'Operation type: cost=cost breakdown, metrics=token usage, throttle=rate limits',
|
|
228
|
+
},
|
|
229
|
+
session_id: {
|
|
230
|
+
type: 'string',
|
|
231
|
+
description: 'Required for all operations: session ID to monitor',
|
|
232
|
+
},
|
|
233
|
+
provider: {
|
|
234
|
+
type: 'string',
|
|
235
|
+
description: 'For throttle operation: specific provider to check',
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
required: ['operation', 'session_id'],
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
/**
|
|
242
|
+
* Configuration Management Tool
|
|
243
|
+
*
|
|
244
|
+
* Handles all configuration operations:
|
|
245
|
+
* - get: Get configuration value (replaces config_get)
|
|
246
|
+
* - set: Set configuration value (replaces config_set)
|
|
247
|
+
*/
|
|
248
|
+
export const configManageTool = {
|
|
249
|
+
name: 'config_manage',
|
|
250
|
+
description: 'Manage configuration: get or set values. Use operation="get" to retrieve config, operation="set" to update config.',
|
|
251
|
+
inputSchema: {
|
|
252
|
+
type: 'object',
|
|
253
|
+
properties: {
|
|
254
|
+
operation: {
|
|
255
|
+
type: 'string',
|
|
256
|
+
enum: ['get', 'set'],
|
|
257
|
+
description: 'Operation type: get=retrieve value, set=update value',
|
|
258
|
+
},
|
|
259
|
+
key: {
|
|
260
|
+
type: 'string',
|
|
261
|
+
description: 'Required for both operations: configuration key',
|
|
262
|
+
},
|
|
263
|
+
value: {
|
|
264
|
+
description: 'Required for set operation: value to set (any JSON-serializable type)',
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
required: ['operation', 'key'],
|
|
268
|
+
},
|
|
269
|
+
};
|
|
270
|
+
/* ========================================================================
|
|
271
|
+
* HANDLER IMPLEMENTATIONS
|
|
272
|
+
* ======================================================================== */
|
|
273
|
+
/**
|
|
274
|
+
* Handle data_manage operations
|
|
275
|
+
*/
|
|
276
|
+
export function handleDataManage(args, context) {
|
|
277
|
+
const operation = args['operation'];
|
|
278
|
+
switch (operation) {
|
|
279
|
+
case 'store': {
|
|
280
|
+
// Validate required parameters
|
|
281
|
+
if (typeof args['key'] !== 'string') {
|
|
282
|
+
throw new Error('Missing required parameter: key (string)');
|
|
283
|
+
}
|
|
284
|
+
if (args['value'] === undefined) {
|
|
285
|
+
throw new Error('Missing required parameter: value');
|
|
286
|
+
}
|
|
287
|
+
// Build storage key (session-scoped if session_id provided)
|
|
288
|
+
const key = args['session_id'] !== undefined
|
|
289
|
+
? `${String(args['session_id'])}:${String(args['key'])}`
|
|
290
|
+
: String(args['key']);
|
|
291
|
+
// Store in memory
|
|
292
|
+
context.memoryStore.set(key, {
|
|
293
|
+
value: args['value'],
|
|
294
|
+
stored_at: new Date(),
|
|
295
|
+
});
|
|
296
|
+
return {
|
|
297
|
+
operation: 'store',
|
|
298
|
+
key,
|
|
299
|
+
stored: true,
|
|
300
|
+
timestamp: new Date(),
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
case 'save': {
|
|
304
|
+
// Validate required parameters
|
|
305
|
+
if (typeof args['session_id'] !== 'string') {
|
|
306
|
+
throw new Error('Missing required parameter: session_id (string)');
|
|
307
|
+
}
|
|
308
|
+
if (typeof args['artifact_type'] !== 'string') {
|
|
309
|
+
throw new Error('Missing required parameter: artifact_type (string)');
|
|
310
|
+
}
|
|
311
|
+
if (typeof args['name'] !== 'string') {
|
|
312
|
+
throw new Error('Missing required parameter: name (string)');
|
|
313
|
+
}
|
|
314
|
+
if (typeof args['content'] !== 'string') {
|
|
315
|
+
throw new Error('Missing required parameter: content (string)');
|
|
316
|
+
}
|
|
317
|
+
// Create artifact
|
|
318
|
+
const artifactId = nanoid(21);
|
|
319
|
+
const now = new Date();
|
|
320
|
+
const content = String(args['content']);
|
|
321
|
+
const artifactTypeArg = args['artifact_type'];
|
|
322
|
+
const artifactType = typeof artifactTypeArg === 'string' ? artifactTypeArg : 'other';
|
|
323
|
+
const sessionId = String(args['session_id']);
|
|
324
|
+
const name = String(args['name']);
|
|
325
|
+
const artifact = {
|
|
326
|
+
id: artifactId,
|
|
327
|
+
session_id: sessionId,
|
|
328
|
+
task_id: null,
|
|
329
|
+
type: artifactType,
|
|
330
|
+
name,
|
|
331
|
+
extension: '',
|
|
332
|
+
content,
|
|
333
|
+
content_hash: '',
|
|
334
|
+
size_bytes: content.length,
|
|
335
|
+
summary: content.slice(0, 200),
|
|
336
|
+
token_count: Math.ceil(content.length / 4),
|
|
337
|
+
relevance_score: 50,
|
|
338
|
+
metadata: {},
|
|
339
|
+
created_at: now,
|
|
340
|
+
updated_at: now,
|
|
341
|
+
};
|
|
342
|
+
// Store in memory
|
|
343
|
+
context.artifacts.set(artifactId, artifact);
|
|
344
|
+
// Persist to MongoDB
|
|
345
|
+
safePersist(context.getPersistence().saveArtifact(artifact));
|
|
346
|
+
return {
|
|
347
|
+
operation: 'save',
|
|
348
|
+
artifact_id: artifact.id,
|
|
349
|
+
name: artifact.name,
|
|
350
|
+
type: artifact.type,
|
|
351
|
+
size_bytes: artifact.size_bytes,
|
|
352
|
+
created_at: artifact.created_at,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
case 'optimize': {
|
|
356
|
+
// Validate required parameters
|
|
357
|
+
if (typeof args['session_id'] !== 'string') {
|
|
358
|
+
throw new Error('Missing required parameter: session_id (string)');
|
|
359
|
+
}
|
|
360
|
+
if (typeof args['objective'] !== 'string') {
|
|
361
|
+
throw new Error('Missing required parameter: objective (string)');
|
|
362
|
+
}
|
|
363
|
+
if (typeof args['phase'] !== 'string') {
|
|
364
|
+
throw new Error('Missing required parameter: phase (string)');
|
|
365
|
+
}
|
|
366
|
+
if (typeof args['progress'] !== 'number') {
|
|
367
|
+
throw new Error('Missing required parameter: progress (number)');
|
|
368
|
+
}
|
|
369
|
+
if (!Array.isArray(args['messages'])) {
|
|
370
|
+
throw new Error('Missing required parameter: messages (array)');
|
|
371
|
+
}
|
|
372
|
+
// Placeholder for context optimization
|
|
373
|
+
// In production, this would use ContextOptimizer from @anastops/core
|
|
374
|
+
return {
|
|
375
|
+
operation: 'optimize',
|
|
376
|
+
session_id: args['session_id'],
|
|
377
|
+
original_tokens: 1000,
|
|
378
|
+
optimized_tokens: 500,
|
|
379
|
+
reduction_percent: 50,
|
|
380
|
+
minimal_context: args['messages'],
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
default:
|
|
384
|
+
throw new Error(`Unknown data_manage operation: ${String(operation)}`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Handle data_query operations
|
|
389
|
+
*/
|
|
390
|
+
export async function handleDataQuery(args, context) {
|
|
391
|
+
const operation = args['operation'];
|
|
392
|
+
switch (operation) {
|
|
393
|
+
case 'retrieve': {
|
|
394
|
+
// Validate required parameters
|
|
395
|
+
if (typeof args['key'] !== 'string') {
|
|
396
|
+
throw new Error('Missing required parameter: key (string)');
|
|
397
|
+
}
|
|
398
|
+
// Retrieve from memory
|
|
399
|
+
const key = String(args['key']);
|
|
400
|
+
const data = context.memoryStore.get(key);
|
|
401
|
+
if (data === undefined) {
|
|
402
|
+
throw new Error(`Key not found: ${key}`);
|
|
403
|
+
}
|
|
404
|
+
return {
|
|
405
|
+
operation: 'retrieve',
|
|
406
|
+
key: args['key'],
|
|
407
|
+
found: true,
|
|
408
|
+
data,
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
case 'get': {
|
|
412
|
+
// Validate required parameters
|
|
413
|
+
if (typeof args['artifact_id'] !== 'string') {
|
|
414
|
+
throw new Error('Missing required parameter: artifact_id (string)');
|
|
415
|
+
}
|
|
416
|
+
// Get artifact
|
|
417
|
+
const artifactId = String(args['artifact_id']);
|
|
418
|
+
const artifact = await getArtifact(artifactId, context);
|
|
419
|
+
if (artifact === null) {
|
|
420
|
+
throw new Error(`Artifact not found: ${artifactId}`);
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
operation: 'get',
|
|
424
|
+
...artifact,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
case 'list': {
|
|
428
|
+
// Validate required parameters
|
|
429
|
+
if (typeof args['session_id'] !== 'string') {
|
|
430
|
+
throw new Error('Missing required parameter: session_id (string)');
|
|
431
|
+
}
|
|
432
|
+
const sessionId = String(args['session_id']);
|
|
433
|
+
const artifactTypeArg = args['artifact_type'];
|
|
434
|
+
const typeFilter = typeof artifactTypeArg === 'string' ? artifactTypeArg : undefined;
|
|
435
|
+
// Get from in-memory cache first
|
|
436
|
+
const inMemoryArtifacts = [];
|
|
437
|
+
for (const [, artifact] of context.artifacts.entries()) {
|
|
438
|
+
if (artifact.session_id === sessionId) {
|
|
439
|
+
if (typeFilter === undefined || artifact.type === typeFilter) {
|
|
440
|
+
inMemoryArtifacts.push(artifact);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
// Also get from MongoDB for persistence
|
|
445
|
+
const persistedArtifacts = await context.getPersistence().listArtifacts({
|
|
446
|
+
session_id: sessionId,
|
|
447
|
+
...(typeFilter !== undefined && { type: typeFilter }),
|
|
448
|
+
});
|
|
449
|
+
// Merge: in-memory takes precedence
|
|
450
|
+
const inMemoryIds = new Set(inMemoryArtifacts.map((a) => a.id));
|
|
451
|
+
const sessionArtifacts = [
|
|
452
|
+
...inMemoryArtifacts,
|
|
453
|
+
...persistedArtifacts.filter((a) => !inMemoryIds.has(a.id)),
|
|
454
|
+
];
|
|
455
|
+
return {
|
|
456
|
+
operation: 'list',
|
|
457
|
+
session_id: sessionId,
|
|
458
|
+
count: sessionArtifacts.length,
|
|
459
|
+
...(typeFilter !== undefined && { type_filter: typeFilter }),
|
|
460
|
+
artifacts: sessionArtifacts.map((a) => ({
|
|
461
|
+
id: a.id,
|
|
462
|
+
name: a.name,
|
|
463
|
+
type: a.type,
|
|
464
|
+
size_bytes: a.size_bytes,
|
|
465
|
+
created_at: a.created_at,
|
|
466
|
+
})),
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
default:
|
|
470
|
+
throw new Error(`Unknown data_query operation: ${String(operation)}`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* Handle system_query operations
|
|
475
|
+
*/
|
|
476
|
+
export async function handleSystemQuery(args, context) {
|
|
477
|
+
const operation = args['operation'] ?? 'health';
|
|
478
|
+
switch (operation) {
|
|
479
|
+
case 'health': {
|
|
480
|
+
// Check MongoDB persistence health
|
|
481
|
+
const persistence = context.getPersistence();
|
|
482
|
+
const isMongoConnected = persistence.isConnected();
|
|
483
|
+
const result = {
|
|
484
|
+
operation: 'health',
|
|
485
|
+
status: isMongoConnected ? 'healthy' : 'degraded',
|
|
486
|
+
timestamp: new Date(),
|
|
487
|
+
components: {
|
|
488
|
+
core: 'healthy',
|
|
489
|
+
router: 'healthy',
|
|
490
|
+
persistence: isMongoConnected ? 'connected' : 'disconnected',
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
if (!isMongoConnected) {
|
|
494
|
+
result['warning'] =
|
|
495
|
+
'MongoDB is not connected. Run "docker ps | grep anastops-mongodb" to verify containers are running.';
|
|
496
|
+
}
|
|
497
|
+
if (args['include_providers'] === true) {
|
|
498
|
+
const providerHealth = {};
|
|
499
|
+
for (const adapter of context.registry.list()) {
|
|
500
|
+
const health = await adapter.healthCheck();
|
|
501
|
+
providerHealth[adapter.type] = {
|
|
502
|
+
healthy: health.healthy,
|
|
503
|
+
error: health.error,
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
result['providers'] = providerHealth;
|
|
507
|
+
}
|
|
508
|
+
return result;
|
|
509
|
+
}
|
|
510
|
+
case 'providers': {
|
|
511
|
+
const providers = [];
|
|
512
|
+
for (const adapter of context.registry.list()) {
|
|
513
|
+
const health = await adapter.healthCheck();
|
|
514
|
+
if (args['filter_healthy'] === true && !health.healthy)
|
|
515
|
+
continue;
|
|
516
|
+
const info = {
|
|
517
|
+
type: adapter.type,
|
|
518
|
+
name: adapter.name,
|
|
519
|
+
healthy: health.healthy,
|
|
520
|
+
};
|
|
521
|
+
if (args['include_capabilities'] === true) {
|
|
522
|
+
const caps = await adapter.getCapabilities();
|
|
523
|
+
info['capabilities'] = caps;
|
|
524
|
+
}
|
|
525
|
+
providers.push(info);
|
|
526
|
+
}
|
|
527
|
+
return {
|
|
528
|
+
operation: 'providers',
|
|
529
|
+
count: providers.length,
|
|
530
|
+
providers,
|
|
531
|
+
};
|
|
532
|
+
}
|
|
533
|
+
case 'metrics': {
|
|
534
|
+
// Placeholder metrics
|
|
535
|
+
return {
|
|
536
|
+
operation: 'metrics',
|
|
537
|
+
routing: {
|
|
538
|
+
tier_distribution: {},
|
|
539
|
+
provider_stats: {},
|
|
540
|
+
},
|
|
541
|
+
tokens: {
|
|
542
|
+
total: 0,
|
|
543
|
+
by_provider: {},
|
|
544
|
+
},
|
|
545
|
+
costs: {
|
|
546
|
+
total: 0,
|
|
547
|
+
by_provider: {},
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
default:
|
|
552
|
+
throw new Error(`Unknown system_query operation: ${String(operation)}`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Handle lock_manage operations
|
|
557
|
+
*/
|
|
558
|
+
export function handleLockManage(args, context) {
|
|
559
|
+
const operation = args['operation'];
|
|
560
|
+
switch (operation) {
|
|
561
|
+
case 'acquire': {
|
|
562
|
+
// Validate required parameters
|
|
563
|
+
if (typeof args['session_id'] !== 'string') {
|
|
564
|
+
throw new Error('Missing required parameter: session_id (string)');
|
|
565
|
+
}
|
|
566
|
+
if (typeof args['file_path'] !== 'string') {
|
|
567
|
+
throw new Error('Missing required parameter: file_path (string)');
|
|
568
|
+
}
|
|
569
|
+
const sessionId = String(args['session_id']);
|
|
570
|
+
const filePath = String(args['file_path']);
|
|
571
|
+
const ttlArg = args['ttl'];
|
|
572
|
+
const ttl = typeof ttlArg === 'number' ? ttlArg : 300000;
|
|
573
|
+
// In-memory lock implementation (Redis-based in production)
|
|
574
|
+
const lockKey = `lock:${filePath}`;
|
|
575
|
+
const existingLock = context.memoryStore.get(lockKey);
|
|
576
|
+
if (existingLock !== undefined) {
|
|
577
|
+
const lockData = existingLock.value;
|
|
578
|
+
// Check if lock is expired
|
|
579
|
+
if (lockData.expires_at > Date.now() && lockData.session_id !== sessionId) {
|
|
580
|
+
return {
|
|
581
|
+
operation: 'acquire',
|
|
582
|
+
session_id: sessionId,
|
|
583
|
+
file_path: filePath,
|
|
584
|
+
acquired: false,
|
|
585
|
+
owner: lockData.session_id,
|
|
586
|
+
ttl,
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
// Acquire lock
|
|
591
|
+
context.memoryStore.set(lockKey, {
|
|
592
|
+
value: { session_id: sessionId, expires_at: Date.now() + ttl },
|
|
593
|
+
stored_at: new Date(),
|
|
594
|
+
});
|
|
595
|
+
return {
|
|
596
|
+
operation: 'acquire',
|
|
597
|
+
session_id: sessionId,
|
|
598
|
+
file_path: filePath,
|
|
599
|
+
acquired: true,
|
|
600
|
+
ttl,
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
case 'release': {
|
|
604
|
+
// Validate required parameters
|
|
605
|
+
if (typeof args['session_id'] !== 'string') {
|
|
606
|
+
throw new Error('Missing required parameter: session_id (string)');
|
|
607
|
+
}
|
|
608
|
+
if (typeof args['file_path'] !== 'string') {
|
|
609
|
+
throw new Error('Missing required parameter: file_path (string)');
|
|
610
|
+
}
|
|
611
|
+
const relSessionId = String(args['session_id']);
|
|
612
|
+
const relFilePath = String(args['file_path']);
|
|
613
|
+
const lockKey = `lock:${relFilePath}`;
|
|
614
|
+
const existingLock = context.memoryStore.get(lockKey);
|
|
615
|
+
if (existingLock !== undefined) {
|
|
616
|
+
const lockData = existingLock.value;
|
|
617
|
+
if (lockData.session_id === relSessionId) {
|
|
618
|
+
context.memoryStore.delete(lockKey);
|
|
619
|
+
return {
|
|
620
|
+
operation: 'release',
|
|
621
|
+
session_id: relSessionId,
|
|
622
|
+
file_path: relFilePath,
|
|
623
|
+
released: true,
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
return {
|
|
627
|
+
operation: 'release',
|
|
628
|
+
session_id: relSessionId,
|
|
629
|
+
file_path: relFilePath,
|
|
630
|
+
released: false,
|
|
631
|
+
error: 'Lock is held by another session',
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
return {
|
|
635
|
+
operation: 'release',
|
|
636
|
+
session_id: relSessionId,
|
|
637
|
+
file_path: relFilePath,
|
|
638
|
+
released: true,
|
|
639
|
+
message: 'Lock did not exist',
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
case 'status': {
|
|
643
|
+
const sessionId = args['session_id'];
|
|
644
|
+
const filePath = args['file_path'];
|
|
645
|
+
if (filePath !== undefined) {
|
|
646
|
+
const lockKey = `lock:${filePath}`;
|
|
647
|
+
const existingLock = context.memoryStore.get(lockKey);
|
|
648
|
+
if (existingLock !== undefined) {
|
|
649
|
+
const lockData = existingLock.value;
|
|
650
|
+
const isExpired = lockData.expires_at <= Date.now();
|
|
651
|
+
return {
|
|
652
|
+
operation: 'status',
|
|
653
|
+
file_path: filePath,
|
|
654
|
+
is_locked: !isExpired,
|
|
655
|
+
owner: isExpired ? null : lockData.session_id,
|
|
656
|
+
expires_at: lockData.expires_at,
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
return {
|
|
660
|
+
operation: 'status',
|
|
661
|
+
file_path: filePath,
|
|
662
|
+
is_locked: false,
|
|
663
|
+
owner: null,
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
if (sessionId !== undefined) {
|
|
667
|
+
// List all locks held by this session
|
|
668
|
+
const sessionLocks = [];
|
|
669
|
+
for (const [key, data] of context.memoryStore.entries()) {
|
|
670
|
+
if (key.startsWith('lock:')) {
|
|
671
|
+
const lockData = data.value;
|
|
672
|
+
if (lockData.session_id === sessionId && lockData.expires_at > Date.now()) {
|
|
673
|
+
sessionLocks.push({
|
|
674
|
+
file_path: key.replace('lock:', ''),
|
|
675
|
+
expires_at: lockData.expires_at,
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
return {
|
|
681
|
+
operation: 'status',
|
|
682
|
+
session_id: sessionId,
|
|
683
|
+
lock_count: sessionLocks.length,
|
|
684
|
+
locks: sessionLocks,
|
|
685
|
+
};
|
|
686
|
+
}
|
|
687
|
+
throw new Error('Must provide either session_id or file_path for lock status');
|
|
688
|
+
}
|
|
689
|
+
default:
|
|
690
|
+
throw new Error(`Unknown lock_manage operation: ${String(operation)}`);
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* Handle session_monitoring operations
|
|
695
|
+
*/
|
|
696
|
+
export function handleSessionMonitoring(args, context) {
|
|
697
|
+
const operation = args['operation'];
|
|
698
|
+
// Validate session_id (required for all operations)
|
|
699
|
+
if (typeof args['session_id'] !== 'string') {
|
|
700
|
+
throw new Error('Missing required parameter: session_id (string)');
|
|
701
|
+
}
|
|
702
|
+
const sessionId = String(args['session_id']);
|
|
703
|
+
switch (operation) {
|
|
704
|
+
case 'cost': {
|
|
705
|
+
// Aggregate cost from task token_usage
|
|
706
|
+
let totalCost = 0;
|
|
707
|
+
for (const [, task] of context.tasks.entries()) {
|
|
708
|
+
if (task.session_id === sessionId && task.token_usage !== undefined) {
|
|
709
|
+
totalCost += task.token_usage.cost ?? 0;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return {
|
|
713
|
+
operation: 'cost',
|
|
714
|
+
session_id: sessionId,
|
|
715
|
+
total_cost_usd: totalCost,
|
|
716
|
+
currency: 'USD',
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
case 'metrics': {
|
|
720
|
+
// Aggregate metrics from tasks
|
|
721
|
+
let requestCount = 0;
|
|
722
|
+
let inputTokens = 0;
|
|
723
|
+
let outputTokens = 0;
|
|
724
|
+
let totalTokens = 0;
|
|
725
|
+
for (const [, task] of context.tasks.entries()) {
|
|
726
|
+
if (task.session_id === sessionId) {
|
|
727
|
+
requestCount++;
|
|
728
|
+
if (task.token_usage !== undefined) {
|
|
729
|
+
inputTokens += task.token_usage.prompt_tokens ?? 0;
|
|
730
|
+
outputTokens += task.token_usage.completion_tokens ?? 0;
|
|
731
|
+
totalTokens += task.token_usage.total_tokens ?? 0;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
return {
|
|
736
|
+
operation: 'metrics',
|
|
737
|
+
session_id: sessionId,
|
|
738
|
+
request_count: requestCount,
|
|
739
|
+
token_usage: {
|
|
740
|
+
input: inputTokens,
|
|
741
|
+
output: outputTokens,
|
|
742
|
+
total: totalTokens,
|
|
743
|
+
},
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
case 'throttle': {
|
|
747
|
+
const provider = args['provider'] ?? 'claude';
|
|
748
|
+
// In-memory rate limit tracking (Redis-based in production)
|
|
749
|
+
const rateKey = `rate:${sessionId}:${provider}`;
|
|
750
|
+
const rateData = context.memoryStore.get(rateKey);
|
|
751
|
+
// Default limits per provider (requests per minute)
|
|
752
|
+
const defaultLimit = 30;
|
|
753
|
+
const limits = {
|
|
754
|
+
claude: 50,
|
|
755
|
+
openai: 60,
|
|
756
|
+
gemini: 60,
|
|
757
|
+
};
|
|
758
|
+
const limit = limits[provider] ?? defaultLimit;
|
|
759
|
+
if (rateData !== undefined) {
|
|
760
|
+
const data = rateData.value;
|
|
761
|
+
const windowSize = 60000; // 1 minute
|
|
762
|
+
const now = Date.now();
|
|
763
|
+
if (now - data.window_start > windowSize) {
|
|
764
|
+
// Window expired, reset
|
|
765
|
+
return {
|
|
766
|
+
operation: 'throttle',
|
|
767
|
+
session_id: sessionId,
|
|
768
|
+
provider,
|
|
769
|
+
usage_percent: 0,
|
|
770
|
+
current_count: 0,
|
|
771
|
+
limit,
|
|
772
|
+
throttled: false,
|
|
773
|
+
blocked: false,
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
const usagePercent = (data.count / limit) * 100;
|
|
777
|
+
return {
|
|
778
|
+
operation: 'throttle',
|
|
779
|
+
session_id: sessionId,
|
|
780
|
+
provider,
|
|
781
|
+
usage_percent: Math.min(100, usagePercent),
|
|
782
|
+
current_count: data.count,
|
|
783
|
+
limit,
|
|
784
|
+
throttled: usagePercent >= 85,
|
|
785
|
+
blocked: usagePercent >= 95,
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
return {
|
|
789
|
+
operation: 'throttle',
|
|
790
|
+
session_id: sessionId,
|
|
791
|
+
provider,
|
|
792
|
+
usage_percent: 0,
|
|
793
|
+
current_count: 0,
|
|
794
|
+
limit,
|
|
795
|
+
throttled: false,
|
|
796
|
+
blocked: false,
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
default:
|
|
800
|
+
throw new Error(`Unknown session_monitoring operation: ${String(operation)}`);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Handle config_manage operations
|
|
805
|
+
*/
|
|
806
|
+
export function handleConfigManage(args, _context) {
|
|
807
|
+
const operation = args['operation'];
|
|
808
|
+
// Validate key (required for both operations)
|
|
809
|
+
if (typeof args['key'] !== 'string') {
|
|
810
|
+
throw new Error('Missing required parameter: key (string)');
|
|
811
|
+
}
|
|
812
|
+
switch (operation) {
|
|
813
|
+
case 'get': {
|
|
814
|
+
// Placeholder config
|
|
815
|
+
const config = {
|
|
816
|
+
default_provider: 'claude',
|
|
817
|
+
default_timeout: 600000, // 10 minutes
|
|
818
|
+
context_budget: 1600,
|
|
819
|
+
};
|
|
820
|
+
const configKey = String(args['key']);
|
|
821
|
+
return {
|
|
822
|
+
operation: 'get',
|
|
823
|
+
key: configKey,
|
|
824
|
+
value: config[configKey],
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
case 'set': {
|
|
828
|
+
// Validate value (required for set)
|
|
829
|
+
if (args['value'] === undefined) {
|
|
830
|
+
throw new Error('Missing required parameter: value for set operation');
|
|
831
|
+
}
|
|
832
|
+
return {
|
|
833
|
+
operation: 'set',
|
|
834
|
+
key: args['key'],
|
|
835
|
+
value: args['value'],
|
|
836
|
+
updated: true,
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
default:
|
|
840
|
+
throw new Error(`Unknown config_manage operation: ${String(operation)}`);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
/* ========================================================================
|
|
844
|
+
* EXPORTS
|
|
845
|
+
* ======================================================================== */
|
|
846
|
+
/**
|
|
847
|
+
* All v3.0 utility and data tool definitions
|
|
848
|
+
*/
|
|
849
|
+
export const toolDefinitions = [
|
|
850
|
+
dataManageTool,
|
|
851
|
+
dataQueryTool,
|
|
852
|
+
systemQueryTool,
|
|
853
|
+
lockManageTool,
|
|
854
|
+
sessionMonitoringTool,
|
|
855
|
+
configManageTool,
|
|
856
|
+
];
|
|
857
|
+
/**
|
|
858
|
+
* Main handler router for all v3.0 utility and data tools
|
|
859
|
+
*/
|
|
860
|
+
export async function handleTool(name, args, context) {
|
|
861
|
+
switch (name) {
|
|
862
|
+
case 'data_manage':
|
|
863
|
+
return handleDataManage(args, context);
|
|
864
|
+
case 'data_query':
|
|
865
|
+
return handleDataQuery(args, context);
|
|
866
|
+
case 'system_query':
|
|
867
|
+
return handleSystemQuery(args, context);
|
|
868
|
+
case 'lock_manage':
|
|
869
|
+
return handleLockManage(args, context);
|
|
870
|
+
case 'session_monitoring':
|
|
871
|
+
return handleSessionMonitoring(args, context);
|
|
872
|
+
case 'config_manage':
|
|
873
|
+
return handleConfigManage(args, context);
|
|
874
|
+
default:
|
|
875
|
+
throw new Error(`Unknown v3.0 utility/data tool: ${name}`);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
//# sourceMappingURL=utility-tools.js.map
|