@vheins/opencode-9router 0.4.3 → 0.4.5
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/dist/plugin.js +60 -15
- package/package.json +2 -1
package/dist/plugin.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { PLUGIN_NAME, PROVIDER_DISPLAY_NAME, DEFAULT_BASE_URL, DEFAULT_API_PATH, KNOWN_PROVIDER_PREFIXES, } from "./constants.js";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import * as os from "node:os";
|
|
2
5
|
function formatModelName(modelId) {
|
|
3
6
|
for (const [prefix, provider] of Object.entries(KNOWN_PROVIDER_PREFIXES)) {
|
|
4
7
|
if (modelId.startsWith(prefix)) {
|
|
@@ -23,6 +26,26 @@ function resolveBaseURL(options) {
|
|
|
23
26
|
function ensureAPIPath(baseURL) {
|
|
24
27
|
return baseURL.endsWith(DEFAULT_API_PATH) ? baseURL : `${baseURL}${DEFAULT_API_PATH}`;
|
|
25
28
|
}
|
|
29
|
+
async function getAuthBaseURL() {
|
|
30
|
+
try {
|
|
31
|
+
const authPath = path.join(os.homedir(), ".local", "share", "opencode", "auth.json");
|
|
32
|
+
const authContent = await fs.promises.readFile(authPath, "utf-8");
|
|
33
|
+
const auth = JSON.parse(authContent);
|
|
34
|
+
// Find 9Router auth entry
|
|
35
|
+
for (const key of Object.keys(auth)) {
|
|
36
|
+
if (key.toLowerCase().includes("9router")) {
|
|
37
|
+
const entry = auth[key];
|
|
38
|
+
if (entry?.baseURL && typeof entry.baseURL === "string") {
|
|
39
|
+
return normalizeBaseURL(entry.baseURL);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
// Auth file doesn't exist or can't be read
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
26
49
|
async function discoverModels(baseURL) {
|
|
27
50
|
const apiURL = ensureAPIPath(baseURL);
|
|
28
51
|
try {
|
|
@@ -47,22 +70,21 @@ async function discoverModels(baseURL) {
|
|
|
47
70
|
}
|
|
48
71
|
export const NineRouterPlugin = async ({ client }, options) => {
|
|
49
72
|
const { url: configuredBaseURL, isDefault } = resolveBaseURL(options);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (isDefault && client?.app?.log) {
|
|
73
|
+
// Try to get baseURL from auth file (set via opencode auth login)
|
|
74
|
+
const authBaseURL = await getAuthBaseURL();
|
|
75
|
+
const effectiveBaseURL = authBaseURL ?? configuredBaseURL;
|
|
76
|
+
// Always try to discover models from effective baseURL
|
|
77
|
+
const discovered = await discoverModels(effectiveBaseURL);
|
|
78
|
+
if (!discovered && client?.app?.log) {
|
|
79
|
+
const level = authBaseURL ? "error" : "info";
|
|
80
|
+
const message = authBaseURL
|
|
81
|
+
? `9Router not reachable at ${effectiveBaseURL}. Please check if 9Router is running and accessible.`
|
|
82
|
+
: `9Router baseURL not configured. Set it via plugin options, ROUTER_BASE_URL env var, or 'opencode auth login' to auto-discover models.`;
|
|
61
83
|
await client.app.log({
|
|
62
84
|
body: {
|
|
63
85
|
service: "9router-provider",
|
|
64
|
-
level
|
|
65
|
-
message
|
|
86
|
+
level,
|
|
87
|
+
message,
|
|
66
88
|
},
|
|
67
89
|
});
|
|
68
90
|
}
|
|
@@ -73,7 +95,7 @@ export const NineRouterPlugin = async ({ client }, options) => {
|
|
|
73
95
|
npm: "@ai-sdk/openai-compatible",
|
|
74
96
|
name: PROVIDER_DISPLAY_NAME,
|
|
75
97
|
options: {
|
|
76
|
-
baseURL: ensureAPIPath(
|
|
98
|
+
baseURL: ensureAPIPath(effectiveBaseURL),
|
|
77
99
|
},
|
|
78
100
|
models: discovered ?? {},
|
|
79
101
|
};
|
|
@@ -84,7 +106,30 @@ export const NineRouterPlugin = async ({ client }, options) => {
|
|
|
84
106
|
const auth = await getAuth();
|
|
85
107
|
if (auth && typeof auth === "object" && "baseURL" in auth) {
|
|
86
108
|
const userURL = normalizeBaseURL(String(auth.baseURL));
|
|
87
|
-
|
|
109
|
+
const apiURL = ensureAPIPath(userURL);
|
|
110
|
+
// Re-discover models with user-provided baseURL
|
|
111
|
+
const authDiscovered = await discoverModels(userURL);
|
|
112
|
+
if (authDiscovered) {
|
|
113
|
+
if (client?.app?.log) {
|
|
114
|
+
await client.app.log({
|
|
115
|
+
body: {
|
|
116
|
+
service: "9router-provider",
|
|
117
|
+
level: "info",
|
|
118
|
+
message: `Discovered ${Object.keys(authDiscovered).length} models from ${apiURL}`,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else if (client?.app?.log) {
|
|
124
|
+
await client.app.log({
|
|
125
|
+
body: {
|
|
126
|
+
service: "9router-provider",
|
|
127
|
+
level: "error",
|
|
128
|
+
message: `Failed to discover models from ${apiURL}. Check if 9Router is running and accessible.`,
|
|
129
|
+
},
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
return { baseURL: apiURL };
|
|
88
133
|
}
|
|
89
134
|
return {};
|
|
90
135
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vheins/opencode-9router",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
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
|
}
|