@antseed/provider-local-llm 0.1.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 +35 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/package.json +25 -0
- package/src/index.test.ts +45 -0
- package/src/index.ts +65 -0
- package/tsconfig.json +9 -0
package/README.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# @antseed/provider-local-llm
|
|
2
|
+
|
|
3
|
+
Sell local LLM capacity on the Antseed P2P network. Works with Ollama, llama.cpp, and any OpenAI-compatible local server.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
antseed plugin add @antseed/provider-local-llm
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# With Ollama (default)
|
|
15
|
+
antseed seed --provider local-llm
|
|
16
|
+
|
|
17
|
+
# With a custom endpoint
|
|
18
|
+
export LOCAL_LLM_BASE_URL=http://localhost:8080
|
|
19
|
+
antseed seed --provider local-llm
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Configuration
|
|
23
|
+
|
|
24
|
+
| Key | Type | Required | Default | Description |
|
|
25
|
+
|-----|------|----------|---------|-------------|
|
|
26
|
+
| `LOCAL_LLM_BASE_URL` | string | No | `http://localhost:11434` | Local LLM server URL |
|
|
27
|
+
| `LOCAL_LLM_API_KEY` | secret | No | -- | Optional API key for local server |
|
|
28
|
+
| `ANTSEED_INPUT_USD_PER_MILLION` | number | No | 0 | Input token price (USD per 1M) |
|
|
29
|
+
| `ANTSEED_OUTPUT_USD_PER_MILLION` | number | No | 0 | Output token price (USD per 1M) |
|
|
30
|
+
| `ANTSEED_MAX_CONCURRENCY` | number | No | 1 | Max concurrent requests |
|
|
31
|
+
| `ANTSEED_ALLOWED_MODELS` | string[] | No | -- | Comma-separated model allowlist |
|
|
32
|
+
|
|
33
|
+
## How It Works
|
|
34
|
+
|
|
35
|
+
Relays requests to a local LLM server. Pricing defaults to 0 (free) since you're running your own hardware. Concurrency defaults to 1 to avoid overloading local inference.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAY,MAAM,eAAe,CAAC;AAWrE,QAAA,MAAM,MAAM,EAAE,qBAmDb,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { BaseProvider, StaticTokenProvider } from '@antseed/provider-core';
|
|
2
|
+
function parseNonNegativeNumber(raw, key, fallback) {
|
|
3
|
+
const parsed = raw === undefined ? fallback : Number.parseFloat(raw);
|
|
4
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
5
|
+
throw new Error(`${key} must be a non-negative number`);
|
|
6
|
+
}
|
|
7
|
+
return parsed;
|
|
8
|
+
}
|
|
9
|
+
const plugin = {
|
|
10
|
+
name: 'local-llm',
|
|
11
|
+
displayName: 'Local LLM',
|
|
12
|
+
version: '0.1.0',
|
|
13
|
+
type: 'provider',
|
|
14
|
+
description: 'Sell local LLM capacity to P2P peers',
|
|
15
|
+
configSchema: [
|
|
16
|
+
{ key: 'LOCAL_LLM_BASE_URL', label: 'Base URL', type: 'string', required: false, default: 'http://localhost:11434', description: 'Local LLM server base URL' },
|
|
17
|
+
{ key: 'LOCAL_LLM_API_KEY', label: 'API Key', type: 'secret', required: false, description: 'Optional API key for local LLM' },
|
|
18
|
+
{ key: 'ANTSEED_INPUT_USD_PER_MILLION', label: 'Input Price', type: 'number', required: false, default: 0, description: 'Input price in USD per 1M tokens' },
|
|
19
|
+
{ key: 'ANTSEED_OUTPUT_USD_PER_MILLION', label: 'Output Price', type: 'number', required: false, default: 0, description: 'Output price in USD per 1M tokens' },
|
|
20
|
+
{ key: 'ANTSEED_MAX_CONCURRENCY', label: 'Max Concurrency', type: 'number', required: false, default: 1, description: 'Max concurrent requests' },
|
|
21
|
+
{ key: 'ANTSEED_ALLOWED_MODELS', label: 'Allowed Models', type: 'string[]', required: false, description: 'Model allow-list' },
|
|
22
|
+
],
|
|
23
|
+
createProvider(config) {
|
|
24
|
+
const baseUrl = config['LOCAL_LLM_BASE_URL'] ?? 'http://localhost:11434';
|
|
25
|
+
const apiKey = config['LOCAL_LLM_API_KEY'] ?? '';
|
|
26
|
+
const pricing = {
|
|
27
|
+
defaults: {
|
|
28
|
+
inputUsdPerMillion: parseNonNegativeNumber(config['ANTSEED_INPUT_USD_PER_MILLION'], 'ANTSEED_INPUT_USD_PER_MILLION', 0),
|
|
29
|
+
outputUsdPerMillion: parseNonNegativeNumber(config['ANTSEED_OUTPUT_USD_PER_MILLION'], 'ANTSEED_OUTPUT_USD_PER_MILLION', 0),
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
const maxConcurrency = parseInt(config['ANTSEED_MAX_CONCURRENCY'] ?? '1', 10);
|
|
33
|
+
if (Number.isNaN(maxConcurrency)) {
|
|
34
|
+
throw new Error('ANTSEED_MAX_CONCURRENCY must be a valid number');
|
|
35
|
+
}
|
|
36
|
+
const allowedModels = config['ANTSEED_ALLOWED_MODELS']
|
|
37
|
+
? config['ANTSEED_ALLOWED_MODELS'].split(',').map((s) => s.trim())
|
|
38
|
+
: [];
|
|
39
|
+
const tokenProvider = apiKey ? new StaticTokenProvider(apiKey) : undefined;
|
|
40
|
+
return new BaseProvider({
|
|
41
|
+
name: 'local-llm',
|
|
42
|
+
models: allowedModels,
|
|
43
|
+
pricing,
|
|
44
|
+
relay: {
|
|
45
|
+
baseUrl,
|
|
46
|
+
authHeaderName: 'authorization',
|
|
47
|
+
authHeaderValue: apiKey ? `Bearer ${apiKey}` : '',
|
|
48
|
+
tokenProvider,
|
|
49
|
+
maxConcurrency,
|
|
50
|
+
allowedModels,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
export default plugin;
|
|
56
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@antseed/provider-local-llm",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local LLM provider plugin for Antseed",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"prebuild": "rm -rf dist",
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"typecheck": "tsc --noEmit"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {
|
|
15
|
+
"@antseed/provider-core": "workspace:*"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@antseed/node": ">=0.1.0"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"typescript": "^5.5.0",
|
|
22
|
+
"vitest": "^2.0.0",
|
|
23
|
+
"@antseed/node": "workspace:*"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import plugin from './index.js';
|
|
3
|
+
|
|
4
|
+
describe('provider-local-llm plugin', () => {
|
|
5
|
+
it('has correct name and metadata', () => {
|
|
6
|
+
expect(plugin.name).toBe('local-llm');
|
|
7
|
+
expect(plugin.displayName).toBe('Local LLM');
|
|
8
|
+
expect(plugin.type).toBe('provider');
|
|
9
|
+
expect(plugin.version).toBe('0.1.0');
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('has configSchema with expected fields', () => {
|
|
13
|
+
const keys = plugin.configSchema!.map((f) => f.key);
|
|
14
|
+
expect(keys).toContain('LOCAL_LLM_BASE_URL');
|
|
15
|
+
expect(keys).toContain('LOCAL_LLM_API_KEY');
|
|
16
|
+
expect(keys).toContain('ANTSEED_INPUT_USD_PER_MILLION');
|
|
17
|
+
expect(keys).toContain('ANTSEED_OUTPUT_USD_PER_MILLION');
|
|
18
|
+
expect(keys).toContain('ANTSEED_MAX_CONCURRENCY');
|
|
19
|
+
expect(keys).toContain('ANTSEED_ALLOWED_MODELS');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('creates provider with default config', () => {
|
|
23
|
+
const provider = plugin.createProvider({});
|
|
24
|
+
expect(provider.name).toBe('local-llm');
|
|
25
|
+
expect(provider.pricing.defaults.inputUsdPerMillion).toBe(0);
|
|
26
|
+
expect(provider.pricing.defaults.outputUsdPerMillion).toBe(0);
|
|
27
|
+
expect(provider.maxConcurrency).toBe(1);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('creates provider with custom base URL and API key', () => {
|
|
31
|
+
const provider = plugin.createProvider({
|
|
32
|
+
LOCAL_LLM_BASE_URL: 'http://192.168.1.100:8080',
|
|
33
|
+
LOCAL_LLM_API_KEY: 'my-local-key',
|
|
34
|
+
});
|
|
35
|
+
expect(provider.name).toBe('local-llm');
|
|
36
|
+
expect(provider.maxConcurrency).toBe(1);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('applies custom concurrency', () => {
|
|
40
|
+
const provider = plugin.createProvider({
|
|
41
|
+
ANTSEED_MAX_CONCURRENCY: '4',
|
|
42
|
+
});
|
|
43
|
+
expect(provider.maxConcurrency).toBe(4);
|
|
44
|
+
});
|
|
45
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { AntseedProviderPlugin, Provider } from '@antseed/node';
|
|
2
|
+
import { BaseProvider, StaticTokenProvider } from '@antseed/provider-core';
|
|
3
|
+
|
|
4
|
+
function parseNonNegativeNumber(raw: string | undefined, key: string, fallback: number): number {
|
|
5
|
+
const parsed = raw === undefined ? fallback : Number.parseFloat(raw);
|
|
6
|
+
if (!Number.isFinite(parsed) || parsed < 0) {
|
|
7
|
+
throw new Error(`${key} must be a non-negative number`);
|
|
8
|
+
}
|
|
9
|
+
return parsed;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const plugin: AntseedProviderPlugin = {
|
|
13
|
+
name: 'local-llm',
|
|
14
|
+
displayName: 'Local LLM',
|
|
15
|
+
version: '0.1.0',
|
|
16
|
+
type: 'provider',
|
|
17
|
+
description: 'Sell local LLM capacity to P2P peers',
|
|
18
|
+
configSchema: [
|
|
19
|
+
{ key: 'LOCAL_LLM_BASE_URL', label: 'Base URL', type: 'string', required: false, default: 'http://localhost:11434', description: 'Local LLM server base URL' },
|
|
20
|
+
{ key: 'LOCAL_LLM_API_KEY', label: 'API Key', type: 'secret', required: false, description: 'Optional API key for local LLM' },
|
|
21
|
+
{ key: 'ANTSEED_INPUT_USD_PER_MILLION', label: 'Input Price', type: 'number', required: false, default: 0, description: 'Input price in USD per 1M tokens' },
|
|
22
|
+
{ key: 'ANTSEED_OUTPUT_USD_PER_MILLION', label: 'Output Price', type: 'number', required: false, default: 0, description: 'Output price in USD per 1M tokens' },
|
|
23
|
+
{ key: 'ANTSEED_MAX_CONCURRENCY', label: 'Max Concurrency', type: 'number', required: false, default: 1, description: 'Max concurrent requests' },
|
|
24
|
+
{ key: 'ANTSEED_ALLOWED_MODELS', label: 'Allowed Models', type: 'string[]', required: false, description: 'Model allow-list' },
|
|
25
|
+
],
|
|
26
|
+
|
|
27
|
+
createProvider(config: Record<string, string>): Provider {
|
|
28
|
+
const baseUrl = config['LOCAL_LLM_BASE_URL'] ?? 'http://localhost:11434';
|
|
29
|
+
const apiKey = config['LOCAL_LLM_API_KEY'] ?? '';
|
|
30
|
+
|
|
31
|
+
const pricing: Provider['pricing'] = {
|
|
32
|
+
defaults: {
|
|
33
|
+
inputUsdPerMillion: parseNonNegativeNumber(config['ANTSEED_INPUT_USD_PER_MILLION'], 'ANTSEED_INPUT_USD_PER_MILLION', 0),
|
|
34
|
+
outputUsdPerMillion: parseNonNegativeNumber(config['ANTSEED_OUTPUT_USD_PER_MILLION'], 'ANTSEED_OUTPUT_USD_PER_MILLION', 0),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const maxConcurrency = parseInt(config['ANTSEED_MAX_CONCURRENCY'] ?? '1', 10);
|
|
39
|
+
if (Number.isNaN(maxConcurrency)) {
|
|
40
|
+
throw new Error('ANTSEED_MAX_CONCURRENCY must be a valid number');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const allowedModels = config['ANTSEED_ALLOWED_MODELS']
|
|
44
|
+
? config['ANTSEED_ALLOWED_MODELS'].split(',').map((s: string) => s.trim())
|
|
45
|
+
: [];
|
|
46
|
+
|
|
47
|
+
const tokenProvider = apiKey ? new StaticTokenProvider(apiKey) : undefined;
|
|
48
|
+
|
|
49
|
+
return new BaseProvider({
|
|
50
|
+
name: 'local-llm',
|
|
51
|
+
models: allowedModels,
|
|
52
|
+
pricing,
|
|
53
|
+
relay: {
|
|
54
|
+
baseUrl,
|
|
55
|
+
authHeaderName: 'authorization',
|
|
56
|
+
authHeaderValue: apiKey ? `Bearer ${apiKey}` : '',
|
|
57
|
+
tokenProvider,
|
|
58
|
+
maxConcurrency,
|
|
59
|
+
allowedModels,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export default plugin;
|