@theone1345/smartrelay 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/README.md +446 -0
- package/config/runners/agents.yaml +47 -0
- package/config/runners/anthropic.yaml +23 -0
- package/config/runners/nvidia.yaml +53 -0
- package/config/runners/ollama.yaml +33 -0
- package/config/runners/openai.yaml +23 -0
- package/config/runners/openrouter.yaml +83 -0
- package/config.yaml +16 -0
- package/dist/benchmark/engine.d.ts +49 -0
- package/dist/benchmark/engine.js +147 -0
- package/dist/benchmark/engine.js.map +1 -0
- package/dist/benchmark/scorers.d.ts +59 -0
- package/dist/benchmark/scorers.js +241 -0
- package/dist/benchmark/scorers.js.map +1 -0
- package/dist/http-api.d.ts +23 -0
- package/dist/http-api.js +329 -0
- package/dist/http-api.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +22 -0
- package/dist/logger.js +34 -0
- package/dist/logger.js.map +1 -0
- package/dist/router.d.ts +33 -0
- package/dist/router.js +298 -0
- package/dist/router.js.map +1 -0
- package/dist/runners/anthropic.d.ts +15 -0
- package/dist/runners/anthropic.js +116 -0
- package/dist/runners/anthropic.js.map +1 -0
- package/dist/runners/base.d.ts +90 -0
- package/dist/runners/base.js +61 -0
- package/dist/runners/base.js.map +1 -0
- package/dist/runners/nvidia.d.ts +14 -0
- package/dist/runners/nvidia.js +23 -0
- package/dist/runners/nvidia.js.map +1 -0
- package/dist/runners/ollama.d.ts +8 -0
- package/dist/runners/ollama.js +107 -0
- package/dist/runners/ollama.js.map +1 -0
- package/dist/runners/openai.d.ts +28 -0
- package/dist/runners/openai.js +131 -0
- package/dist/runners/openai.js.map +1 -0
- package/dist/runners/openrouter.d.ts +11 -0
- package/dist/runners/openrouter.js +19 -0
- package/dist/runners/openrouter.js.map +1 -0
- package/dist/runners/registry.d.ts +53 -0
- package/dist/runners/registry.js +273 -0
- package/dist/runners/registry.js.map +1 -0
- package/dist/server.d.ts +16 -0
- package/dist/server.js +305 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/handlers.d.ts +49 -0
- package/dist/tools/handlers.js +331 -0
- package/dist/tools/handlers.js.map +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/util.d.ts +47 -0
- package/dist/util.js +140 -0
- package/dist/util.js.map +1 -0
- package/package.json +70 -0
- package/prompts/code_review.md +99 -0
- package/prompts/explain_code.md +79 -0
- package/prompts/planner.md +23 -0
- package/prompts/test_generator.md +2 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/** Shared handlers and implementations for all SmartRelay tools. */
|
|
2
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { benchmarkResultToJson } from '../benchmark/engine.js';
|
|
5
|
+
import { getLogger } from '../logger.js';
|
|
6
|
+
import { makeRunnerResult, runnerResultToJson } from '../runners/base.js';
|
|
7
|
+
import { describeError, resolveUserPath } from '../util.js';
|
|
8
|
+
const logger = getLogger('smartrelay.tools');
|
|
9
|
+
/** Extract strictly the review report and remove any model reasoning or scratchpad text. */
|
|
10
|
+
export function cleanReviewOutput(output) {
|
|
11
|
+
const markers = [
|
|
12
|
+
'# 🛡️ Code Review Report',
|
|
13
|
+
'# 🛡️',
|
|
14
|
+
'## 📊 Summary of Findings',
|
|
15
|
+
'## 🚨 Blockers',
|
|
16
|
+
'## 🔴 High Priority Issues',
|
|
17
|
+
'## 🔴 High Priority',
|
|
18
|
+
'## 🟡 Medium Priority Issues',
|
|
19
|
+
'## 🟡 Medium Priority',
|
|
20
|
+
'## 💡 Suggestions & Minor Optimizations',
|
|
21
|
+
'## 💡 Suggestions & Improvements',
|
|
22
|
+
'## 💡 Suggestions',
|
|
23
|
+
'✅ No issues found',
|
|
24
|
+
'⚠️ This reviewer is scoped to Dart/Flutter',
|
|
25
|
+
];
|
|
26
|
+
for (const marker of markers) {
|
|
27
|
+
const idx = output.indexOf(marker);
|
|
28
|
+
if (idx !== -1) {
|
|
29
|
+
return output.slice(idx).trim();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return output.trim();
|
|
33
|
+
}
|
|
34
|
+
/** Read a file from disk, returning `{ content, error }`. */
|
|
35
|
+
export function readFileFromDisk(filePath) {
|
|
36
|
+
try {
|
|
37
|
+
const target = resolveUserPath(filePath);
|
|
38
|
+
if (!existsSync(target)) {
|
|
39
|
+
return { content: null, error: `❌ File not found: \`${filePath}\` (resolved to \`${target}\`)` };
|
|
40
|
+
}
|
|
41
|
+
const stat = statSync(target);
|
|
42
|
+
if (!stat.isFile()) {
|
|
43
|
+
return { content: null, error: `❌ Path is not a file: \`${filePath}\`` };
|
|
44
|
+
}
|
|
45
|
+
const sizeKb = stat.size / 1024;
|
|
46
|
+
if (sizeKb > 500) {
|
|
47
|
+
return {
|
|
48
|
+
content: null,
|
|
49
|
+
error: `⚠️ File too large: \`${filePath}\` (${sizeKb.toFixed(1)} KB). ` +
|
|
50
|
+
'Max recommended: 500 KB (~125K tokens). Split into smaller files.',
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const content = readFileSync(target, 'utf-8');
|
|
54
|
+
return { content, error: null };
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
return { content: null, error: `❌ Error reading file: \`${filePath}\`: ${describeError(err)}` };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Switch the active model/sub-agent for subsequent tasks. */
|
|
61
|
+
export function switchModel(router, model = 'list') {
|
|
62
|
+
const { message } = router.setActiveRunner(model);
|
|
63
|
+
return message;
|
|
64
|
+
}
|
|
65
|
+
/** Get the currently active model and routing mode. */
|
|
66
|
+
export function getActiveModel(router) {
|
|
67
|
+
const info = router.getActiveRunnerInfo();
|
|
68
|
+
return JSON.stringify(info, null, 2);
|
|
69
|
+
}
|
|
70
|
+
/** Create a structured architectural implementation plan. */
|
|
71
|
+
export async function createPlan(router, goal, context = '') {
|
|
72
|
+
const runner = router.routeTask(`Create an implementation plan for: ${goal}`);
|
|
73
|
+
if (!runner) {
|
|
74
|
+
return JSON.stringify({ error: 'No planner runner available. Check config.yaml' });
|
|
75
|
+
}
|
|
76
|
+
let taskPrompt = `Create a comprehensive, phased implementation plan for the following goal:\n\n**Goal**: ${goal}`;
|
|
77
|
+
if (context) {
|
|
78
|
+
taskPrompt += `\n\n**Context & Constraints**:\n${context}`;
|
|
79
|
+
}
|
|
80
|
+
const result = await runner.execute(taskPrompt);
|
|
81
|
+
if (result.success) {
|
|
82
|
+
return result.output;
|
|
83
|
+
}
|
|
84
|
+
return `Plan creation failed: ${result.error_message}`;
|
|
85
|
+
}
|
|
86
|
+
/** Perform an in-depth, expert code review. */
|
|
87
|
+
export async function reviewCode(router, code, focus = 'bugs, security, clean code, and performance') {
|
|
88
|
+
const runner = router.routeTask(`Review code with focus on ${focus}`);
|
|
89
|
+
if (!runner) {
|
|
90
|
+
return JSON.stringify({ error: 'No code review runner available. Check config.yaml' });
|
|
91
|
+
}
|
|
92
|
+
const taskPrompt = `Perform a comprehensive code review focusing on: ${focus}.\n\n` +
|
|
93
|
+
'Format the output strictly using the `# 🛡️ Code Review Report` template with Health Score, ' +
|
|
94
|
+
'Summary Table, 🚨 Blockers, ⚠️ Warnings, 💡 Suggestions, ✅ Commendations, and 🛠️ Verification Commands.\n\n' +
|
|
95
|
+
'STRICT RULES:\n' +
|
|
96
|
+
'- Begin directly with `# 🛡️ Code Review Report`.\n' +
|
|
97
|
+
'- NEVER output or rewrite the entire source code file.\n' +
|
|
98
|
+
'- NEVER include internal thinking process, conversational greetings, or closing text.\n\n' +
|
|
99
|
+
`\`\`\`\n${code}\n\`\`\``;
|
|
100
|
+
const result = await runner.execute(taskPrompt);
|
|
101
|
+
if (result.success) {
|
|
102
|
+
return cleanReviewOutput(result.output);
|
|
103
|
+
}
|
|
104
|
+
return `Code review failed: ${result.error_message}`;
|
|
105
|
+
}
|
|
106
|
+
/** Generate production-ready unit and integration tests. */
|
|
107
|
+
export async function generateTests(router, code, framework = 'standard unit test framework (pytest, flutter_test, etc.)') {
|
|
108
|
+
const runner = router.routeTask('Generate unit tests for this code');
|
|
109
|
+
if (!runner) {
|
|
110
|
+
return JSON.stringify({ error: 'No test generator runner available. Check config.yaml' });
|
|
111
|
+
}
|
|
112
|
+
const taskPrompt = `Generate comprehensive unit and integration tests using ${framework} for this code:\n\n\`\`\`\n${code}\n\`\`\``;
|
|
113
|
+
const result = await runner.execute(taskPrompt);
|
|
114
|
+
if (result.success) {
|
|
115
|
+
return result.output;
|
|
116
|
+
}
|
|
117
|
+
return `Test generation failed: ${result.error_message}`;
|
|
118
|
+
}
|
|
119
|
+
/** Ask any question directly to an external sub-agent model. */
|
|
120
|
+
export async function askSubagent(router, prompt, model = 'auto') {
|
|
121
|
+
const runner = model.toLowerCase() === 'auto' ? router.getDefaultRunner() : router.resolveShortcut(model);
|
|
122
|
+
if (!runner) {
|
|
123
|
+
const allRunners = router.registry.listRunners();
|
|
124
|
+
return JSON.stringify({
|
|
125
|
+
error: `Model '${model}' not found in registry.`,
|
|
126
|
+
available_runners: Array.from(allRunners.keys()),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
logger.info(`ask_subagent: Routing prompt to '${runner.id}' (${runner.model})`);
|
|
130
|
+
const result = await runner.execute(prompt);
|
|
131
|
+
if (result.success) {
|
|
132
|
+
const costStr = result.estimated_cost_usd > 0 ? ` | Cost: $${result.estimated_cost_usd.toFixed(6)}` : '';
|
|
133
|
+
const header = `**[Sub-Agent: ${runner.id} (${runner.model}) | Latency: ${Math.round(result.latency_ms)}ms${costStr}]**\n\n`;
|
|
134
|
+
return `${header}${result.output}`;
|
|
135
|
+
}
|
|
136
|
+
return `Execution error (${runner.id}): ${result.error_message}`;
|
|
137
|
+
}
|
|
138
|
+
/** Review a source code file directly from disk — zero Claude token burn. */
|
|
139
|
+
export async function reviewFile(router, filePath, focus = 'bugs, security, clean code, and performance') {
|
|
140
|
+
const { content: code, error } = readFileFromDisk(filePath);
|
|
141
|
+
if (error || code === null) {
|
|
142
|
+
return error ?? '❌ Could not read file.';
|
|
143
|
+
}
|
|
144
|
+
const resolvedName = path.basename(filePath);
|
|
145
|
+
logger.info(`review_file: Read ${code.length} chars from ${resolvedName}`);
|
|
146
|
+
const runner = router.routeTask(`Review code with focus on ${focus}`);
|
|
147
|
+
if (!runner) {
|
|
148
|
+
return JSON.stringify({ error: 'No code review runner available. Check config.yaml' });
|
|
149
|
+
}
|
|
150
|
+
const taskPrompt = `Perform a comprehensive code review of **\`${resolvedName}\`** focusing on: ${focus}.\n\n` +
|
|
151
|
+
'Format the output strictly using the `# 🛡️ Code Review Report` template with Health Score, ' +
|
|
152
|
+
'Summary Table, 🚨 Blockers, ⚠️ Warnings, 💡 Suggestions, ✅ Commendations, and 🛠️ Verification Commands.\n\n' +
|
|
153
|
+
'STRICT RULES:\n' +
|
|
154
|
+
'- Begin directly with `# 🛡️ Code Review Report`.\n' +
|
|
155
|
+
'- NEVER output or rewrite the entire source code file.\n' +
|
|
156
|
+
'- NEVER include internal thinking process, conversational greetings, or closing text.\n\n' +
|
|
157
|
+
`\`\`\`\n${code}\n\`\`\``;
|
|
158
|
+
const result = await runner.execute(taskPrompt);
|
|
159
|
+
if (result.success) {
|
|
160
|
+
return cleanReviewOutput(result.output);
|
|
161
|
+
}
|
|
162
|
+
return `Code review failed: ${result.error_message}`;
|
|
163
|
+
}
|
|
164
|
+
/** Generate tests for a source code file directly from disk. */
|
|
165
|
+
export async function testFile(router, filePath, framework = 'standard unit test framework (pytest, flutter_test, etc.)') {
|
|
166
|
+
const { content: code, error } = readFileFromDisk(filePath);
|
|
167
|
+
if (error || code === null) {
|
|
168
|
+
return error ?? '❌ Could not read file.';
|
|
169
|
+
}
|
|
170
|
+
const resolvedName = path.basename(filePath);
|
|
171
|
+
logger.info(`test_file: Read ${code.length} chars from ${resolvedName}`);
|
|
172
|
+
const runner = router.routeTask('Generate unit tests for this code');
|
|
173
|
+
if (!runner) {
|
|
174
|
+
return JSON.stringify({ error: 'No test generator runner available. Check config.yaml' });
|
|
175
|
+
}
|
|
176
|
+
const taskPrompt = `Generate comprehensive unit and integration tests using ${framework} ` +
|
|
177
|
+
`for the file **\`${resolvedName}\`**:\n\n\`\`\`\n${code}\n\`\`\``;
|
|
178
|
+
const result = await runner.execute(taskPrompt);
|
|
179
|
+
if (result.success) {
|
|
180
|
+
return result.output;
|
|
181
|
+
}
|
|
182
|
+
return `Test generation failed: ${result.error_message}`;
|
|
183
|
+
}
|
|
184
|
+
/** Get a plain-English explanation of code. */
|
|
185
|
+
export async function explainCode(router, code, audience = 'mid-level engineer', language = 'auto') {
|
|
186
|
+
const runner = router.routeTask('explain what does this code do');
|
|
187
|
+
if (!runner) {
|
|
188
|
+
return JSON.stringify({ error: 'No explainer runner available. Check config.yaml' });
|
|
189
|
+
}
|
|
190
|
+
const langHint = language.toLowerCase() !== 'auto' ? ` (Language: ${language})` : '';
|
|
191
|
+
const taskPrompt = `Explain the following code${langHint} for a ${audience}.\n\n` +
|
|
192
|
+
'Format your response strictly using the `# 📖 Code Explanation:` template.\n\n' +
|
|
193
|
+
`\`\`\`\n${code}\n\`\`\``;
|
|
194
|
+
const result = await runner.execute(taskPrompt);
|
|
195
|
+
if (result.success) {
|
|
196
|
+
return result.output;
|
|
197
|
+
}
|
|
198
|
+
return `Code explanation failed: ${result.error_message}`;
|
|
199
|
+
}
|
|
200
|
+
/** Get a plain-English explanation of a source file directly from disk. */
|
|
201
|
+
export async function explainFile(router, filePath, audience = 'mid-level engineer') {
|
|
202
|
+
const { content: code, error } = readFileFromDisk(filePath);
|
|
203
|
+
if (error || code === null) {
|
|
204
|
+
return error ?? '❌ Could not read file.';
|
|
205
|
+
}
|
|
206
|
+
const resolvedName = path.basename(filePath);
|
|
207
|
+
logger.info(`explain_file: Read ${code.length} chars from ${resolvedName}`);
|
|
208
|
+
const runner = router.routeTask('explain what does this code do');
|
|
209
|
+
if (!runner) {
|
|
210
|
+
return JSON.stringify({ error: 'No explainer runner available. Check config.yaml' });
|
|
211
|
+
}
|
|
212
|
+
const taskPrompt = `Explain the file **\`${resolvedName}\`** for a ${audience}.\n\n` +
|
|
213
|
+
'Format your response strictly using the `# 📖 Code Explanation:` template.\n\n' +
|
|
214
|
+
`\`\`\`\n${code}\n\`\`\``;
|
|
215
|
+
const result = await runner.execute(taskPrompt);
|
|
216
|
+
if (result.success) {
|
|
217
|
+
return result.output;
|
|
218
|
+
}
|
|
219
|
+
return `Code explanation failed: ${result.error_message}`;
|
|
220
|
+
}
|
|
221
|
+
/** List all registered runners and metadata. */
|
|
222
|
+
export function listRunners(registry) {
|
|
223
|
+
const metadata = registry.getRunnersMetadata();
|
|
224
|
+
return JSON.stringify(metadata, null, 2);
|
|
225
|
+
}
|
|
226
|
+
/** Delegate a task to an external runner or auto-route. */
|
|
227
|
+
export async function delegateTask(router, task, runnerId = 'auto', params) {
|
|
228
|
+
const runner = router.routeTask(task, runnerId);
|
|
229
|
+
if (!runner) {
|
|
230
|
+
const available = router.registry.registeredIds();
|
|
231
|
+
const errRes = makeRunnerResult({
|
|
232
|
+
runner_id: runnerId,
|
|
233
|
+
model: 'unknown',
|
|
234
|
+
task,
|
|
235
|
+
latency_ms: 0,
|
|
236
|
+
input_tokens: 0,
|
|
237
|
+
output_tokens: 0,
|
|
238
|
+
estimated_cost_usd: 0,
|
|
239
|
+
success: false,
|
|
240
|
+
error_message: `Runner '${runnerId}' is not registered. Available runners: [${available.map((id) => `'${id}'`).join(', ')}]. ` +
|
|
241
|
+
'Use list_runners() to see all registered runners.',
|
|
242
|
+
});
|
|
243
|
+
return runnerResultToJson(errRes);
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const result = await runner.execute(task, params);
|
|
247
|
+
return runnerResultToJson(result);
|
|
248
|
+
}
|
|
249
|
+
catch (err) {
|
|
250
|
+
logger.error(`Unhandled error executing runner ${runner.id}:`, err);
|
|
251
|
+
const errRes = makeRunnerResult({
|
|
252
|
+
runner_id: runner.id,
|
|
253
|
+
model: runner.model,
|
|
254
|
+
task,
|
|
255
|
+
latency_ms: 0,
|
|
256
|
+
input_tokens: 0,
|
|
257
|
+
output_tokens: 0,
|
|
258
|
+
estimated_cost_usd: 0,
|
|
259
|
+
success: false,
|
|
260
|
+
error_message: `Server execution error: ${describeError(err)}`,
|
|
261
|
+
});
|
|
262
|
+
return runnerResultToJson(errRes);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/** Fan out a task across multiple runners concurrently and produce a benchmark report. */
|
|
266
|
+
export async function benchmarkRun(registry, engine, options) {
|
|
267
|
+
let targetRunnerIds = options.runner_ids;
|
|
268
|
+
if (!targetRunnerIds || targetRunnerIds.length === 0) {
|
|
269
|
+
const metadata = registry.getRunnersMetadata();
|
|
270
|
+
targetRunnerIds = metadata.filter((r) => r.is_authenticated).map((r) => r.runner_id);
|
|
271
|
+
if (targetRunnerIds.length === 0) {
|
|
272
|
+
targetRunnerIds = registry.registeredIds();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const runOptions = {
|
|
276
|
+
task: options.task,
|
|
277
|
+
runnerIds: targetRunnerIds,
|
|
278
|
+
params: options.params,
|
|
279
|
+
evalCriteria: options.eval_criteria,
|
|
280
|
+
referenceAnswer: options.reference_answer,
|
|
281
|
+
judgeRunnerId: options.judge_runner_id,
|
|
282
|
+
};
|
|
283
|
+
const benchmarkResult = await engine.runBenchmark(runOptions);
|
|
284
|
+
return benchmarkResultToJson(benchmarkResult);
|
|
285
|
+
}
|
|
286
|
+
// =========================================================================
|
|
287
|
+
// PLUGIN LIFECYCLE HANDLERS (MCPHub / HTTP plugin)
|
|
288
|
+
// =========================================================================
|
|
289
|
+
export function pluginConfigure(_args) {
|
|
290
|
+
return { status: 'configured' };
|
|
291
|
+
}
|
|
292
|
+
export function pluginStatus(registry) {
|
|
293
|
+
try {
|
|
294
|
+
return {
|
|
295
|
+
configured: true,
|
|
296
|
+
runners_available: registry.registeredIds().length,
|
|
297
|
+
status: 'healthy',
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
return {
|
|
302
|
+
configured: false,
|
|
303
|
+
error: describeError(err),
|
|
304
|
+
status: 'unhealthy',
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
export function pluginRemove() {
|
|
309
|
+
return { status: 'removed' };
|
|
310
|
+
}
|
|
311
|
+
export function pluginHealthCheck(registry) {
|
|
312
|
+
try {
|
|
313
|
+
return {
|
|
314
|
+
status: 'healthy',
|
|
315
|
+
details: {
|
|
316
|
+
service: 'smartrelay-http',
|
|
317
|
+
runners_loaded: registry.registeredIds().length,
|
|
318
|
+
},
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
catch (err) {
|
|
322
|
+
return {
|
|
323
|
+
status: 'unhealthy',
|
|
324
|
+
error: describeError(err),
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
export function pluginGetLogs(args) {
|
|
329
|
+
return { logs: [], limit: args?.['limit'] ?? 50 };
|
|
330
|
+
}
|
|
331
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/tools/handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './handlers.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC"}
|
package/dist/util.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Shared helpers: rounding, path resolution, .env loading, and concurrency limiting. */
|
|
2
|
+
/**
|
|
3
|
+
* Round to a fixed number of decimal places.
|
|
4
|
+
*
|
|
5
|
+
* Python's `round()` uses banker's rounding while this rounds half away from
|
|
6
|
+
* zero. The difference only shows up on exact .5 ties, which never occur for
|
|
7
|
+
* the latency and cost values this is used on.
|
|
8
|
+
*/
|
|
9
|
+
export declare function round(value: number, digits?: number): number;
|
|
10
|
+
/** Strip every leading and trailing occurrence of `char`, matching Python's `str.strip(char)`. */
|
|
11
|
+
export declare function stripChar(value: string, char: string): string;
|
|
12
|
+
/** Expand a leading `~` to the user's home directory (Node's path.resolve does not). */
|
|
13
|
+
export declare function expandUser(filePath: string): string;
|
|
14
|
+
/** Equivalent of Python's `Path(p).expanduser().resolve()`. */
|
|
15
|
+
export declare function resolveUserPath(filePath: string): string;
|
|
16
|
+
/**
|
|
17
|
+
* Walk upward from `startDir` looking for a directory that holds a project
|
|
18
|
+
* marker. Replaces the Python code's reliance on a fixed `__file__` offset,
|
|
19
|
+
* which would break once TypeScript compiles `src/` into `dist/`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function findProjectRoot(startDir?: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* Load variables from the first `.env` found in the current directory or the
|
|
24
|
+
* project root. Existing environment variables always win.
|
|
25
|
+
*
|
|
26
|
+
* Deliberately hand-rolled rather than delegating to a dotenv package so the
|
|
27
|
+
* quote-stripping and precedence behavior stays identical to the Python original.
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadDotEnv(): void;
|
|
30
|
+
/** Counting semaphore, replacing `asyncio.Semaphore`. */
|
|
31
|
+
export declare class Semaphore {
|
|
32
|
+
private available;
|
|
33
|
+
private readonly waiting;
|
|
34
|
+
constructor(permits: number);
|
|
35
|
+
private acquire;
|
|
36
|
+
private release;
|
|
37
|
+
/** Run `fn` while holding a permit. */
|
|
38
|
+
run<T>(fn: () => Promise<T>): Promise<T>;
|
|
39
|
+
}
|
|
40
|
+
/** Start a monotonic timer; the returned function yields elapsed milliseconds. */
|
|
41
|
+
export declare function startTimer(): () => number;
|
|
42
|
+
/** Format an unknown thrown value the way Python renders `type(e).__name__: e`. */
|
|
43
|
+
export declare function describeError(error: unknown): string;
|
|
44
|
+
/** Truncate by code point (not UTF-16 unit) so multi-byte characters are never split. */
|
|
45
|
+
export declare function truncateByCodePoint(value: string, limit: number): string;
|
|
46
|
+
/** Just the message of a thrown value, matching Python's `str(e)`. */
|
|
47
|
+
export declare function errorMessage(error: unknown): string;
|
package/dist/util.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/** Shared helpers: rounding, path resolution, .env loading, and concurrency limiting. */
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
/**
|
|
6
|
+
* Round to a fixed number of decimal places.
|
|
7
|
+
*
|
|
8
|
+
* Python's `round()` uses banker's rounding while this rounds half away from
|
|
9
|
+
* zero. The difference only shows up on exact .5 ties, which never occur for
|
|
10
|
+
* the latency and cost values this is used on.
|
|
11
|
+
*/
|
|
12
|
+
export function round(value, digits = 0) {
|
|
13
|
+
const factor = 10 ** digits;
|
|
14
|
+
return Math.round(value * factor) / factor;
|
|
15
|
+
}
|
|
16
|
+
/** Strip every leading and trailing occurrence of `char`, matching Python's `str.strip(char)`. */
|
|
17
|
+
export function stripChar(value, char) {
|
|
18
|
+
let start = 0;
|
|
19
|
+
let end = value.length;
|
|
20
|
+
while (start < end && value[start] === char)
|
|
21
|
+
start++;
|
|
22
|
+
while (end > start && value[end - 1] === char)
|
|
23
|
+
end--;
|
|
24
|
+
return value.slice(start, end);
|
|
25
|
+
}
|
|
26
|
+
/** Expand a leading `~` to the user's home directory (Node's path.resolve does not). */
|
|
27
|
+
export function expandUser(filePath) {
|
|
28
|
+
if (filePath === '~')
|
|
29
|
+
return homedir();
|
|
30
|
+
if (filePath.startsWith('~/') || filePath.startsWith('~\\')) {
|
|
31
|
+
return path.join(homedir(), filePath.slice(2));
|
|
32
|
+
}
|
|
33
|
+
return filePath;
|
|
34
|
+
}
|
|
35
|
+
/** Equivalent of Python's `Path(p).expanduser().resolve()`. */
|
|
36
|
+
export function resolveUserPath(filePath) {
|
|
37
|
+
return path.resolve(expandUser(filePath));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Walk upward from `startDir` looking for a directory that holds a project
|
|
41
|
+
* marker. Replaces the Python code's reliance on a fixed `__file__` offset,
|
|
42
|
+
* which would break once TypeScript compiles `src/` into `dist/`.
|
|
43
|
+
*/
|
|
44
|
+
export function findProjectRoot(startDir = import.meta.dirname) {
|
|
45
|
+
let current = path.resolve(startDir);
|
|
46
|
+
while (true) {
|
|
47
|
+
if (existsSync(path.join(current, 'config.yaml')) || existsSync(path.join(current, 'package.json'))) {
|
|
48
|
+
return current;
|
|
49
|
+
}
|
|
50
|
+
const parent = path.dirname(current);
|
|
51
|
+
if (parent === current)
|
|
52
|
+
return path.resolve(startDir);
|
|
53
|
+
current = parent;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Load variables from the first `.env` found in the current directory or the
|
|
58
|
+
* project root. Existing environment variables always win.
|
|
59
|
+
*
|
|
60
|
+
* Deliberately hand-rolled rather than delegating to a dotenv package so the
|
|
61
|
+
* quote-stripping and precedence behavior stays identical to the Python original.
|
|
62
|
+
*/
|
|
63
|
+
export function loadDotEnv() {
|
|
64
|
+
const candidates = [path.join(process.cwd(), '.env'), path.join(findProjectRoot(), '.env')];
|
|
65
|
+
for (const envFile of candidates) {
|
|
66
|
+
if (!existsSync(envFile))
|
|
67
|
+
continue;
|
|
68
|
+
try {
|
|
69
|
+
for (const rawLine of readFileSync(envFile, 'utf-8').split(/\r?\n/)) {
|
|
70
|
+
const line = rawLine.trim();
|
|
71
|
+
if (!line || line.startsWith('#') || !line.includes('='))
|
|
72
|
+
continue;
|
|
73
|
+
const splitAt = line.indexOf('=');
|
|
74
|
+
const key = line.slice(0, splitAt).trim();
|
|
75
|
+
const value = stripChar(stripChar(line.slice(splitAt + 1).trim(), "'"), '"');
|
|
76
|
+
if (key && !(key in process.env))
|
|
77
|
+
process.env[key] = value;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Matches the Python original: a malformed .env is ignored, not fatal.
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Counting semaphore, replacing `asyncio.Semaphore`. */
|
|
87
|
+
export class Semaphore {
|
|
88
|
+
available;
|
|
89
|
+
waiting = [];
|
|
90
|
+
constructor(permits) {
|
|
91
|
+
// Guard against a misconfigured `max_concurrency: 0`, which would otherwise
|
|
92
|
+
// deadlock the benchmark fan-out exactly as it does in the Python version.
|
|
93
|
+
this.available = Math.max(1, Math.floor(permits));
|
|
94
|
+
}
|
|
95
|
+
async acquire() {
|
|
96
|
+
if (this.available > 0) {
|
|
97
|
+
this.available--;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
await new Promise((resolve) => this.waiting.push(resolve));
|
|
101
|
+
}
|
|
102
|
+
release() {
|
|
103
|
+
const next = this.waiting.shift();
|
|
104
|
+
if (next)
|
|
105
|
+
next();
|
|
106
|
+
else
|
|
107
|
+
this.available++;
|
|
108
|
+
}
|
|
109
|
+
/** Run `fn` while holding a permit. */
|
|
110
|
+
async run(fn) {
|
|
111
|
+
await this.acquire();
|
|
112
|
+
try {
|
|
113
|
+
return await fn();
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
this.release();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/** Start a monotonic timer; the returned function yields elapsed milliseconds. */
|
|
121
|
+
export function startTimer() {
|
|
122
|
+
const started = performance.now();
|
|
123
|
+
return () => round(performance.now() - started, 2);
|
|
124
|
+
}
|
|
125
|
+
/** Format an unknown thrown value the way Python renders `type(e).__name__: e`. */
|
|
126
|
+
export function describeError(error) {
|
|
127
|
+
if (error instanceof Error)
|
|
128
|
+
return `${error.constructor.name}: ${error.message}`;
|
|
129
|
+
return `Error: ${String(error)}`;
|
|
130
|
+
}
|
|
131
|
+
/** Truncate by code point (not UTF-16 unit) so multi-byte characters are never split. */
|
|
132
|
+
export function truncateByCodePoint(value, limit) {
|
|
133
|
+
const points = Array.from(value);
|
|
134
|
+
return points.length > limit ? `${points.slice(0, limit).join('')}...` : value;
|
|
135
|
+
}
|
|
136
|
+
/** Just the message of a thrown value, matching Python's `str(e)`. */
|
|
137
|
+
export function errorMessage(error) {
|
|
138
|
+
return error instanceof Error ? error.message : String(error);
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@theone1345/smartrelay",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "MCP server for delegating tasks across LLM backends and benchmarking their outputs",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"author": "Dhavan Bhalodiya",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/DhavanBhalodiya/smart-relay.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/DhavanBhalodiya/smart-relay/issues"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/DhavanBhalodiya/smart-relay#readme",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"mcp",
|
|
20
|
+
"model-context-protocol",
|
|
21
|
+
"claude",
|
|
22
|
+
"cursor",
|
|
23
|
+
"windsurf",
|
|
24
|
+
"subagents",
|
|
25
|
+
"openrouter",
|
|
26
|
+
"nvidia",
|
|
27
|
+
"ollama"
|
|
28
|
+
],
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=20"
|
|
31
|
+
},
|
|
32
|
+
"bin": {
|
|
33
|
+
"smartrelay": "dist/server.js",
|
|
34
|
+
"mcp-delegation-server": "dist/server.js",
|
|
35
|
+
"smartrelay-http": "dist/http-api.js"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist",
|
|
39
|
+
"config",
|
|
40
|
+
"config.yaml",
|
|
41
|
+
"prompts"
|
|
42
|
+
],
|
|
43
|
+
"scripts": {
|
|
44
|
+
"prepublishOnly": "npm run build && npm test",
|
|
45
|
+
"build": "tsc",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"dev": "tsx src/server.ts",
|
|
48
|
+
"dev:http": "tsx src/http-api.ts",
|
|
49
|
+
"start": "node dist/server.js",
|
|
50
|
+
"start:http": "node dist/http-api.js",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:watch": "vitest",
|
|
53
|
+
"quick-test": "tsx scripts/quick-test.ts",
|
|
54
|
+
"test:plugin": "tsx scripts/test-plugin.ts"
|
|
55
|
+
},
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@anthropic-ai/sdk": "^0.124.0",
|
|
58
|
+
"@modelcontextprotocol/server": "^2.0.0",
|
|
59
|
+
"fastify": "^5.12.3",
|
|
60
|
+
"openai": "^7.12.1",
|
|
61
|
+
"yaml": "^2.9.0",
|
|
62
|
+
"zod": "^4.5.4"
|
|
63
|
+
},
|
|
64
|
+
"devDependencies": {
|
|
65
|
+
"@types/node": "^26.5.0",
|
|
66
|
+
"tsx": "^4.23.13",
|
|
67
|
+
"typescript": "^7.0.2",
|
|
68
|
+
"vitest": "^5.0.0"
|
|
69
|
+
}
|
|
70
|
+
}
|