@vheins/opencode-9router 0.4.0 → 0.4.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/README.md +33 -16
- package/dist/plugin.js +26 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,8 @@ Mendaftarkan 9Router sebagai custom provider di OpenCode dengan auto-discovery m
|
|
|
8
8
|
|
|
9
9
|
```json
|
|
10
10
|
{
|
|
11
|
-
"
|
|
11
|
+
"$schema": "https://opencode.ai/config.json",
|
|
12
|
+
"plugin": ["@vheins/opencode-9router@latest"]
|
|
12
13
|
}
|
|
13
14
|
```
|
|
14
15
|
|
|
@@ -21,10 +22,11 @@ Mendaftarkan 9Router sebagai custom provider di OpenCode dengan auto-discovery m
|
|
|
21
22
|
## Features
|
|
22
23
|
|
|
23
24
|
- **Auto-discover models** — Models dari 9Router otomatis terdeteksi saat startup
|
|
24
|
-
- **Configurable baseURL** — Atur Base URL
|
|
25
|
+
- **Configurable baseURL** — Atur Base URL via `/connect`, plugin options, atau environment variable
|
|
25
26
|
- **Dynamic model list** — Semua model dari 9Router tersedia, termasuk combo kustom
|
|
26
27
|
- **27+ fallback models** — Well-known models tersedia jika 9Router belum running
|
|
27
28
|
- **OpenAI-compatible** — Menggunakan `@ai-sdk/openai-compatible`
|
|
29
|
+
- **Type-safe** — Menggunakan `config` hook untuk registrasi provider yang sesuai dengan OpenCode config schema
|
|
28
30
|
|
|
29
31
|
## Installation
|
|
30
32
|
|
|
@@ -32,14 +34,18 @@ Mendaftarkan 9Router sebagai custom provider di OpenCode dengan auto-discovery m
|
|
|
32
34
|
|
|
33
35
|
```json
|
|
34
36
|
{
|
|
35
|
-
"
|
|
37
|
+
"$schema": "https://opencode.ai/config.json",
|
|
38
|
+
"plugin": ["@vheins/opencode-9router@latest"]
|
|
36
39
|
}
|
|
37
40
|
```
|
|
38
41
|
|
|
42
|
+
Tidak perlu mendefinisikan models atau provider secara manual — plugin mendaftarkan semuanya otomatis.
|
|
43
|
+
|
|
39
44
|
### Local file
|
|
40
45
|
|
|
41
46
|
```bash
|
|
42
47
|
cp src/plugin.ts .opencode/plugins/9router-provider.ts
|
|
48
|
+
cp src/constants.ts .opencode/plugins/constants.ts
|
|
43
49
|
```
|
|
44
50
|
|
|
45
51
|
## Usage
|
|
@@ -63,23 +69,24 @@ cp src/plugin.ts .opencode/plugins/9router-provider.ts
|
|
|
63
69
|
|
|
64
70
|
### Custom Base URL
|
|
65
71
|
|
|
66
|
-
Jika 9Router berjalan di host/port berbeda,
|
|
72
|
+
Jika 9Router berjalan di host/port berbeda, ada 3 cara konfigurasi:
|
|
67
73
|
|
|
68
|
-
|
|
69
|
-
Base URL: http://192.168.1.100:20128
|
|
70
|
-
```
|
|
74
|
+
#### Via `/connect` (recommended)
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
Masukkan URL custom saat diminta Base URL.
|
|
77
|
+
|
|
78
|
+
#### Via plugin options
|
|
73
79
|
|
|
74
80
|
```json
|
|
75
81
|
{
|
|
82
|
+
"$schema": "https://opencode.ai/config.json",
|
|
76
83
|
"plugin": [
|
|
77
|
-
["@vheins/opencode-9router", { "baseURL": "http://192.168.1.100:20128" }]
|
|
84
|
+
["@vheins/opencode-9router@latest", { "baseURL": "http://192.168.1.100:20128" }]
|
|
78
85
|
]
|
|
79
86
|
}
|
|
80
87
|
```
|
|
81
88
|
|
|
82
|
-
|
|
89
|
+
#### Via environment variable
|
|
83
90
|
|
|
84
91
|
```bash
|
|
85
92
|
export ROUTER_BASE_URL=http://192.168.1.100:20128
|
|
@@ -106,14 +113,17 @@ export ROUTER_BASE_URL=http://192.168.1.100:20128
|
|
|
106
113
|
## How It Works
|
|
107
114
|
|
|
108
115
|
```
|
|
109
|
-
opencode.json "plugin": ["@vheins/opencode-9router"]
|
|
116
|
+
opencode.json "plugin": ["@vheins/opencode-9router@latest"]
|
|
110
117
|
↓
|
|
111
118
|
Bun installs package from npm
|
|
112
119
|
↓
|
|
113
120
|
Plugin loads at startup:
|
|
114
|
-
1.
|
|
115
|
-
2.
|
|
116
|
-
3. If
|
|
121
|
+
1. Resolve baseURL (options > env > default)
|
|
122
|
+
2. Try GET /v1/models from 9Router (3s timeout)
|
|
123
|
+
3. If OK → register live models
|
|
124
|
+
4. If fail → register 27 fallback models
|
|
125
|
+
↓
|
|
126
|
+
config hook injects provider "9router" into OpenCode config
|
|
117
127
|
↓
|
|
118
128
|
Provider "9router" appears in /models
|
|
119
129
|
↓
|
|
@@ -127,7 +137,14 @@ Auth loader overrides provider config with user's baseURL
|
|
|
127
137
|
```bash
|
|
128
138
|
git clone https://github.com/vheins/opencode-9router
|
|
129
139
|
cd opencode-9router
|
|
130
|
-
|
|
140
|
+
npm install
|
|
141
|
+
npm run build
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Test
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
node test-minimal.mjs
|
|
131
148
|
```
|
|
132
149
|
|
|
133
150
|
### Publish
|
|
@@ -141,10 +158,10 @@ npm publish --access public
|
|
|
141
158
|
|
|
142
159
|
```
|
|
143
160
|
opencode-9router/
|
|
144
|
-
index.ts # Re-exports
|
|
145
161
|
src/
|
|
146
162
|
plugin.ts # Main plugin logic
|
|
147
163
|
constants.ts # Models, defaults, prefixes
|
|
164
|
+
dist/ # Compiled output (generated)
|
|
148
165
|
package.json # npm package config
|
|
149
166
|
tsconfig.json # TypeScript config
|
|
150
167
|
README.md # This file
|
package/dist/plugin.js
CHANGED
|
@@ -7,8 +7,24 @@ function formatModelName(modelId) {
|
|
|
7
7
|
}
|
|
8
8
|
return modelId;
|
|
9
9
|
}
|
|
10
|
+
function normalizeBaseURL(url) {
|
|
11
|
+
return url.replace(/\/+$/, "");
|
|
12
|
+
}
|
|
13
|
+
function resolveBaseURL(options) {
|
|
14
|
+
if (options?.baseURL && typeof options.baseURL === "string") {
|
|
15
|
+
return normalizeBaseURL(options.baseURL);
|
|
16
|
+
}
|
|
17
|
+
const envURL = globalThis.process;
|
|
18
|
+
if (envURL?.env?.ROUTER_BASE_URL) {
|
|
19
|
+
return normalizeBaseURL(envURL.env.ROUTER_BASE_URL);
|
|
20
|
+
}
|
|
21
|
+
return DEFAULT_BASE_URL;
|
|
22
|
+
}
|
|
23
|
+
function ensureAPIPath(baseURL) {
|
|
24
|
+
return baseURL.endsWith(DEFAULT_API_PATH) ? baseURL : `${baseURL}${DEFAULT_API_PATH}`;
|
|
25
|
+
}
|
|
10
26
|
async function discoverModels(baseURL) {
|
|
11
|
-
const apiURL =
|
|
27
|
+
const apiURL = ensureAPIPath(baseURL);
|
|
12
28
|
try {
|
|
13
29
|
const response = await fetch(`${apiURL}/models`, {
|
|
14
30
|
signal: AbortSignal.timeout(3000),
|
|
@@ -29,8 +45,8 @@ async function discoverModels(baseURL) {
|
|
|
29
45
|
return null;
|
|
30
46
|
}
|
|
31
47
|
}
|
|
32
|
-
export const NineRouterPlugin = async ({ client }) => {
|
|
33
|
-
const configuredBaseURL =
|
|
48
|
+
export const NineRouterPlugin = async ({ client }, options) => {
|
|
49
|
+
const configuredBaseURL = resolveBaseURL(options);
|
|
34
50
|
const discovered = await discoverModels(configuredBaseURL);
|
|
35
51
|
const models = discovered ?? FALLBACK_MODELS;
|
|
36
52
|
if (!discovered && client?.app?.log) {
|
|
@@ -43,22 +59,24 @@ export const NineRouterPlugin = async ({ client }) => {
|
|
|
43
59
|
});
|
|
44
60
|
}
|
|
45
61
|
return {
|
|
46
|
-
|
|
47
|
-
|
|
62
|
+
config: async (config) => {
|
|
63
|
+
config.provider ??= {};
|
|
64
|
+
config.provider[PLUGIN_NAME] = {
|
|
48
65
|
npm: "@ai-sdk/openai-compatible",
|
|
49
66
|
name: PROVIDER_DISPLAY_NAME,
|
|
50
67
|
options: {
|
|
51
|
-
baseURL:
|
|
68
|
+
baseURL: ensureAPIPath(configuredBaseURL),
|
|
52
69
|
},
|
|
53
70
|
models,
|
|
54
|
-
}
|
|
71
|
+
};
|
|
55
72
|
},
|
|
56
73
|
auth: {
|
|
57
74
|
provider: PLUGIN_NAME,
|
|
58
75
|
async loader(getAuth) {
|
|
59
76
|
const auth = await getAuth();
|
|
60
77
|
if (auth && typeof auth === "object" && "baseURL" in auth) {
|
|
61
|
-
|
|
78
|
+
const userURL = normalizeBaseURL(String(auth.baseURL));
|
|
79
|
+
return { baseURL: ensureAPIPath(userURL) };
|
|
62
80
|
}
|
|
63
81
|
return {};
|
|
64
82
|
},
|
|
@@ -71,7 +89,6 @@ export const NineRouterPlugin = async ({ client }) => {
|
|
|
71
89
|
type: "text",
|
|
72
90
|
message: `${PROVIDER_DISPLAY_NAME} Base URL (default: ${DEFAULT_BASE_URL})`,
|
|
73
91
|
key: "baseURL",
|
|
74
|
-
default: DEFAULT_BASE_URL,
|
|
75
92
|
},
|
|
76
93
|
{
|
|
77
94
|
type: "text",
|