@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.
Files changed (64) hide show
  1. package/README.md +446 -0
  2. package/config/runners/agents.yaml +47 -0
  3. package/config/runners/anthropic.yaml +23 -0
  4. package/config/runners/nvidia.yaml +53 -0
  5. package/config/runners/ollama.yaml +33 -0
  6. package/config/runners/openai.yaml +23 -0
  7. package/config/runners/openrouter.yaml +83 -0
  8. package/config.yaml +16 -0
  9. package/dist/benchmark/engine.d.ts +49 -0
  10. package/dist/benchmark/engine.js +147 -0
  11. package/dist/benchmark/engine.js.map +1 -0
  12. package/dist/benchmark/scorers.d.ts +59 -0
  13. package/dist/benchmark/scorers.js +241 -0
  14. package/dist/benchmark/scorers.js.map +1 -0
  15. package/dist/http-api.d.ts +23 -0
  16. package/dist/http-api.js +329 -0
  17. package/dist/http-api.js.map +1 -0
  18. package/dist/index.d.ts +16 -0
  19. package/dist/index.js +17 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/logger.d.ts +22 -0
  22. package/dist/logger.js +34 -0
  23. package/dist/logger.js.map +1 -0
  24. package/dist/router.d.ts +33 -0
  25. package/dist/router.js +298 -0
  26. package/dist/router.js.map +1 -0
  27. package/dist/runners/anthropic.d.ts +15 -0
  28. package/dist/runners/anthropic.js +116 -0
  29. package/dist/runners/anthropic.js.map +1 -0
  30. package/dist/runners/base.d.ts +90 -0
  31. package/dist/runners/base.js +61 -0
  32. package/dist/runners/base.js.map +1 -0
  33. package/dist/runners/nvidia.d.ts +14 -0
  34. package/dist/runners/nvidia.js +23 -0
  35. package/dist/runners/nvidia.js.map +1 -0
  36. package/dist/runners/ollama.d.ts +8 -0
  37. package/dist/runners/ollama.js +107 -0
  38. package/dist/runners/ollama.js.map +1 -0
  39. package/dist/runners/openai.d.ts +28 -0
  40. package/dist/runners/openai.js +131 -0
  41. package/dist/runners/openai.js.map +1 -0
  42. package/dist/runners/openrouter.d.ts +11 -0
  43. package/dist/runners/openrouter.js +19 -0
  44. package/dist/runners/openrouter.js.map +1 -0
  45. package/dist/runners/registry.d.ts +53 -0
  46. package/dist/runners/registry.js +273 -0
  47. package/dist/runners/registry.js.map +1 -0
  48. package/dist/server.d.ts +16 -0
  49. package/dist/server.js +305 -0
  50. package/dist/server.js.map +1 -0
  51. package/dist/tools/handlers.d.ts +49 -0
  52. package/dist/tools/handlers.js +331 -0
  53. package/dist/tools/handlers.js.map +1 -0
  54. package/dist/tools/index.d.ts +1 -0
  55. package/dist/tools/index.js +2 -0
  56. package/dist/tools/index.js.map +1 -0
  57. package/dist/util.d.ts +47 -0
  58. package/dist/util.js +140 -0
  59. package/dist/util.js.map +1 -0
  60. package/package.json +70 -0
  61. package/prompts/code_review.md +99 -0
  62. package/prompts/explain_code.md +79 -0
  63. package/prompts/planner.md +23 -0
  64. package/prompts/test_generator.md +2 -0
