@vheins/opencode-9router 0.4.4 → 0.5.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 (3) hide show
  1. package/README.md +40 -42
  2. package/dist/plugin.js +44 -88
  3. package/package.json +2 -1
package/README.md CHANGED
@@ -2,29 +2,34 @@
2
2
 
3
3
  OpenCode plugin provider for [9Router](https://github.com/decolua/9router) — FREE AI Router & Token Saver. 40+ providers, 100+ models.
4
4
 
5
- Mendaftarkan 9Router sebagai custom provider di OpenCode dengan auto-discovery models dan konfigurasi baseURL via `/connect`.
5
+ Mendaftarkan 9Router sebagai custom provider di OpenCode dengan auto-discovery models.
6
6
 
7
7
  ## Quick Start
8
8
 
9
9
  ```json
10
10
  {
11
11
  "$schema": "https://opencode.ai/config.json",
12
- "plugin": ["@vheins/opencode-9router@latest"]
12
+ "plugin": ["@vheins/opencode-9router@latest"],
13
+ "provider": {
14
+ "9router": {
15
+ "npm": "@ai-sdk/openai-compatible",
16
+ "name": "9Router",
17
+ "options": {
18
+ "baseURL": "https://model.idsolutions.id/v1"
19
+ }
20
+ }
21
+ }
13
22
  }
14
23
  ```
15
24
 
16
- 1. Tambahkan plugin ke `opencode.json`
25
+ 1. Tambahkan plugin dan provider ke `opencode.json`
17
26
  2. Restart OpenCode
18
- 3. `/connect` → pilih **Connect to 9Router**
19
- 4. Masukkan Base URL (default: `http://localhost:20128`) dan API Key
20
- 5. `/models` → pilih model 9Router
27
+ 3. `/models` → pilih model 9Router
21
28
 
22
29
  ## Features
23
30
 
24
31
  - **Auto-discover models** — Models dari 9Router otomatis terdeteksi saat startup
25
- - **Configurable baseURL** — Atur Base URL via `/connect`, plugin options, atau environment variable
26
32
  - **Dynamic model list** — Semua model dari 9Router tersedia, termasuk combo kustom
27
- - **27+ fallback models** — Well-known models tersedia jika 9Router belum running
28
33
  - **OpenAI-compatible** — Menggunakan `@ai-sdk/openai-compatible`
29
34
  - **Type-safe** — Menggunakan `config` hook untuk registrasi provider yang sesuai dengan OpenCode config schema
30
35
 
@@ -35,11 +40,20 @@ Mendaftarkan 9Router sebagai custom provider di OpenCode dengan auto-discovery m
35
40
  ```json
36
41
  {
37
42
  "$schema": "https://opencode.ai/config.json",
38
- "plugin": ["@vheins/opencode-9router@latest"]
43
+ "plugin": ["@vheins/opencode-9router@latest"],
44
+ "provider": {
45
+ "9router": {
46
+ "npm": "@ai-sdk/openai-compatible",
47
+ "name": "9Router",
48
+ "options": {
49
+ "baseURL": "https://model.idsolutions.id/v1"
50
+ }
51
+ }
52
+ }
39
53
  }
40
54
  ```
41
55
 
42
- Tidak perlu mendefinisikan models atau provider secara manual — plugin mendaftarkan semuanya otomatis.
56
+ Plugin akan auto-discover models dari baseURL yang dikonfigurasi.
43
57
 
44
58
  ### Local file
45
59
 
@@ -50,14 +64,9 @@ cp src/constants.ts .opencode/plugins/constants.ts
50
64
 
51
65
  ## Usage
52
66
 
53
- ### 1. Connect via `/connect`
67
+ ### 1. Configure provider
54
68
 
55
- ```
56
- /connect
57
- → Select: Connect to 9Router
58
- → Base URL: http://localhost:20128 (customize if needed)
59
- → API Key: [paste from 9Router Dashboard → Endpoints]
60
- ```
69
+ Tambahkan provider `9router` ke `opencode.json` dengan `baseURL` yang sesuai.
61
70
 
62
71
  ### 2. Select model
63
72
 
@@ -69,29 +78,22 @@ cp src/constants.ts .opencode/plugins/constants.ts
69
78
 
70
79
  ### Custom Base URL
71
80
 
72
- Jika 9Router berjalan di host/port berbeda, ada 3 cara konfigurasi:
73
-
74
- #### Via `/connect` (recommended)
75
-
76
- Masukkan URL custom saat diminta Base URL.
77
-
78
- #### Via plugin options
81
+ Ubah `baseURL` di provider config sesuai kebutuhan:
79
82
 
80
83
  ```json
81
84
  {
82
- "$schema": "https://opencode.ai/config.json",
83
- "plugin": [
84
- ["@vheins/opencode-9router@latest", { "baseURL": "http://192.168.1.100:20128" }]
85
- ]
85
+ "provider": {
86
+ "9router": {
87
+ "npm": "@ai-sdk/openai-compatible",
88
+ "name": "9Router",
89
+ "options": {
90
+ "baseURL": "http://localhost:20128/v1"
91
+ }
92
+ }
93
+ }
86
94
  }
87
95
  ```
88
96
 
89
- #### Via environment variable
90
-
91
- ```bash
92
- export ROUTER_BASE_URL=http://192.168.1.100:20128
93
- ```
94
-
95
97
  ## Model Prefixes
96
98
 
97
99
  | Prefix | Provider | Tier |
@@ -118,18 +120,14 @@ opencode.json "plugin": ["@vheins/opencode-9router@latest"]
118
120
  Bun installs package from npm
119
121
 
120
122
  Plugin loads at startup:
121
- 1. Resolve baseURL (options > env > default)
122
- 2. Try GET /v1/models from 9Router (3s timeout)
123
+ 1. Read provider config from opencode.json
124
+ 2. Try GET /v1/models from baseURL (3s timeout)
123
125
  3. If OK → register live models
124
- 4. If fail → register 27 fallback models
126
+ 4. If fail → log error, no models registered
125
127
 
126
- config hook injects provider "9router" into OpenCode config
128
+ config hook updates provider with discovered models
127
129
 
128
130
  Provider "9router" appears in /models
129
-
130
- User runs /connect → enters baseURL + API key
131
-
132
- Auth loader overrides provider config with user's baseURL
133
131
  ```
134
132
 
135
133
  ## Development
package/dist/plugin.js CHANGED
@@ -10,16 +10,6 @@ function formatModelName(modelId) {
10
10
  function normalizeBaseURL(url) {
11
11
  return url.replace(/\/+$/, "");
12
12
  }
13
- function resolveBaseURL(options) {
14
- if (options?.baseURL && typeof options.baseURL === "string") {
15
- return { url: normalizeBaseURL(options.baseURL), isDefault: false };
16
- }
17
- const envURL = globalThis.process;
18
- if (envURL?.env?.ROUTER_BASE_URL) {
19
- return { url: normalizeBaseURL(envURL.env.ROUTER_BASE_URL), isDefault: false };
20
- }
21
- return { url: DEFAULT_BASE_URL, isDefault: true };
22
- }
23
13
  function ensureAPIPath(baseURL) {
24
14
  return baseURL.endsWith(DEFAULT_API_PATH) ? baseURL : `${baseURL}${DEFAULT_API_PATH}`;
25
15
  }
@@ -45,86 +35,52 @@ async function discoverModels(baseURL) {
45
35
  return null;
46
36
  }
47
37
  }
48
- export const NineRouterPlugin = async ({ client }, options) => {
49
- const { url: configuredBaseURL, isDefault } = resolveBaseURL(options);
50
- let discovered = isDefault ? null : await discoverModels(configuredBaseURL);
51
- if (!discovered && !isDefault && client?.app?.log) {
52
- await client.app.log({
53
- body: {
54
- service: "9router-provider",
55
- level: "error",
56
- message: `9Router not reachable at ${configuredBaseURL}. Please check if 9Router is running and accessible.`,
57
- },
58
- });
59
- }
60
- if (isDefault && client?.app?.log) {
61
- await client.app.log({
62
- body: {
63
- service: "9router-provider",
64
- level: "info",
65
- message: `9Router baseURL not configured. Set it via plugin options or ROUTER_BASE_URL env var to auto-discover models.`,
66
- },
67
- });
68
- }
38
+ export const NineRouterPlugin = async ({ client }) => {
39
+ const log = async (level, message) => {
40
+ try {
41
+ await client.app.log({
42
+ body: {
43
+ service: "9router-provider",
44
+ level,
45
+ message,
46
+ },
47
+ });
48
+ }
49
+ catch {
50
+ // Logging is best-effort
51
+ }
52
+ };
69
53
  return {
70
54
  config: async (config) => {
71
- config.provider ??= {};
72
- config.provider[PLUGIN_NAME] = {
73
- npm: "@ai-sdk/openai-compatible",
74
- name: PROVIDER_DISPLAY_NAME,
75
- options: {
76
- baseURL: ensureAPIPath(configuredBaseURL),
77
- },
78
- models: discovered ?? {},
79
- };
80
- },
81
- auth: {
82
- provider: PLUGIN_NAME,
83
- async loader(getAuth) {
84
- const auth = await getAuth();
85
- if (auth && typeof auth === "object" && "baseURL" in auth) {
86
- const userURL = normalizeBaseURL(String(auth.baseURL));
87
- const apiURL = ensureAPIPath(userURL);
88
- // Re-discover models with user-provided baseURL
89
- const authDiscovered = await discoverModels(userURL);
90
- if (authDiscovered) {
91
- discovered = authDiscovered;
92
- if (client?.app?.log) {
93
- await client.app.log({
94
- body: {
95
- service: "9router-provider",
96
- level: "info",
97
- message: `Discovered ${Object.keys(authDiscovered).length} models from ${apiURL}`,
98
- },
99
- });
100
- }
101
- }
102
- else if (client?.app?.log) {
103
- await client.app.log({
104
- body: {
105
- service: "9router-provider",
106
- level: "error",
107
- message: `Failed to discover models from ${apiURL}. Check if 9Router is running and accessible.`,
108
- },
109
- });
110
- }
111
- return { baseURL: apiURL };
112
- }
113
- return {};
114
- },
115
- methods: [
116
- {
117
- label: `Connect to ${PROVIDER_DISPLAY_NAME}`,
118
- type: "api",
119
- prompts: [
120
- {
121
- type: "text",
122
- message: `${PROVIDER_DISPLAY_NAME} Base URL (default: ${DEFAULT_BASE_URL})`,
123
- key: "baseURL",
124
- },
125
- ],
126
- },
127
- ],
55
+ if (!config.provider) {
56
+ await log("info", "9Router provider not configured. Add it to opencode.json provider section.");
57
+ return;
58
+ }
59
+ const existingProvider = config.provider[PLUGIN_NAME];
60
+ if (!existingProvider) {
61
+ await log("info", "9Router provider not configured. Add it to opencode.json provider section.");
62
+ return;
63
+ }
64
+ const options = existingProvider.options;
65
+ const baseURL = options?.baseURL;
66
+ if (!baseURL) {
67
+ await log("warn", "9Router provider missing baseURL option.");
68
+ return;
69
+ }
70
+ const normalizedURL = normalizeBaseURL(baseURL);
71
+ const apiURL = ensureAPIPath(normalizedURL);
72
+ const discovered = await discoverModels(normalizedURL);
73
+ if (discovered) {
74
+ config.provider[PLUGIN_NAME] = {
75
+ ...existingProvider,
76
+ options: { ...options, baseURL: apiURL },
77
+ models: discovered,
78
+ };
79
+ await log("info", `Discovered ${Object.keys(discovered).length} models from ${apiURL}`);
80
+ }
81
+ else {
82
+ await log("error", `Failed to discover models from ${apiURL}. Check if 9Router is running and accessible.`);
83
+ }
128
84
  },
129
85
  };
130
86
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vheins/opencode-9router",
3
- "version": "0.4.4",
3
+ "version": "0.5.0",
4
4
  "description": "OpenCode plugin provider for 9Router — FREE AI Router & Token Saver. 40+ providers, 100+ models.",
5
5
  "author": "vheins",
6
6
  "keywords": [
@@ -39,6 +39,7 @@
39
39
  "devDependencies": {
40
40
  "@opencode-ai/plugin": "^1.0.182",
41
41
  "@opencode-ai/sdk": "^1.0.182",
42
+ "@types/node": "^22.0.0",
42
43
  "typescript": "^5.9.3"
43
44
  }
44
45
  }