package/dist/router.js ADDED
@@ -0,0 +1,298 @@
1
+ /** Intelligent router that selects a runner from task intent, explicit IDs, or provider shortcuts. */
2
+ /** Provider shortcut groups, tried in order until a configured runner is found. */
3
+ const PROVIDER_SHORTCUTS = [
4
+ // 1. Providers
5
+ {
6
+ match: ['openrouter', 'or'],
7
+ candidates: [
8
+ 'openrouter-claude-3.7-sonnet',
9
+ 'openrouter-deepseek-r1',
10
+ 'openrouter-deepseek-v3',
11
+ 'openrouter-qwen-2.5-coder',
12
+ 'openrouter-claude-sonnet-4.5',
13
+ ],
14
+ },
15
+ {
16
+ match: ['nvidia', 'nemotron'],
17
+ candidates: [
18
+ 'nemotron-3-super-120b-a12b',
19
+ 'nvidia-llama-3.3-70b',
20
+ 'nvidia-llama-70b',
21
+ 'nvidia-qwen-coder',
22
+ 'nvidia-deepseek-r1',
23
+ ],
24
+ },
25
+ {
26
+ match: ['ollama', 'local'],
27
+ candidates: ['ollama-qwen-coder', 'ollama-llama3.2', 'ollama-deepseek-r1'],
28
+ },
29
+ {
30
+ match: ['openai'],
31
+ candidates: ['gpt-4o', 'gpt-4o-mini', 'test-generator-agent'],
32
+ },
33
+ // 2. Model Families (Natural & Explicit)
34
+ {
35
+ match: ['deepseek', 'r1'],
36
+ candidates: [
37
+ 'openrouter-deepseek-r1',
38
+ 'nvidia-deepseek-r1',
39
+ 'openrouter-deepseek-v3',
40
+ 'ollama-deepseek-r1',
41
+ ],
42
+ },
43
+ {
44
+ match: ['v3', 'deepseek-v3'],
45
+ candidates: ['openrouter-deepseek-v3'],
46
+ },
47
+ {
48
+ match: ['claude', 'sonnet'],
49
+ candidates: [
50
+ 'openrouter-claude-sonnet-4.5',
51
+ 'openrouter-claude-3.7-sonnet',
52
+ 'code-review-agent',
53
+ 'claude-3-7-sonnet',
54
+ ],
55
+ },
56
+ {
57
+ match: ['qwen'],
58
+ candidates: [
59
+ 'openrouter-qwen-2.5-coder',
60
+ 'nvidia-qwen-coder',
61
+ 'ollama-qwen-coder',
62
+ 'openrouter-qwen-coder-free',
63
+ ],
64
+ },
65
+ {
66
+ match: ['llama'],
67
+ candidates: [
68
+ 'openrouter-llama-3.3-70b',
69
+ 'nvidia-llama-3.3-70b',
70
+ 'ollama-llama3.2',
71
+ ],
72
+ },
73
+ {
74
+ match: ['gemini'],
75
+ candidates: ['openrouter-gemini-2.0-flash'],
76
+ },
77
+ {
78
+ match: ['gpt'],
79
+ candidates: ['gpt-4o', 'gpt-4o-mini', 'planner-agent'],
80
+ },
81
+ ];
82
+ /** Role shortcuts mapping a keyword to a single specialized agent. */
83
+ const ROLE_SHORTCUTS = [
84
+ ['plan', 'planner-agent'],
85
+ ['review', 'code-review-agent'],
86
+ ['test', 'test-generator-agent'],
87
+ ['explain', 'explain-agent'],
88
+ ];
89
+ /** Preferred defaults, in priority order, when no `default_runner` is configured. */
90
+ const PREFERRED_DEFAULTS = [
91
+ 'nemotron-3-super-120b-a12b',
92
+ 'openrouter-claude-sonnet-4.5',
93
+ 'code-review-agent',
94
+ 'claude-3-7-sonnet',
95
+ 'gpt-4o',
96
+ 'gpt-4o-mini',
97
+ 'ollama-qwen-coder',
98
+ ];
99
+ const PLAN_KEYWORDS = [
100
+ 'plan', 'roadmap', 'architecture', 'break down', 'design plan',
101
+ 'implementation plan', 'strategy', 'phases', 'step-by-step plan',
102
+ ];
103
+ const REVIEW_KEYWORDS = [
104
+ 'review', 'audit', 'critique', 'vulnerability', 'security',
105
+ 'edge case', 'smell', 'refactor', 'race condition', 'memory leak',
106
+ 'optimize', 'performance issue', 'bug in', 'check this code',
107
+ ];
108
+ const EXPLAIN_KEYWORDS = [
109
+ 'explain', 'what does this do', 'how does this work',
110
+ 'walk me through', 'help me understand', 'document this',
111
+ 'what is this', 'describe this', 'break down', 'annotate',
112
+ 'summarize this code', 'help me read', 'what does it do',
113
+ ];
114
+ const TEST_KEYWORDS = [
115
+ 'generate test', 'unit test', 'widget test', 'integration test',
116
+ 'pytest', 'mock', 'assert', 'coverage', 'test case', 'tdd',
117
+ 'write test', 'add test',
118
+ ];
119
+ /** Routes tasks to the most suitable runner automatically, via shortcuts, or by explicit ID. */
120
+ export class TaskRouter {
121
+ registry;
122
+ activeRunnerId = null;
123
+ constructor(registry) {
124
+ this.registry = registry;
125
+ }
126
+ /** Formats a clean interactive menu of available shortcuts and runners. */
127
+ formatMenu() {
128
+ const activeText = this.activeRunnerId
129
+ ? `Pinned to \`${this.activeRunnerId}\``
130
+ : '🟢 Auto-Routing (routes dynamically based on task intent)';
131
+ const lines = [
132
+ '⚡ **SmartRelay Model Fleet**',
133
+ '',
134
+ `**Current Mode**: ${activeText}`,
135
+ '',
136
+ '### ⚡ Natural Language Shortcuts',
137
+ '| What to say | Target Model & Provider | Purpose |',
138
+ '| :--- | :--- | :--- |',
139
+ '| **`Switch to openrouter`** | Claude 3.7 Sonnet (OpenRouter) | Flagship Cloud Reasoning & Code |',
140
+ '| **`Switch to deepseek`** | DeepSeek-R1 671B (OpenRouter / NVIDIA) | Deep Reasoning with CoT |',
141
+ '| **`Switch to v3`** | DeepSeek-V3 671B (OpenRouter) | High-Speed Code & Chat |',
142
+ '| **`Switch to qwen`** | Qwen 2.5 Coder 32B (OpenRouter / NVIDIA) | Code Specialist |',
143
+ '| **`Switch to llama`** | Llama 3.3 70B (OpenRouter / NVIDIA) | System Architecture & Planning |',
144
+ '| **`Switch to gemini`** | Gemini 2.0 Flash (OpenRouter) | Ultra-Fast & 1M Token Context |',
145
+ '| **`Switch to nvidia`** | Nemotron 3 Super 120B (NVIDIA NIM) | Heavyweight Cloud Agent |',
146
+ '| **`Switch to claude`** | Claude Sonnet 4.5 / 3.7 | Elite Code & Review |',
147
+ '| **`Switch to ollama`** | Qwen 2.5 Coder (Local Ollama) | Free $0.00 Offline Runner |',
148
+ '| **`Switch to auto`** | Smart Intent Routing (default) | Automatic Agent Routing |',
149
+ '| **`Switch to direct`** | Native Claude Intelligence | Bypass Sub-Agents |',
150
+ '',
151
+ "💡 *Tip: Say 'Switch to deepseek', 'Switch to qwen', or 'Switch to openrouter' anytime.*",
152
+ ];
153
+ return lines.join('\n');
154
+ }
155
+ /** Resolve a shortcut or provider name (e.g. 'nvidia', 'ollama', 'claude') to a runner. */
156
+ resolveShortcut(target) {
157
+ const targetClean = target.trim().toLowerCase();
158
+ // 1. Exact match in the registry (which itself handles aliases).
159
+ const exact = this.registry.get(target);
160
+ if (exact)
161
+ return exact;
162
+ // 2. Provider and model shortcuts.
163
+ for (const { match, candidates } of PROVIDER_SHORTCUTS) {
164
+ if (!match.some((keyword) => targetClean.includes(keyword)))
165
+ continue;
166
+ for (const candidate of candidates) {
167
+ const runner = this.registry.get(candidate);
168
+ if (runner)
169
+ return runner;
170
+ }
171
+ }
172
+ // 3. Role shortcuts.
173
+ for (const [keyword, runnerId] of ROLE_SHORTCUTS) {
174
+ if (targetClean.includes(keyword)) {
175
+ const runner = this.registry.get(runnerId);
176
+ if (runner)
177
+ return runner;
178
+ }
179
+ }
180
+ return null;
181
+ }
182
+ /** Switch the active runner. Accepts an exact ID, a provider name, 'auto', or 'direct'. */
183
+ setActiveRunner(target) {
184
+ const targetClean = target.trim().toLowerCase();
185
+ if (['list', 'help', '?', 'status', 'models', 'menu', ''].includes(targetClean)) {
186
+ return {
187
+ ok: true,
188
+ message: this.formatMenu(),
189
+ };
190
+ }
191
+ if (['auto', 'default', 'reset'].includes(targetClean)) {
192
+ this.activeRunnerId = null;
193
+ return {
194
+ ok: true,
195
+ message: "Switched to 'auto' mode. TaskRouter will automatically pick the best agent for each task.",
196
+ };
197
+ }
198
+ if (['direct', 'claude-direct', 'native'].includes(targetClean)) {
199
+ this.activeRunnerId = 'direct';
200
+ return { ok: true, message: "Switched to 'direct' mode. Claude Code will handle tasks natively." };
201
+ }
202
+ const runner = this.resolveShortcut(target);
203
+ if (runner) {
204
+ this.activeRunnerId = runner.id;
205
+ return { ok: true, message: `Active model switched to: '${runner.id}' (${runner.model})` };
206
+ }
207
+ return {
208
+ ok: false,
209
+ message: `Could not find runner matching '${target}'.\n\n` +
210
+ `💡 Quick shortcuts: 'openrouter', 'deepseek', 'qwen', 'llama', 'gemini', 'nvidia', 'claude', 'ollama', 'auto'.\n` +
211
+ `Available runners: ${this.formatAvailable()}`,
212
+ };
213
+ }
214
+ /** Information about the currently active runner and mode. */
215
+ getActiveRunnerInfo() {
216
+ if (this.activeRunnerId === null) {
217
+ const fallback = this.getDefaultRunner();
218
+ return {
219
+ mode: 'auto',
220
+ active_runner_id: fallback ? fallback.id : null,
221
+ model: fallback ? fallback.model : null,
222
+ description: 'Auto-routing active based on task keywords',
223
+ };
224
+ }
225
+ const runner = this.registry.get(this.activeRunnerId);
226
+ return {
227
+ mode: 'pinned',
228
+ active_runner_id: this.activeRunnerId,
229
+ model: runner ? runner.model : 'unknown',
230
+ description: `Pinned to ${this.activeRunnerId}`,
231
+ };
232
+ }
233
+ /** The configured default runner, the first available preferred runner, or any runner. */
234
+ getDefaultRunner() {
235
+ const configuredId = this.registry.serverConfig['default_runner'];
236
+ if (typeof configuredId === 'string' && configuredId) {
237
+ const runner = this.registry.get(configuredId);
238
+ if (runner)
239
+ return runner;
240
+ }
241
+ for (const preferredId of PREFERRED_DEFAULTS) {
242
+ const runner = this.registry.get(preferredId);
243
+ if (runner)
244
+ return runner;
245
+ }
246
+ const first = this.registry.listRunners().values().next();
247
+ return first.done ? null : first.value;
248
+ }
249
+ /** Pick the best runner for a task: explicit ID, pinned runner, then intent classification. */
250
+ routeTask(task, explicitRunnerId) {
251
+ // 1. Explicit runner ID or shortcut supplied with the request.
252
+ if (explicitRunnerId && !['default', 'auto', ''].includes(explicitRunnerId)) {
253
+ const runner = this.resolveShortcut(explicitRunnerId);
254
+ if (runner)
255
+ return runner;
256
+ return this.registry.get(explicitRunnerId);
257
+ }
258
+ // 2. Pinned active runner.
259
+ if (this.activeRunnerId && !['auto', 'direct'].includes(this.activeRunnerId)) {
260
+ const pinned = this.registry.get(this.activeRunnerId);
261
+ if (pinned)
262
+ return pinned;
263
+ }
264
+ const taskLower = task.toLowerCase();
265
+ const matches = (keywords) => keywords.some((keyword) => taskLower.includes(keyword));
266
+ // 3. Planning / architecture intent.
267
+ if (matches(PLAN_KEYWORDS)) {
268
+ const runner = this.registry.get('planner-agent');
269
+ if (runner)
270
+ return runner;
271
+ }
272
+ // 4. Code review intent.
273
+ if (matches(REVIEW_KEYWORDS)) {
274
+ const runner = this.registry.get('code-review-agent');
275
+ if (runner)
276
+ return runner;
277
+ }
278
+ // 5. Explanation / documentation intent.
279
+ if (matches(EXPLAIN_KEYWORDS)) {
280
+ const runner = this.registry.get('explain-agent');
281
+ if (runner)
282
+ return runner;
283
+ }
284
+ // 6. Test generation intent.
285
+ if (matches(TEST_KEYWORDS)) {
286
+ const runner = this.registry.get('test-generator-agent') ?? this.registry.get('gpt-4o');
287
+ if (runner)
288
+ return runner;
289
+ }
290
+ // 7. Default primary runner.
291
+ return this.getDefaultRunner();
292
+ }
293
+ /** Render the registered ID list the way Python's list repr did, for error messages. */
294
+ formatAvailable() {
295
+ return `[${this.registry.registeredIds().map((id) => `'${id}'`).join(', ')}]`;
296
+ }
297
+ }
298
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /** Anthropic API runner implementation. */
2
+ import { BaseRunner, type RunnerConfig, type RunnerResult } from './base.js';
3
+ /** Runner adapter for Anthropic Claude models via the official SDK. */
4
+ export declare class AnthropicRunner extends BaseRunner {
5
+ private client;
6
+ private clientKey;
7
+ constructor(config: RunnerConfig);
8
+ private get envVarName();
9
+ /** Resolve the API key strictly from environment variables. */
10
+ private getApiKey;
11
+ private getClient;
12
+ execute(task: string, params?: Record<string, unknown> | null): Promise<RunnerResult>;
13
+ /** Map SDK exceptions onto the same messages the Python implementation produced. */
14
+ private describeFailure;
15
+ }
@@ -0,0 +1,116 @@
1
+ /** Anthropic API runner implementation. */
2
+ import Anthropic, { APIConnectionTimeoutError, APIError, APIUserAbortError, AuthenticationError, RateLimitError, } from '@anthropic-ai/sdk';
3
+ import { BaseRunner, makeRunnerResult, resolveParams } from './base.js';
4
+ import { describeError, startTimer } from '../util.js';
5
+ /** Runner adapter for Anthropic Claude models via the official SDK. */
6
+ export class AnthropicRunner extends BaseRunner {
7
+ client = null;
8
+ clientKey = null;
9
+ constructor(config) {
10
+ super(config);
11
+ }
12
+ get envVarName() {
13
+ return this.config.api_key_env || 'ANTHROPIC_API_KEY';
14
+ }
15
+ /** Resolve the API key strictly from environment variables. */
16
+ getApiKey() {
17
+ return process.env[this.envVarName] || undefined;
18
+ }
19
+ getClient(apiKey) {
20
+ if (this.client === null || this.clientKey !== apiKey) {
21
+ this.client = new Anthropic({
22
+ apiKey,
23
+ ...(this.config.base_url ? { baseURL: this.config.base_url } : {}),
24
+ });
25
+ this.clientKey = apiKey;
26
+ }
27
+ return this.client;
28
+ }
29
+ async execute(task, params) {
30
+ const elapsed = startTimer();
31
+ const { maxTokens, temperature, systemPrompt, timeoutSeconds } = resolveParams(this.config, params);
32
+ const apiKey = this.getApiKey();
33
+ if (!apiKey) {
34
+ return makeRunnerResult({
35
+ runner_id: this.id,
36
+ model: this.model,
37
+ task,
38
+ latency_ms: elapsed(),
39
+ success: false,
40
+ error_message: `Authentication error: Environment variable '${this.envVarName}' is not set. ` +
41
+ `Please export ${this.envVarName}=<your-key> to use runner '${this.id}'.`,
42
+ });
43
+ }
44
+ const timeoutMs = timeoutSeconds * 1000;
45
+ try {
46
+ const client = this.getClient(apiKey);
47
+ const response = await client.messages.create({
48
+ model: this.model,
49
+ messages: [{ role: 'user', content: task }],
50
+ max_tokens: maxTokens,
51
+ temperature,
52
+ ...(systemPrompt ? { system: systemPrompt } : {}),
53
+ }, { timeout: timeoutMs, signal: AbortSignal.timeout(timeoutMs) });
54
+ const chunks = [];
55
+ for (const block of response.content) {
56
+ if (block.type === 'text') {
57
+ chunks.push(block.text);
58
+ }
59
+ else if ('text' in block && typeof block.text === 'string') {
60
+ chunks.push(block.text);
61
+ }
62
+ }
63
+ const inputTokens = response.usage?.input_tokens ?? 0;
64
+ const outputTokens = response.usage?.output_tokens ?? 0;
65
+ return makeRunnerResult({
66
+ runner_id: this.id,
67
+ model: this.model,
68
+ task,
69
+ output: chunks.join(''),
70
+ latency_ms: elapsed(),
71
+ input_tokens: inputTokens,
72
+ output_tokens: outputTokens,
73
+ estimated_cost_usd: this.calculateCost(inputTokens, outputTokens),
74
+ success: true,
75
+ error_message: null,
76
+ raw_metadata: {
77
+ stop_reason: response.stop_reason,
78
+ stop_sequence: response.stop_sequence,
79
+ usage: {
80
+ input_tokens: inputTokens,
81
+ output_tokens: outputTokens,
82
+ cache_creation_input_tokens: response.usage?.cache_creation_input_tokens ?? 0,
83
+ cache_read_input_tokens: response.usage?.cache_read_input_tokens ?? 0,
84
+ },
85
+ },
86
+ });
87
+ }
88
+ catch (error) {
89
+ return makeRunnerResult({
90
+ runner_id: this.id,
91
+ model: this.model,
92
+ task,
93
+ latency_ms: elapsed(),
94
+ success: false,
95
+ error_message: this.describeFailure(error, timeoutSeconds),
96
+ });
97
+ }
98
+ }
99
+ /** Map SDK exceptions onto the same messages the Python implementation produced. */
100
+ describeFailure(error, timeoutSeconds) {
101
+ if (error instanceof APIConnectionTimeoutError || error instanceof APIUserAbortError) {
102
+ return `Request timed out after ${timeoutSeconds} seconds.`;
103
+ }
104
+ if (error instanceof AuthenticationError) {
105
+ return `Anthropic authentication failed: ${error.message}`;
106
+ }
107
+ if (error instanceof RateLimitError) {
108
+ return `Anthropic rate limit exceeded: ${error.message}`;
109
+ }
110
+ if (error instanceof APIError) {
111
+ return `Anthropic API error (${error.status}): ${error.message}`;
112
+ }
113
+ return `Unexpected error executing Anthropic runner: ${describeError(error)}`;
114
+ }
115
+ }
116
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../src/runners/anthropic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /** Base classes and data models for LLM runners. */
2
+ /**
3
+ * Configuration for a specific LLM runner.
4
+ *
5
+ * Field names mirror the YAML keys in `config/runners/*.yaml` verbatim so a
6
+ * parsed config block maps straight onto this shape.
7
+ */
8
+ export interface RunnerConfig {
9
+ id: string;
10
+ /** "anthropic", "openai", "ollama", etc. */
11
+ type: string;
12
+ model: string;
13
+ api_key_env: string | null;
14
+ base_url: string | null;
15
+ cost_per_million_input_tokens: number;
16
+ cost_per_million_output_tokens: number;
17
+ default_params: Record<string, unknown>;
18
+ timeout_seconds: number;
19
+ }
20
+ /**
21
+ * Normalized result returned by any runner execution.
22
+ *
23
+ * Keys are snake_case and declared in the same order as the Python dataclass:
24
+ * this object is serialized directly onto the wire, and both the test suite and
25
+ * `plugin-smartrelay` depend on that exact shape.
26
+ */
27
+ export interface RunnerResult {
28
+ runner_id: string;
29
+ model: string;
30
+ task: string;
31
+ output: string;
32
+ latency_ms: number;
33
+ input_tokens: number;
34
+ output_tokens: number;
35
+ estimated_cost_usd: number;
36
+ success: boolean;
37
+ error_message: string | null;
38
+ raw_metadata: Record<string, unknown>;
39
+ timestamp: string;
40
+ }
41
+ export interface RunnerResultInit {
42
+ runner_id: string;
43
+ model: string;
44
+ task: string;
45
+ output?: string;
46
+ latency_ms?: number;
47
+ input_tokens?: number;
48
+ output_tokens?: number;
49
+ estimated_cost_usd?: number;
50
+ success: boolean;
51
+ error_message?: string | null;
52
+ raw_metadata?: Record<string, unknown>;
53
+ timestamp?: string;
54
+ }
55
+ /**
56
+ * Build a `RunnerResult`, filling in the same defaults as the Python dataclass
57
+ * and always emitting keys in declaration order so `JSON.stringify` reproduces
58
+ * the original payload.
59
+ */
60
+ export declare function makeRunnerResult(init: RunnerResultInit): RunnerResult;
61
+ /** Serialize a result the way `RunnerResult.to_json()` did. */
62
+ export declare function runnerResultToJson(result: RunnerResult, indent?: number | null): string;
63
+ /** Inference parameters after merging runner defaults with per-request overrides. */
64
+ export interface ResolvedParams {
65
+ maxTokens: number;
66
+ temperature: number;
67
+ systemPrompt: string | undefined;
68
+ timeoutSeconds: number;
69
+ }
70
+ /**
71
+ * Merge a runner's `default_params` with per-request overrides and pull out the
72
+ * four values every backend needs. Overrides win, matching `dict.update()`.
73
+ */
74
+ export declare function resolveParams(config: RunnerConfig, params?: Record<string, unknown> | null): ResolvedParams;
75
+ /** Abstract base class for all LLM backend runners. */
76
+ export declare abstract class BaseRunner {
77
+ readonly config: RunnerConfig;
78
+ constructor(config: RunnerConfig);
79
+ get id(): string;
80
+ get model(): string;
81
+ /** Estimated cost in USD based on the configured per-million token rates. */
82
+ calculateCost(inputTokens: number, outputTokens: number): number;
83
+ /**
84
+ * Execute a task on the runner backend and return a normalized `RunnerResult`.
85
+ *
86
+ * Must never throw: errors are captured and returned as a result with
87
+ * `success: false` and an `error_message`.
88
+ */
89
+ abstract execute(task: string, params?: Record<string, unknown> | null): Promise<RunnerResult>;
90
+ }
@@ -0,0 +1,61 @@
1
+ /** Base classes and data models for LLM runners. */
2
+ import { round } from '../util.js';
3
+ /**
4
+ * Build a `RunnerResult`, filling in the same defaults as the Python dataclass
5
+ * and always emitting keys in declaration order so `JSON.stringify` reproduces
6
+ * the original payload.
7
+ */
8
+ export function makeRunnerResult(init) {
9
+ return {
10
+ runner_id: init.runner_id,
11
+ model: init.model,
12
+ task: init.task,
13
+ output: init.output ?? '',
14
+ latency_ms: init.latency_ms ?? 0,
15
+ input_tokens: init.input_tokens ?? 0,
16
+ output_tokens: init.output_tokens ?? 0,
17
+ estimated_cost_usd: init.estimated_cost_usd ?? 0,
18
+ success: init.success,
19
+ error_message: init.error_message ?? null,
20
+ raw_metadata: init.raw_metadata ?? {},
21
+ timestamp: init.timestamp ?? new Date().toISOString(),
22
+ };
23
+ }
24
+ /** Serialize a result the way `RunnerResult.to_json()` did. */
25
+ export function runnerResultToJson(result, indent = 2) {
26
+ return JSON.stringify(result, null, indent ?? undefined);
27
+ }
28
+ /**
29
+ * Merge a runner's `default_params` with per-request overrides and pull out the
30
+ * four values every backend needs. Overrides win, matching `dict.update()`.
31
+ */
32
+ export function resolveParams(config, params) {
33
+ const merged = { ...config.default_params, ...(params ?? {}) };
34
+ const systemPrompt = merged['system_prompt'];
35
+ return {
36
+ maxTokens: merged['max_tokens'] ?? 2048,
37
+ temperature: merged['temperature'] ?? 0.7,
38
+ systemPrompt: typeof systemPrompt === 'string' && systemPrompt ? systemPrompt : undefined,
39
+ timeoutSeconds: merged['timeout_seconds'] ?? config.timeout_seconds,
40
+ };
41
+ }
42
+ /** Abstract base class for all LLM backend runners. */
43
+ export class BaseRunner {
44
+ config;
45
+ constructor(config) {
46
+ this.config = config;
47
+ }
48
+ get id() {
49
+ return this.config.id;
50
+ }
51
+ get model() {
52
+ return this.config.model;
53
+ }
54
+ /** Estimated cost in USD based on the configured per-million token rates. */
55
+ calculateCost(inputTokens, outputTokens) {
56
+ const inputCost = (inputTokens / 1_000_000) * this.config.cost_per_million_input_tokens;
57
+ const outputCost = (outputTokens / 1_000_000) * this.config.cost_per_million_output_tokens;
58
+ return round(inputCost + outputCost, 6);
59
+ }
60
+ }
61
+ //# sourceMappingURL=base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base.js","sourceRoot":"","sources":["../../src/runners/base.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAEpD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AA0DnC;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAsB;IACrD,OAAO;QACL,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE;QACzB,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,CAAC;QAChC,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,CAAC;QACpC,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,CAAC;QACtC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,IAAI,CAAC;QAChD,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,aAAa,EAAE,IAAI,CAAC,aAAa,IAAI,IAAI;QACzC,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,EAAE;QACrC,SAAS,EAAE,IAAI,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACtD,CAAC;AACJ,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,kBAAkB,CAAC,MAAoB,EAAE,MAAM,GAAkB,CAAC;IAChF,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,SAAS,CAAC,CAAC;AAC3D,CAAC;AAUD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAoB,EACpB,MAAuC;IAEvC,MAAM,MAAM,GAA4B,EAAE,GAAG,MAAM,CAAC,cAAc,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;IACxF,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;IAE7C,OAAO;QACL,SAAS,EAAG,MAAM,CAAC,YAAY,CAAwB,IAAI,IAAI;QAC/D,WAAW,EAAG,MAAM,CAAC,aAAa,CAAwB,IAAI,GAAG;QACjE,YAAY,EAAE,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS;QACzF,cAAc,EAAG,MAAM,CAAC,iBAAiB,CAAwB,IAAI,MAAM,CAAC,eAAe;KAC5F,CAAC;AACJ,CAAC;AAED,uDAAuD;AACvD,MAAM,OAAgB,UAAU;IACF,MAAM;IAAlC,YAA4B,MAAoB;sBAApB,MAAM;IAAiB,CAAC;IAEpD,IAAI,EAAE;QACJ,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;IACxB,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;IAC3B,CAAC;IAED,6EAA6E;IAC7E,aAAa,CAAC,WAAmB,EAAE,YAAoB;QACrD,MAAM,SAAS,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,6BAA6B,CAAC;QACxF,MAAM,UAAU,GAAG,CAAC,YAAY,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,8BAA8B,CAAC;QAC3F,OAAO,KAAK,CAAC,SAAS,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC;IAC1C,CAAC;CASF"}
@@ -0,0 +1,14 @@
1
+ /** NVIDIA NIM / API Catalog runner implementation. */
2
+ import { OpenAIRunner } from './openai.js';
3
+ import type { RunnerConfig } from './base.js';
4
+ /**
5
+ * Runner adapter for NVIDIA NIM and the NVIDIA API Catalog (build.nvidia.com).
6
+ *
7
+ * Like the Python original this only swaps in NVIDIA's base URL and credential
8
+ * env var; it deliberately inherits OpenAI's error-message wording.
9
+ */
10
+ export declare class NVIDIARunner extends OpenAIRunner {
11
+ static readonly DEFAULT_BASE_URL = "https://integrate.api.nvidia.com/v1";
12
+ constructor(config: RunnerConfig);
13
+ protected readonly defaultEnvVar = "NVIDIA_API_KEY";
14
+ }
@@ -0,0 +1,23 @@
1
+ /** NVIDIA NIM / API Catalog runner implementation. */
2
+ import { OpenAIRunner } from './openai.js';
3
+ /**
4
+ * Runner adapter for NVIDIA NIM and the NVIDIA API Catalog (build.nvidia.com).
5
+ *
6
+ * Like the Python original this only swaps in NVIDIA's base URL and credential
7
+ * env var; it deliberately inherits OpenAI's error-message wording.
8
+ */
9
+ export class NVIDIARunner extends OpenAIRunner {
10
+ static DEFAULT_BASE_URL = 'https://integrate.api.nvidia.com/v1';
11
+ constructor(config) {
12
+ // Backfilled onto the config itself (before `super`, which is legal because
13
+ // it does not touch `this`) so `getRunnersMetadata()` reports the effective
14
+ // base URL and env var rather than the empty YAML values.
15
+ if (!config.base_url)
16
+ config.base_url = NVIDIARunner.DEFAULT_BASE_URL;
17
+ if (!config.api_key_env)
18
+ config.api_key_env = 'NVIDIA_API_KEY';
19
+ super(config);
20
+ }
21
+ defaultEnvVar = 'NVIDIA_API_KEY';
22
+ }
23
+ //# sourceMappingURL=nvidia.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nvidia.js","sourceRoot":"","sources":["../../src/runners/nvidia.ts"],"names":[],"mappings":"AAAA,sDAAsD;AAEtD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C;;;;;GAKG;AACH,MAAM,OAAO,YAAa,SAAQ,YAAY;IAC5C,MAAM,CAAU,gBAAgB,GAAG,qCAAqC,CAAC;IAEzE,YAAY,MAAoB;QAC9B,4EAA4E;QAC5E,4EAA4E;QAC5E,0DAA0D;QAC1D,IAAI,CAAC,MAAM,CAAC,QAAQ;YAAE,MAAM,CAAC,QAAQ,GAAG,YAAY,CAAC,gBAAgB,CAAC;QACtE,IAAI,CAAC,MAAM,CAAC,WAAW;YAAE,MAAM,CAAC,WAAW,GAAG,gBAAgB,CAAC;QAC/D,KAAK,CAAC,MAAM,CAAC,CAAC;IAChB,CAAC;IAE2B,aAAa,GAAG,gBAAgB,CAAC;CAC9D"}
@@ -0,0 +1,8 @@
1
+ /** Ollama local HTTP runner implementation. */
2
+ import { BaseRunner, type RunnerConfig, type RunnerResult } from './base.js';
3
+ /** Runner adapter for local LLMs served by Ollama (Llama 3, DeepSeek, Mistral, Qwen). */
4
+ export declare class OllamaRunner extends BaseRunner {
5
+ private readonly baseUrl;
6
+ constructor(config: RunnerConfig);
7
+ execute(task: string, params?: Record<string, unknown> | null): Promise<RunnerResult>;
8
+ }