@rethinkingstudio/clawpilot 1.0.18 → 1.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/dist/commands/provider-config.d.ts +20 -0
- package/dist/commands/provider-config.js +162 -0
- package/dist/commands/provider-config.js.map +1 -0
- package/dist/commands/provider-handlers.d.ts +2 -0
- package/dist/commands/provider-handlers.js +197 -0
- package/dist/commands/provider-handlers.js.map +1 -0
- package/dist/commands/provider-registry.d.ts +14 -0
- package/dist/commands/provider-registry.js +112 -0
- package/dist/commands/provider-registry.js.map +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/relay/relay-manager.js +17 -0
- package/dist/relay/relay-manager.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/provider-config.ts +224 -0
- package/src/commands/provider-handlers.ts +216 -0
- package/src/commands/provider-registry.ts +125 -0
- package/src/index.ts +3 -1
- package/src/relay/relay-manager.ts +18 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ProviderEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
type: string;
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
keyMasked: string | null;
|
|
6
|
+
hasKey: boolean;
|
|
7
|
+
isDefault: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function listProviderEntries(): Promise<ProviderEntry[]>;
|
|
10
|
+
export declare function addProvider(params: {
|
|
11
|
+
id: string;
|
|
12
|
+
type: string;
|
|
13
|
+
apiKey: string | null;
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
api: string;
|
|
16
|
+
apiKeyEnvName: string;
|
|
17
|
+
modelId?: string;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
export declare function deleteProvider(id: string): Promise<void>;
|
|
20
|
+
export declare function setDefaultProvider(id: string): Promise<void>;
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir, readdir } from "fs/promises";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
const OPENCLAW_DIR = join(homedir(), ".openclaw");
|
|
5
|
+
const OPENCLAW_CONFIG = join(OPENCLAW_DIR, "openclaw.json");
|
|
6
|
+
const AGENTS_DIR = join(OPENCLAW_DIR, "agents");
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Internal helpers
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
function maskKey(key) {
|
|
11
|
+
if (key.length <= 8)
|
|
12
|
+
return key.slice(0, 2) + "***" + key.slice(-2);
|
|
13
|
+
return key.slice(0, 4) + "***" + key.slice(-4);
|
|
14
|
+
}
|
|
15
|
+
async function resolveAgentId() {
|
|
16
|
+
try {
|
|
17
|
+
const entries = await readdir(AGENTS_DIR, { withFileTypes: true });
|
|
18
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
19
|
+
if (dirs.length > 0) {
|
|
20
|
+
return dirs[0];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
// agents dir missing or unreadable
|
|
25
|
+
}
|
|
26
|
+
return "main";
|
|
27
|
+
}
|
|
28
|
+
async function readJson(filePath) {
|
|
29
|
+
try {
|
|
30
|
+
const raw = await readFile(filePath, "utf-8");
|
|
31
|
+
return JSON.parse(raw);
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return {};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
async function writeJson(filePath, data) {
|
|
38
|
+
await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
39
|
+
}
|
|
40
|
+
function getNestedObj(root, keys) {
|
|
41
|
+
let cur = root;
|
|
42
|
+
for (const key of keys) {
|
|
43
|
+
if (cur[key] == null || typeof cur[key] !== "object" || Array.isArray(cur[key])) {
|
|
44
|
+
cur[key] = {};
|
|
45
|
+
}
|
|
46
|
+
cur = cur[key];
|
|
47
|
+
}
|
|
48
|
+
return cur;
|
|
49
|
+
}
|
|
50
|
+
function authProfilesPath(agentId) {
|
|
51
|
+
return join(AGENTS_DIR, agentId, "agent", "auth-profiles.json");
|
|
52
|
+
}
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Public API
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
export async function listProviderEntries() {
|
|
57
|
+
const config = await readJson(OPENCLAW_CONFIG);
|
|
58
|
+
// Dig out models.providers
|
|
59
|
+
const models = config["models"] ?? {};
|
|
60
|
+
const providers = models["providers"] ?? {};
|
|
61
|
+
// Determine current default model primary string
|
|
62
|
+
const agents = config["agents"] ?? {};
|
|
63
|
+
const defaults = agents["defaults"] ?? {};
|
|
64
|
+
const model = defaults["model"] ?? {};
|
|
65
|
+
const primaryModel = typeof model["primary"] === "string" ? model["primary"] : "";
|
|
66
|
+
// Read auth profiles for key lookup
|
|
67
|
+
const agentId = await resolveAgentId();
|
|
68
|
+
const authProfiles = await readJson(authProfilesPath(agentId));
|
|
69
|
+
const profiles = authProfiles["profiles"] ?? {};
|
|
70
|
+
const entries = [];
|
|
71
|
+
for (const [id, providerRaw] of Object.entries(providers)) {
|
|
72
|
+
const provider = providerRaw ?? {};
|
|
73
|
+
const type = typeof provider["type"] === "string" ? provider["type"] : id;
|
|
74
|
+
const baseUrl = typeof provider["baseUrl"] === "string" ? provider["baseUrl"] : "";
|
|
75
|
+
// Key lookup: profile key is "<type>:default"
|
|
76
|
+
const profileKey = `${type}:default`;
|
|
77
|
+
const profileRaw = profiles[profileKey];
|
|
78
|
+
const profile = profileRaw != null && typeof profileRaw === "object" && !Array.isArray(profileRaw)
|
|
79
|
+
? profileRaw
|
|
80
|
+
: null;
|
|
81
|
+
const apiKey = profile != null && typeof profile["apiKey"] === "string"
|
|
82
|
+
? profile["apiKey"]
|
|
83
|
+
: null;
|
|
84
|
+
const hasKey = apiKey != null && apiKey.length > 0;
|
|
85
|
+
const keyMasked = hasKey ? maskKey(apiKey) : null;
|
|
86
|
+
// isDefault: primary model string starts with "<id>/"
|
|
87
|
+
const isDefault = primaryModel === id || primaryModel.startsWith(`${id}/`);
|
|
88
|
+
entries.push({ id, type, baseUrl, keyMasked, hasKey, isDefault });
|
|
89
|
+
}
|
|
90
|
+
return entries;
|
|
91
|
+
}
|
|
92
|
+
export async function addProvider(params) {
|
|
93
|
+
const { id, type, apiKey, baseUrl, api, apiKeyEnvName, modelId } = params;
|
|
94
|
+
// --- Update openclaw.json ---
|
|
95
|
+
const config = await readJson(OPENCLAW_CONFIG);
|
|
96
|
+
const models = getNestedObj(config, ["models"]);
|
|
97
|
+
const providers = getNestedObj(models, ["providers"]);
|
|
98
|
+
const providerEntry = { type, baseUrl, api, apiKeyEnvName };
|
|
99
|
+
if (modelId !== undefined) {
|
|
100
|
+
providerEntry["modelId"] = modelId;
|
|
101
|
+
}
|
|
102
|
+
providers[id] = providerEntry;
|
|
103
|
+
await writeJson(OPENCLAW_CONFIG, config);
|
|
104
|
+
// Note: writes are not atomic. openclaw.json is updated first, then auth-profiles.json.
|
|
105
|
+
// If auth-profiles write fails, the provider will appear in the list without a key.
|
|
106
|
+
// This is acceptable since config files are user-owned and easily recoverable.
|
|
107
|
+
// --- Update auth-profiles.json (only if apiKey provided) ---
|
|
108
|
+
if (apiKey != null && apiKey.length > 0) {
|
|
109
|
+
const agentId = await resolveAgentId();
|
|
110
|
+
const profilesPath = authProfilesPath(agentId);
|
|
111
|
+
const profilesDir = join(AGENTS_DIR, agentId, "agent");
|
|
112
|
+
await mkdir(profilesDir, { recursive: true });
|
|
113
|
+
const authProfiles = await readJson(profilesPath);
|
|
114
|
+
const profiles = getNestedObj(authProfiles, ["profiles"]);
|
|
115
|
+
const profileKey = `${type}:default`;
|
|
116
|
+
profiles[profileKey] = { apiKey };
|
|
117
|
+
await writeJson(profilesPath, authProfiles);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export async function deleteProvider(id) {
|
|
121
|
+
// --- Update openclaw.json ---
|
|
122
|
+
const config = await readJson(OPENCLAW_CONFIG);
|
|
123
|
+
const models = getNestedObj(config, ["models"]);
|
|
124
|
+
const providers = getNestedObj(models, ["providers"]);
|
|
125
|
+
const providerRaw = providers[id];
|
|
126
|
+
const type = providerRaw != null &&
|
|
127
|
+
typeof providerRaw === "object" &&
|
|
128
|
+
!Array.isArray(providerRaw) &&
|
|
129
|
+
typeof providerRaw["type"] === "string"
|
|
130
|
+
? providerRaw["type"]
|
|
131
|
+
: id;
|
|
132
|
+
delete providers[id];
|
|
133
|
+
// Note: writes are not atomic. openclaw.json is updated first, then auth-profiles.json.
|
|
134
|
+
// If auth-profiles write fails, the provider will appear in the list without a key.
|
|
135
|
+
// This is acceptable since config files are user-owned and easily recoverable.
|
|
136
|
+
await writeJson(OPENCLAW_CONFIG, config);
|
|
137
|
+
// --- Update auth-profiles.json ---
|
|
138
|
+
const agentId = await resolveAgentId();
|
|
139
|
+
const profilesPath = authProfilesPath(agentId);
|
|
140
|
+
const authProfiles = await readJson(profilesPath);
|
|
141
|
+
const profiles = getNestedObj(authProfiles, ["profiles"]);
|
|
142
|
+
const profileKey = `${type}:default`;
|
|
143
|
+
if (profileKey in profiles) {
|
|
144
|
+
delete profiles[profileKey];
|
|
145
|
+
await writeJson(profilesPath, authProfiles);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
export async function setDefaultProvider(id) {
|
|
149
|
+
const config = await readJson(OPENCLAW_CONFIG);
|
|
150
|
+
// Preserve existing model suffix if present
|
|
151
|
+
const agents = getNestedObj(config, ["agents"]);
|
|
152
|
+
const defaults = getNestedObj(agents, ["defaults"]);
|
|
153
|
+
const model = getNestedObj(defaults, ["model"]);
|
|
154
|
+
const currentPrimary = typeof model["primary"] === "string" ? model["primary"] : "";
|
|
155
|
+
let modelSuffix = "default";
|
|
156
|
+
if (currentPrimary.includes("/")) {
|
|
157
|
+
modelSuffix = currentPrimary.split("/").slice(1).join("/");
|
|
158
|
+
}
|
|
159
|
+
model["primary"] = `${id}/${modelSuffix}`;
|
|
160
|
+
await writeJson(OPENCLAW_CONFIG, config);
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=provider-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-config.js","sourceRoot":"","sources":["../../src/commands/provider-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { randomUUID } from "crypto";
|
|
6
|
+
import { PROVIDER_REGISTRY } from "./provider-registry.js";
|
|
7
|
+
import { listProviderEntries, addProvider, deleteProvider, setDefaultProvider, } from "./provider-config.js";
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Subprocess env (mirrors local-handlers.ts)
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
const NODE_BIN_DIR = dirname(process.execPath);
|
|
12
|
+
const SUBPROCESS_ENV = {
|
|
13
|
+
...process.env,
|
|
14
|
+
HOME: homedir(),
|
|
15
|
+
PATH: [
|
|
16
|
+
NODE_BIN_DIR,
|
|
17
|
+
"/opt/homebrew/bin",
|
|
18
|
+
"/opt/homebrew/sbin",
|
|
19
|
+
"/usr/local/bin",
|
|
20
|
+
"/usr/local/sbin",
|
|
21
|
+
process.env.PATH ?? "/usr/bin:/bin",
|
|
22
|
+
].join(":"),
|
|
23
|
+
};
|
|
24
|
+
function resolveOpenclawBin() {
|
|
25
|
+
try {
|
|
26
|
+
const p = execSync("which openclaw", { stdio: "pipe", env: SUBPROCESS_ENV, timeout: 3000 })
|
|
27
|
+
.toString().trim();
|
|
28
|
+
if (p && existsSync(p))
|
|
29
|
+
return p;
|
|
30
|
+
}
|
|
31
|
+
catch { /* fall through */ }
|
|
32
|
+
return "openclaw";
|
|
33
|
+
}
|
|
34
|
+
const OPENCLAW_BIN = resolveOpenclawBin();
|
|
35
|
+
function restartGateway() {
|
|
36
|
+
try {
|
|
37
|
+
execSync(`"${OPENCLAW_BIN}" gateway restart`, { stdio: "pipe", env: SUBPROCESS_ENV });
|
|
38
|
+
console.log("[provider] gateway restarted");
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
console.warn("[provider] gateway restart failed:", String(err));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// HTTP key validation
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
async function validateApiKey(type, apiKey, baseUrl) {
|
|
48
|
+
const info = PROVIDER_REGISTRY[type];
|
|
49
|
+
if (!info)
|
|
50
|
+
return { ok: false, error: `Unknown provider type: ${type}` };
|
|
51
|
+
if (!info.requiresApiKey || !apiKey)
|
|
52
|
+
return { ok: true };
|
|
53
|
+
return new Promise((resolve) => {
|
|
54
|
+
try {
|
|
55
|
+
const url = new URL(info.validationPath, baseUrl);
|
|
56
|
+
if (info.validationAuth === "google-query-param") {
|
|
57
|
+
url.searchParams.set("key", apiKey);
|
|
58
|
+
}
|
|
59
|
+
const headers = {};
|
|
60
|
+
if (info.validationAuth === "bearer") {
|
|
61
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
62
|
+
}
|
|
63
|
+
else if (info.validationAuth === "x-api-key") {
|
|
64
|
+
headers["x-api-key"] = apiKey;
|
|
65
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
66
|
+
}
|
|
67
|
+
// Use http or https based on protocol
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
69
|
+
const mod = url.protocol === "https:" ? require("https") : require("http");
|
|
70
|
+
const req = mod.get({
|
|
71
|
+
hostname: url.hostname,
|
|
72
|
+
port: url.port || undefined,
|
|
73
|
+
path: url.pathname + url.search,
|
|
74
|
+
headers,
|
|
75
|
+
}, (res) => {
|
|
76
|
+
res.resume(); // drain body
|
|
77
|
+
const status = res.statusCode ?? 0;
|
|
78
|
+
if (status >= 200 && status < 300) {
|
|
79
|
+
resolve({ ok: true });
|
|
80
|
+
}
|
|
81
|
+
else if (status === 401 || status === 403) {
|
|
82
|
+
resolve({ ok: false, error: "API Key 无效" });
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
resolve({ ok: false, error: `验证失败 (HTTP ${status})` });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
req.setTimeout(10_000, () => {
|
|
89
|
+
req.destroy();
|
|
90
|
+
resolve({ ok: false, error: "验证超时" });
|
|
91
|
+
});
|
|
92
|
+
req.on("error", (e) => resolve({ ok: false, error: e.message }));
|
|
93
|
+
}
|
|
94
|
+
catch (e) {
|
|
95
|
+
resolve({ ok: false, error: String(e) });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Command handlers
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
async function cmdList() {
|
|
103
|
+
try {
|
|
104
|
+
const providers = await listProviderEntries();
|
|
105
|
+
return { ok: true, payload: { providers } };
|
|
106
|
+
}
|
|
107
|
+
catch (err) {
|
|
108
|
+
return { ok: false, error: String(err) };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function cmdValidateKey(params) {
|
|
112
|
+
try {
|
|
113
|
+
const type = params.type;
|
|
114
|
+
const apiKey = params.apiKey;
|
|
115
|
+
const baseUrl = params.baseUrl ?? PROVIDER_REGISTRY[type]?.defaultBaseUrl ?? "";
|
|
116
|
+
const result = await validateApiKey(type, apiKey, baseUrl);
|
|
117
|
+
if (result.ok)
|
|
118
|
+
return { ok: true };
|
|
119
|
+
return { ok: false, error: result.error ?? "验证失败" };
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
return { ok: false, error: String(err) };
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async function cmdAdd(params) {
|
|
126
|
+
try {
|
|
127
|
+
const type = params.type;
|
|
128
|
+
const apiKey = params.apiKey ?? null;
|
|
129
|
+
const info = PROVIDER_REGISTRY[type];
|
|
130
|
+
if (!info)
|
|
131
|
+
return { ok: false, error: `Unknown provider type: ${type}` };
|
|
132
|
+
const baseUrl = params.baseUrl || info.defaultBaseUrl;
|
|
133
|
+
const modelId = params.modelId ?? info.defaultModelId;
|
|
134
|
+
// Validate key before writing config
|
|
135
|
+
if (info.requiresApiKey && apiKey) {
|
|
136
|
+
const v = await validateApiKey(type, apiKey, baseUrl);
|
|
137
|
+
if (!v.ok)
|
|
138
|
+
return { ok: false, error: v.error ?? "API Key 无效" };
|
|
139
|
+
}
|
|
140
|
+
// custom providers get a UUID suffix; id and apiKeyEnvName share the same UUID so they're traceable
|
|
141
|
+
const uuid = info.allowMultiple ? randomUUID() : null;
|
|
142
|
+
const id = uuid ? `custom-${uuid}` : type;
|
|
143
|
+
const apiKeyEnvName = uuid
|
|
144
|
+
? `CUSTOM_${uuid.replace(/-/g, "_").toUpperCase()}_API_KEY`
|
|
145
|
+
: info.apiKeyEnvName;
|
|
146
|
+
await addProvider({ id, type, apiKey, baseUrl, api: info.api, apiKeyEnvName, modelId });
|
|
147
|
+
restartGateway();
|
|
148
|
+
return { ok: true, payload: { id } };
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
return { ok: false, error: String(err) };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
async function cmdDelete(params) {
|
|
155
|
+
try {
|
|
156
|
+
const id = params.id;
|
|
157
|
+
if (!id)
|
|
158
|
+
return { ok: false, error: "id required" };
|
|
159
|
+
await deleteProvider(id);
|
|
160
|
+
restartGateway();
|
|
161
|
+
return { ok: true };
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
return { ok: false, error: String(err) };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async function cmdSetDefault(params) {
|
|
168
|
+
try {
|
|
169
|
+
const id = params.id;
|
|
170
|
+
if (!id)
|
|
171
|
+
return { ok: false, error: "id required" };
|
|
172
|
+
await setDefaultProvider(id);
|
|
173
|
+
restartGateway();
|
|
174
|
+
return { ok: true };
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
return { ok: false, error: String(err) };
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// Main dispatch
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
export function handleProviderCommand(method, params) {
|
|
184
|
+
if (!method.startsWith("clawpilot.provider."))
|
|
185
|
+
return null;
|
|
186
|
+
const p = (params ?? {});
|
|
187
|
+
switch (method) {
|
|
188
|
+
case "clawpilot.provider.list": return cmdList();
|
|
189
|
+
case "clawpilot.provider.validateKey": return cmdValidateKey(p);
|
|
190
|
+
case "clawpilot.provider.add": return cmdAdd(p);
|
|
191
|
+
case "clawpilot.provider.delete": return cmdDelete(p);
|
|
192
|
+
case "clawpilot.provider.setDefault": return cmdSetDefault(p);
|
|
193
|
+
default:
|
|
194
|
+
return Promise.resolve({ ok: false, error: `Unknown provider command: ${method}` });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=provider-handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-handlers.js","sourceRoot":"","sources":["../../src/commands/provider-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EACL,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAE9B,8EAA8E;AAC9E,6CAA6C;AAC7C,8EAA8E;AAE9E,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE/C,MAAM,cAAc,GAAsB;IACxC,GAAG,OAAO,CAAC,GAAG;IACd,IAAI,EAAE,OAAO,EAAE;IACf,IAAI,EAAE;QACJ,YAAY;QACZ,mBAAmB;QACnB,oBAAoB;QACpB,gBAAgB;QAChB,iBAAiB;QACjB,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,eAAe;KACpC,CAAC,IAAI,CAAC,GAAG,CAAC;CACZ,CAAC;AAEF,SAAS,kBAAkB;IACzB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,QAAQ,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;aACxF,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;QACrB,IAAI,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC,CAAC,kBAAkB,CAAC,CAAC;IAC9B,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAC;AAE1C,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,QAAQ,CAAC,IAAI,YAAY,mBAAmB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,CAAC;QACtF,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,oCAAoC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,sBAAsB;AACtB,8EAA8E;AAE9E,KAAK,UAAU,cAAc,CAC3B,IAAY,EACZ,MAAc,EACd,OAAe;IAEf,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,IAAI,EAAE,EAAE,CAAC;IACzE,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IAEzD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;YAClD,IAAI,IAAI,CAAC,cAAc,KAAK,oBAAoB,EAAE,CAAC;gBACjD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACtC,CAAC;YAED,MAAM,OAAO,GAA2B,EAAE,CAAC;YAC3C,IAAI,IAAI,CAAC,cAAc,KAAK,QAAQ,EAAE,CAAC;gBACrC,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,MAAM,EAAE,CAAC;YAChD,CAAC;iBAAM,IAAI,IAAI,CAAC,cAAc,KAAK,WAAW,EAAE,CAAC;gBAC/C,OAAO,CAAC,WAAW,CAAC,GAAG,MAAM,CAAC;gBAC9B,OAAO,CAAC,mBAAmB,CAAC,GAAG,YAAY,CAAC;YAC9C,CAAC;YAED,sCAAsC;YACtC,iEAAiE;YACjE,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAC3E,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,CACjB;gBACE,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,SAAS;gBAC3B,IAAI,EAAE,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM;gBAC/B,OAAO;aACR,EACD,CAAC,GAAgD,EAAE,EAAE;gBACnD,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,aAAa;gBAC3B,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,IAAI,CAAC,CAAC;gBACnC,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,GAAG,GAAG,EAAE,CAAC;oBAClC,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;gBACxB,CAAC;qBAAM,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;oBAC5C,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;gBAC9C,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,MAAM,GAAG,EAAE,CAAC,CAAC;gBACzD,CAAC;YACH,CAAC,CACF,CAAC;YACF,GAAG,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE;gBAC1B,GAAG,CAAC,OAAO,EAAE,CAAC;gBACd,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YACxC,CAAC,CAAC,CAAC;YACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC1E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,8EAA8E;AAC9E,mBAAmB;AACnB,8EAA8E;AAE9E,KAAK,UAAU,OAAO;IACpB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,MAAM,mBAAmB,EAAE,CAAC;QAC9C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,EAAE,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,MAA+B;IAC3D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAc,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAgB,CAAC;QACvC,MAAM,OAAO,GAAI,MAAM,CAAC,OAA8B,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,cAAc,IAAI,EAAE,CAAC;QACxG,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAC3D,IAAI,MAAM,CAAC,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;QACnC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,MAAM,EAAE,CAAC;IACtD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,MAA+B;IACnD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAc,CAAC;QACnC,MAAM,MAAM,GAAI,MAAM,CAAC,MAAoC,IAAI,IAAI,CAAC;QACpE,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,0BAA0B,IAAI,EAAE,EAAE,CAAC;QAEzE,MAAM,OAAO,GAAI,MAAM,CAAC,OAA8B,IAAI,IAAI,CAAC,cAAc,CAAC;QAC9E,MAAM,OAAO,GAAI,MAAM,CAAC,OAA8B,IAAI,IAAI,CAAC,cAAc,CAAC;QAE9E,qCAAqC;QACrC,IAAI,IAAI,CAAC,cAAc,IAAI,MAAM,EAAE,CAAC;YAClC,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;YACtD,IAAI,CAAC,CAAC,CAAC,EAAE;gBAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,IAAI,YAAY,EAAE,CAAC;QAClE,CAAC;QAED,oGAAoG;QACpG,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACtD,MAAM,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1C,MAAM,aAAa,GAAG,IAAI;YACxB,CAAC,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE,UAAU;YAC3D,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;QAEvB,MAAM,WAAW,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;QACxF,cAAc,EAAE,CAAC;QACjB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,MAA+B;IACtD,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,CAAC,EAAY,CAAC;QAC/B,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;QACpD,MAAM,cAAc,CAAC,EAAE,CAAC,CAAC;QACzB,cAAc,EAAE,CAAC;QACjB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,MAA+B;IAC1D,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,CAAC,EAAY,CAAC;QAC/B,IAAI,CAAC,EAAE;YAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;QACpD,MAAM,kBAAkB,CAAC,EAAE,CAAC,CAAC;QAC7B,cAAc,EAAE,CAAC;QACjB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,MAAM,UAAU,qBAAqB,CACnC,MAAc,EACd,MAAe;IAEf,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,qBAAqB,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3D,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAA4B,CAAC;IAEpD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,yBAAyB,CAAC,CAAO,OAAO,OAAO,EAAE,CAAC;QACvD,KAAK,gCAAgC,CAAC,CAAC,OAAO,cAAc,CAAC,CAAC,CAAC,CAAC;QAChE,KAAK,wBAAwB,CAAC,CAAQ,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;QACvD,KAAK,2BAA2B,CAAC,CAAK,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;QAC1D,KAAK,+BAA+B,CAAC,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;QAC9D;YACE,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,6BAA6B,MAAM,EAAE,EAAE,CAAC,CAAC;IACxF,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ProviderTypeInfo {
|
|
2
|
+
displayName: string;
|
|
3
|
+
defaultBaseUrl: string;
|
|
4
|
+
api: "anthropic-messages" | "openai-completions" | "openai-responses";
|
|
5
|
+
apiKeyEnvName: string;
|
|
6
|
+
validationPath: string;
|
|
7
|
+
validationAuth: "bearer" | "x-api-key" | "google-query-param" | "none";
|
|
8
|
+
requiresApiKey: boolean;
|
|
9
|
+
allowMultiple: boolean;
|
|
10
|
+
showBaseUrl: boolean;
|
|
11
|
+
showModelId: boolean;
|
|
12
|
+
defaultModelId?: string;
|
|
13
|
+
}
|
|
14
|
+
export declare const PROVIDER_REGISTRY: Record<string, ProviderTypeInfo>;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
export const PROVIDER_REGISTRY = {
|
|
2
|
+
anthropic: {
|
|
3
|
+
displayName: "Anthropic",
|
|
4
|
+
defaultBaseUrl: "https://api.anthropic.com",
|
|
5
|
+
api: "anthropic-messages",
|
|
6
|
+
apiKeyEnvName: "ANTHROPIC_API_KEY",
|
|
7
|
+
validationPath: "/v1/models",
|
|
8
|
+
validationAuth: "x-api-key",
|
|
9
|
+
requiresApiKey: true,
|
|
10
|
+
allowMultiple: false,
|
|
11
|
+
showBaseUrl: false,
|
|
12
|
+
showModelId: false,
|
|
13
|
+
},
|
|
14
|
+
openai: {
|
|
15
|
+
displayName: "OpenAI",
|
|
16
|
+
defaultBaseUrl: "https://api.openai.com",
|
|
17
|
+
api: "openai-responses",
|
|
18
|
+
apiKeyEnvName: "OPENAI_API_KEY",
|
|
19
|
+
validationPath: "/v1/models",
|
|
20
|
+
validationAuth: "bearer",
|
|
21
|
+
requiresApiKey: true,
|
|
22
|
+
allowMultiple: false,
|
|
23
|
+
showBaseUrl: false,
|
|
24
|
+
showModelId: false,
|
|
25
|
+
},
|
|
26
|
+
google: {
|
|
27
|
+
displayName: "Google",
|
|
28
|
+
defaultBaseUrl: "https://generativelanguage.googleapis.com",
|
|
29
|
+
api: "openai-completions",
|
|
30
|
+
apiKeyEnvName: "GOOGLE_API_KEY",
|
|
31
|
+
validationPath: "/v1beta/models",
|
|
32
|
+
validationAuth: "google-query-param",
|
|
33
|
+
requiresApiKey: true,
|
|
34
|
+
allowMultiple: false,
|
|
35
|
+
showBaseUrl: false,
|
|
36
|
+
showModelId: false,
|
|
37
|
+
},
|
|
38
|
+
openrouter: {
|
|
39
|
+
displayName: "OpenRouter",
|
|
40
|
+
defaultBaseUrl: "https://openrouter.ai",
|
|
41
|
+
api: "openai-completions",
|
|
42
|
+
apiKeyEnvName: "OPENROUTER_API_KEY",
|
|
43
|
+
validationPath: "/api/v1/models",
|
|
44
|
+
validationAuth: "bearer",
|
|
45
|
+
requiresApiKey: true,
|
|
46
|
+
allowMultiple: false,
|
|
47
|
+
showBaseUrl: false,
|
|
48
|
+
showModelId: false,
|
|
49
|
+
},
|
|
50
|
+
ark: {
|
|
51
|
+
displayName: "ByteDance (Ark)",
|
|
52
|
+
defaultBaseUrl: "https://ark.cn-beijing.volces.com",
|
|
53
|
+
api: "openai-completions",
|
|
54
|
+
apiKeyEnvName: "ARK_API_KEY",
|
|
55
|
+
validationPath: "/api/v3/models",
|
|
56
|
+
validationAuth: "bearer",
|
|
57
|
+
requiresApiKey: true,
|
|
58
|
+
allowMultiple: false,
|
|
59
|
+
showBaseUrl: false,
|
|
60
|
+
showModelId: false,
|
|
61
|
+
},
|
|
62
|
+
moonshot: {
|
|
63
|
+
displayName: "Moonshot (Kimi)",
|
|
64
|
+
defaultBaseUrl: "https://api.moonshot.cn",
|
|
65
|
+
api: "openai-completions",
|
|
66
|
+
apiKeyEnvName: "MOONSHOT_API_KEY",
|
|
67
|
+
validationPath: "/v1/models",
|
|
68
|
+
validationAuth: "bearer",
|
|
69
|
+
requiresApiKey: true,
|
|
70
|
+
allowMultiple: false,
|
|
71
|
+
showBaseUrl: false,
|
|
72
|
+
showModelId: false,
|
|
73
|
+
},
|
|
74
|
+
siliconflow: {
|
|
75
|
+
displayName: "SiliconFlow",
|
|
76
|
+
defaultBaseUrl: "https://api.siliconflow.cn",
|
|
77
|
+
api: "openai-completions",
|
|
78
|
+
apiKeyEnvName: "SILICONFLOW_API_KEY",
|
|
79
|
+
validationPath: "/v1/models",
|
|
80
|
+
validationAuth: "bearer",
|
|
81
|
+
requiresApiKey: true,
|
|
82
|
+
allowMultiple: false,
|
|
83
|
+
showBaseUrl: false,
|
|
84
|
+
showModelId: false,
|
|
85
|
+
},
|
|
86
|
+
ollama: {
|
|
87
|
+
displayName: "Ollama",
|
|
88
|
+
defaultBaseUrl: "http://localhost:11434",
|
|
89
|
+
api: "openai-completions",
|
|
90
|
+
apiKeyEnvName: "OLLAMA_API_KEY",
|
|
91
|
+
validationPath: "/api/tags",
|
|
92
|
+
validationAuth: "none",
|
|
93
|
+
requiresApiKey: false,
|
|
94
|
+
allowMultiple: false,
|
|
95
|
+
showBaseUrl: true,
|
|
96
|
+
showModelId: false,
|
|
97
|
+
},
|
|
98
|
+
custom: {
|
|
99
|
+
displayName: "Custom",
|
|
100
|
+
defaultBaseUrl: "",
|
|
101
|
+
api: "openai-completions",
|
|
102
|
+
apiKeyEnvName: "CUSTOM_API_KEY",
|
|
103
|
+
validationPath: "/v1/models",
|
|
104
|
+
validationAuth: "bearer",
|
|
105
|
+
requiresApiKey: false,
|
|
106
|
+
allowMultiple: true,
|
|
107
|
+
showBaseUrl: true,
|
|
108
|
+
showModelId: true,
|
|
109
|
+
defaultModelId: "custom-model",
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
//# sourceMappingURL=provider-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-registry.js","sourceRoot":"","sources":["../../src/commands/provider-registry.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
+
import { createRequire } from "module";
|
|
3
4
|
import { pairCommand } from "./commands/pair.js";
|
|
4
5
|
import { runCommand } from "./commands/run.js";
|
|
5
6
|
import { installCommand, uninstallCommand, stopCommand, restartCommand, resetCommand } from "./commands/install.js";
|
|
6
7
|
import { statusCommand } from "./commands/status.js";
|
|
7
8
|
import { setTokenCommand } from "./commands/set-token.js";
|
|
8
|
-
const
|
|
9
|
+
const require = createRequire(import.meta.url);
|
|
10
|
+
const { version } = require("../package.json");
|
|
9
11
|
const program = new Command();
|
|
10
12
|
program
|
|
11
13
|
.name("clawpilot")
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACpH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D,MAAM,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WebSocket } from "ws";
|
|
2
2
|
import { OpenClawGatewayClient } from "./gateway-client.js";
|
|
3
3
|
import { handleLocalCommand } from "../commands/local-handlers.js";
|
|
4
|
+
import { handleProviderCommand } from "../commands/provider-handlers.js";
|
|
4
5
|
import { homedir } from "os";
|
|
5
6
|
import { join } from "path";
|
|
6
7
|
import { mkdir, writeFile } from "fs/promises";
|
|
@@ -73,6 +74,22 @@ export async function runRelayManager(opts) {
|
|
|
73
74
|
return;
|
|
74
75
|
const requestId = msg.id;
|
|
75
76
|
console.log(`[relay] cmd received method=${msg.method} id=${requestId ?? "(no-id)"}`);
|
|
77
|
+
// Handle clawpilot.provider.* commands locally (async)
|
|
78
|
+
const providerPromise = handleProviderCommand(msg.method, msg.params);
|
|
79
|
+
if (providerPromise !== null) {
|
|
80
|
+
const result = await providerPromise;
|
|
81
|
+
if (requestId) {
|
|
82
|
+
send({
|
|
83
|
+
type: "res",
|
|
84
|
+
id: requestId,
|
|
85
|
+
ok: result.ok,
|
|
86
|
+
...(result.ok
|
|
87
|
+
? { payload: result.payload }
|
|
88
|
+
: { error: { message: result.error } }),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
76
93
|
// Handle clawpilot.* commands locally without forwarding to the gateway
|
|
77
94
|
const localResult = handleLocalCommand(msg.method);
|
|
78
95
|
if (localResult !== null) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-manager.js","sourceRoot":"","sources":["../../src/relay/relay-manager.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"relay-manager.js","sourceRoot":"","sources":["../../src/relay/relay-manager.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir, readdir } from "fs/promises";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { homedir } from "os";
|
|
4
|
+
|
|
5
|
+
const OPENCLAW_DIR = join(homedir(), ".openclaw");
|
|
6
|
+
const OPENCLAW_CONFIG = join(OPENCLAW_DIR, "openclaw.json");
|
|
7
|
+
const AGENTS_DIR = join(OPENCLAW_DIR, "agents");
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Types
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
export interface ProviderEntry {
|
|
14
|
+
id: string; // e.g. "anthropic", "custom-<uuid>"
|
|
15
|
+
type: string; // provider type key
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
keyMasked: string | null; // e.g. "sk-a***xyz", null if no key
|
|
18
|
+
hasKey: boolean;
|
|
19
|
+
isDefault: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Internal helpers
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
|
|
26
|
+
function maskKey(key: string): string {
|
|
27
|
+
if (key.length <= 8) return key.slice(0, 2) + "***" + key.slice(-2);
|
|
28
|
+
return key.slice(0, 4) + "***" + key.slice(-4);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async function resolveAgentId(): Promise<string> {
|
|
32
|
+
try {
|
|
33
|
+
const entries = await readdir(AGENTS_DIR, { withFileTypes: true });
|
|
34
|
+
const dirs = entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
35
|
+
if (dirs.length > 0) {
|
|
36
|
+
return dirs[0];
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// agents dir missing or unreadable
|
|
40
|
+
}
|
|
41
|
+
return "main";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function readJson(filePath: string): Promise<Record<string, unknown>> {
|
|
45
|
+
try {
|
|
46
|
+
const raw = await readFile(filePath, "utf-8");
|
|
47
|
+
return JSON.parse(raw) as Record<string, unknown>;
|
|
48
|
+
} catch {
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function writeJson(filePath: string, data: unknown): Promise<void> {
|
|
54
|
+
await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getNestedObj(
|
|
58
|
+
root: Record<string, unknown>,
|
|
59
|
+
keys: string[],
|
|
60
|
+
): Record<string, unknown> {
|
|
61
|
+
let cur: Record<string, unknown> = root;
|
|
62
|
+
for (const key of keys) {
|
|
63
|
+
if (cur[key] == null || typeof cur[key] !== "object" || Array.isArray(cur[key])) {
|
|
64
|
+
cur[key] = {};
|
|
65
|
+
}
|
|
66
|
+
cur = cur[key] as Record<string, unknown>;
|
|
67
|
+
}
|
|
68
|
+
return cur;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function authProfilesPath(agentId: string): string {
|
|
72
|
+
return join(AGENTS_DIR, agentId, "agent", "auth-profiles.json");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Public API
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
export async function listProviderEntries(): Promise<ProviderEntry[]> {
|
|
80
|
+
const config = await readJson(OPENCLAW_CONFIG);
|
|
81
|
+
|
|
82
|
+
// Dig out models.providers
|
|
83
|
+
const models = (config["models"] as Record<string, unknown> | undefined) ?? {};
|
|
84
|
+
const providers = (models["providers"] as Record<string, unknown> | undefined) ?? {};
|
|
85
|
+
|
|
86
|
+
// Determine current default model primary string
|
|
87
|
+
const agents = (config["agents"] as Record<string, unknown> | undefined) ?? {};
|
|
88
|
+
const defaults = (agents["defaults"] as Record<string, unknown> | undefined) ?? {};
|
|
89
|
+
const model = (defaults["model"] as Record<string, unknown> | undefined) ?? {};
|
|
90
|
+
const primaryModel = typeof model["primary"] === "string" ? model["primary"] : "";
|
|
91
|
+
|
|
92
|
+
// Read auth profiles for key lookup
|
|
93
|
+
const agentId = await resolveAgentId();
|
|
94
|
+
const authProfiles = await readJson(authProfilesPath(agentId));
|
|
95
|
+
const profiles = (authProfiles["profiles"] as Record<string, unknown> | undefined) ?? {};
|
|
96
|
+
|
|
97
|
+
const entries: ProviderEntry[] = [];
|
|
98
|
+
|
|
99
|
+
for (const [id, providerRaw] of Object.entries(providers)) {
|
|
100
|
+
const provider = (providerRaw as Record<string, unknown>) ?? {};
|
|
101
|
+
const type = typeof provider["type"] === "string" ? provider["type"] : id;
|
|
102
|
+
const baseUrl = typeof provider["baseUrl"] === "string" ? provider["baseUrl"] : "";
|
|
103
|
+
|
|
104
|
+
// Key lookup: profile key is "<type>:default"
|
|
105
|
+
const profileKey = `${type}:default`;
|
|
106
|
+
const profileRaw = profiles[profileKey];
|
|
107
|
+
const profile = profileRaw != null && typeof profileRaw === "object" && !Array.isArray(profileRaw)
|
|
108
|
+
? (profileRaw as Record<string, unknown>)
|
|
109
|
+
: null;
|
|
110
|
+
const apiKey = profile != null && typeof profile["apiKey"] === "string"
|
|
111
|
+
? profile["apiKey"]
|
|
112
|
+
: null;
|
|
113
|
+
|
|
114
|
+
const hasKey = apiKey != null && apiKey.length > 0;
|
|
115
|
+
const keyMasked = hasKey ? maskKey(apiKey!) : null;
|
|
116
|
+
|
|
117
|
+
// isDefault: primary model string starts with "<id>/"
|
|
118
|
+
const isDefault = primaryModel === id || primaryModel.startsWith(`${id}/`);
|
|
119
|
+
|
|
120
|
+
entries.push({ id, type, baseUrl, keyMasked, hasKey, isDefault });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return entries;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export async function addProvider(params: {
|
|
127
|
+
id: string;
|
|
128
|
+
type: string;
|
|
129
|
+
apiKey: string | null;
|
|
130
|
+
baseUrl: string;
|
|
131
|
+
api: string;
|
|
132
|
+
apiKeyEnvName: string;
|
|
133
|
+
modelId?: string;
|
|
134
|
+
}): Promise<void> {
|
|
135
|
+
const { id, type, apiKey, baseUrl, api, apiKeyEnvName, modelId } = params;
|
|
136
|
+
|
|
137
|
+
// --- Update openclaw.json ---
|
|
138
|
+
const config = await readJson(OPENCLAW_CONFIG);
|
|
139
|
+
const models = getNestedObj(config, ["models"]);
|
|
140
|
+
const providers = getNestedObj(models, ["providers"]);
|
|
141
|
+
|
|
142
|
+
const providerEntry: Record<string, unknown> = { type, baseUrl, api, apiKeyEnvName };
|
|
143
|
+
if (modelId !== undefined) {
|
|
144
|
+
providerEntry["modelId"] = modelId;
|
|
145
|
+
}
|
|
146
|
+
providers[id] = providerEntry;
|
|
147
|
+
|
|
148
|
+
await writeJson(OPENCLAW_CONFIG, config);
|
|
149
|
+
|
|
150
|
+
// Note: writes are not atomic. openclaw.json is updated first, then auth-profiles.json.
|
|
151
|
+
// If auth-profiles write fails, the provider will appear in the list without a key.
|
|
152
|
+
// This is acceptable since config files are user-owned and easily recoverable.
|
|
153
|
+
|
|
154
|
+
// --- Update auth-profiles.json (only if apiKey provided) ---
|
|
155
|
+
if (apiKey != null && apiKey.length > 0) {
|
|
156
|
+
const agentId = await resolveAgentId();
|
|
157
|
+
const profilesPath = authProfilesPath(agentId);
|
|
158
|
+
const profilesDir = join(AGENTS_DIR, agentId, "agent");
|
|
159
|
+
|
|
160
|
+
await mkdir(profilesDir, { recursive: true });
|
|
161
|
+
|
|
162
|
+
const authProfiles = await readJson(profilesPath);
|
|
163
|
+
const profiles = getNestedObj(authProfiles, ["profiles"]);
|
|
164
|
+
|
|
165
|
+
const profileKey = `${type}:default`;
|
|
166
|
+
profiles[profileKey] = { apiKey };
|
|
167
|
+
|
|
168
|
+
await writeJson(profilesPath, authProfiles);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function deleteProvider(id: string): Promise<void> {
|
|
173
|
+
// --- Update openclaw.json ---
|
|
174
|
+
const config = await readJson(OPENCLAW_CONFIG);
|
|
175
|
+
const models = getNestedObj(config, ["models"]);
|
|
176
|
+
const providers = getNestedObj(models, ["providers"]);
|
|
177
|
+
|
|
178
|
+
const providerRaw = providers[id];
|
|
179
|
+
const type = providerRaw != null &&
|
|
180
|
+
typeof providerRaw === "object" &&
|
|
181
|
+
!Array.isArray(providerRaw) &&
|
|
182
|
+
typeof (providerRaw as Record<string, unknown>)["type"] === "string"
|
|
183
|
+
? (providerRaw as Record<string, unknown>)["type"] as string
|
|
184
|
+
: id;
|
|
185
|
+
|
|
186
|
+
delete providers[id];
|
|
187
|
+
|
|
188
|
+
// Note: writes are not atomic. openclaw.json is updated first, then auth-profiles.json.
|
|
189
|
+
// If auth-profiles write fails, the provider will appear in the list without a key.
|
|
190
|
+
// This is acceptable since config files are user-owned and easily recoverable.
|
|
191
|
+
|
|
192
|
+
await writeJson(OPENCLAW_CONFIG, config);
|
|
193
|
+
|
|
194
|
+
// --- Update auth-profiles.json ---
|
|
195
|
+
const agentId = await resolveAgentId();
|
|
196
|
+
const profilesPath = authProfilesPath(agentId);
|
|
197
|
+
const authProfiles = await readJson(profilesPath);
|
|
198
|
+
const profiles = getNestedObj(authProfiles, ["profiles"]);
|
|
199
|
+
|
|
200
|
+
const profileKey = `${type}:default`;
|
|
201
|
+
if (profileKey in profiles) {
|
|
202
|
+
delete profiles[profileKey];
|
|
203
|
+
await writeJson(profilesPath, authProfiles);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export async function setDefaultProvider(id: string): Promise<void> {
|
|
208
|
+
const config = await readJson(OPENCLAW_CONFIG);
|
|
209
|
+
|
|
210
|
+
// Preserve existing model suffix if present
|
|
211
|
+
const agents = getNestedObj(config, ["agents"]);
|
|
212
|
+
const defaults = getNestedObj(agents, ["defaults"]);
|
|
213
|
+
const model = getNestedObj(defaults, ["model"]);
|
|
214
|
+
|
|
215
|
+
const currentPrimary = typeof model["primary"] === "string" ? model["primary"] : "";
|
|
216
|
+
let modelSuffix = "default";
|
|
217
|
+
if (currentPrimary.includes("/")) {
|
|
218
|
+
modelSuffix = currentPrimary.split("/").slice(1).join("/");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
model["primary"] = `${id}/${modelSuffix}`;
|
|
222
|
+
|
|
223
|
+
await writeJson(OPENCLAW_CONFIG, config);
|
|
224
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { execSync } from "child_process";
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { randomUUID } from "crypto";
|
|
6
|
+
import type { LocalResult } from "./local-handlers.js";
|
|
7
|
+
import { PROVIDER_REGISTRY } from "./provider-registry.js";
|
|
8
|
+
import {
|
|
9
|
+
listProviderEntries,
|
|
10
|
+
addProvider,
|
|
11
|
+
deleteProvider,
|
|
12
|
+
setDefaultProvider,
|
|
13
|
+
} from "./provider-config.js";
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Subprocess env (mirrors local-handlers.ts)
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
|
|
19
|
+
const NODE_BIN_DIR = dirname(process.execPath);
|
|
20
|
+
|
|
21
|
+
const SUBPROCESS_ENV: NodeJS.ProcessEnv = {
|
|
22
|
+
...process.env,
|
|
23
|
+
HOME: homedir(),
|
|
24
|
+
PATH: [
|
|
25
|
+
NODE_BIN_DIR,
|
|
26
|
+
"/opt/homebrew/bin",
|
|
27
|
+
"/opt/homebrew/sbin",
|
|
28
|
+
"/usr/local/bin",
|
|
29
|
+
"/usr/local/sbin",
|
|
30
|
+
process.env.PATH ?? "/usr/bin:/bin",
|
|
31
|
+
].join(":"),
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
function resolveOpenclawBin(): string {
|
|
35
|
+
try {
|
|
36
|
+
const p = execSync("which openclaw", { stdio: "pipe", env: SUBPROCESS_ENV, timeout: 3000 })
|
|
37
|
+
.toString().trim();
|
|
38
|
+
if (p && existsSync(p)) return p;
|
|
39
|
+
} catch { /* fall through */ }
|
|
40
|
+
return "openclaw";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const OPENCLAW_BIN = resolveOpenclawBin();
|
|
44
|
+
|
|
45
|
+
function restartGateway(): void {
|
|
46
|
+
try {
|
|
47
|
+
execSync(`"${OPENCLAW_BIN}" gateway restart`, { stdio: "pipe", env: SUBPROCESS_ENV });
|
|
48
|
+
console.log("[provider] gateway restarted");
|
|
49
|
+
} catch (err) {
|
|
50
|
+
console.warn("[provider] gateway restart failed:", String(err));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// HTTP key validation
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
async function validateApiKey(
|
|
59
|
+
type: string,
|
|
60
|
+
apiKey: string,
|
|
61
|
+
baseUrl: string
|
|
62
|
+
): Promise<{ ok: boolean; error?: string }> {
|
|
63
|
+
const info = PROVIDER_REGISTRY[type];
|
|
64
|
+
if (!info) return { ok: false, error: `Unknown provider type: ${type}` };
|
|
65
|
+
if (!info.requiresApiKey || !apiKey) return { ok: true };
|
|
66
|
+
|
|
67
|
+
return new Promise((resolve) => {
|
|
68
|
+
try {
|
|
69
|
+
const url = new URL(info.validationPath, baseUrl);
|
|
70
|
+
if (info.validationAuth === "google-query-param") {
|
|
71
|
+
url.searchParams.set("key", apiKey);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const headers: Record<string, string> = {};
|
|
75
|
+
if (info.validationAuth === "bearer") {
|
|
76
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
77
|
+
} else if (info.validationAuth === "x-api-key") {
|
|
78
|
+
headers["x-api-key"] = apiKey;
|
|
79
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Use http or https based on protocol
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
84
|
+
const mod = url.protocol === "https:" ? require("https") : require("http");
|
|
85
|
+
const req = mod.get(
|
|
86
|
+
{
|
|
87
|
+
hostname: url.hostname,
|
|
88
|
+
port: url.port || undefined,
|
|
89
|
+
path: url.pathname + url.search,
|
|
90
|
+
headers,
|
|
91
|
+
},
|
|
92
|
+
(res: { statusCode?: number; resume: () => void }) => {
|
|
93
|
+
res.resume(); // drain body
|
|
94
|
+
const status = res.statusCode ?? 0;
|
|
95
|
+
if (status >= 200 && status < 300) {
|
|
96
|
+
resolve({ ok: true });
|
|
97
|
+
} else if (status === 401 || status === 403) {
|
|
98
|
+
resolve({ ok: false, error: "API Key 无效" });
|
|
99
|
+
} else {
|
|
100
|
+
resolve({ ok: false, error: `验证失败 (HTTP ${status})` });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
req.setTimeout(10_000, () => {
|
|
105
|
+
req.destroy();
|
|
106
|
+
resolve({ ok: false, error: "验证超时" });
|
|
107
|
+
});
|
|
108
|
+
req.on("error", (e: Error) => resolve({ ok: false, error: e.message }));
|
|
109
|
+
} catch (e) {
|
|
110
|
+
resolve({ ok: false, error: String(e) });
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// Command handlers
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
async function cmdList(): Promise<LocalResult> {
|
|
120
|
+
try {
|
|
121
|
+
const providers = await listProviderEntries();
|
|
122
|
+
return { ok: true, payload: { providers } };
|
|
123
|
+
} catch (err) {
|
|
124
|
+
return { ok: false, error: String(err) };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function cmdValidateKey(params: Record<string, unknown>): Promise<LocalResult> {
|
|
129
|
+
try {
|
|
130
|
+
const type = params.type as string;
|
|
131
|
+
const apiKey = params.apiKey as string;
|
|
132
|
+
const baseUrl = (params.baseUrl as string | undefined) ?? PROVIDER_REGISTRY[type]?.defaultBaseUrl ?? "";
|
|
133
|
+
const result = await validateApiKey(type, apiKey, baseUrl);
|
|
134
|
+
if (result.ok) return { ok: true };
|
|
135
|
+
return { ok: false, error: result.error ?? "验证失败" };
|
|
136
|
+
} catch (err) {
|
|
137
|
+
return { ok: false, error: String(err) };
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function cmdAdd(params: Record<string, unknown>): Promise<LocalResult> {
|
|
142
|
+
try {
|
|
143
|
+
const type = params.type as string;
|
|
144
|
+
const apiKey = (params.apiKey as string | null | undefined) ?? null;
|
|
145
|
+
const info = PROVIDER_REGISTRY[type];
|
|
146
|
+
if (!info) return { ok: false, error: `Unknown provider type: ${type}` };
|
|
147
|
+
|
|
148
|
+
const baseUrl = (params.baseUrl as string | undefined) || info.defaultBaseUrl;
|
|
149
|
+
const modelId = (params.modelId as string | undefined) ?? info.defaultModelId;
|
|
150
|
+
|
|
151
|
+
// Validate key before writing config
|
|
152
|
+
if (info.requiresApiKey && apiKey) {
|
|
153
|
+
const v = await validateApiKey(type, apiKey, baseUrl);
|
|
154
|
+
if (!v.ok) return { ok: false, error: v.error ?? "API Key 无效" };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// custom providers get a UUID suffix; id and apiKeyEnvName share the same UUID so they're traceable
|
|
158
|
+
const uuid = info.allowMultiple ? randomUUID() : null;
|
|
159
|
+
const id = uuid ? `custom-${uuid}` : type;
|
|
160
|
+
const apiKeyEnvName = uuid
|
|
161
|
+
? `CUSTOM_${uuid.replace(/-/g, "_").toUpperCase()}_API_KEY`
|
|
162
|
+
: info.apiKeyEnvName;
|
|
163
|
+
|
|
164
|
+
await addProvider({ id, type, apiKey, baseUrl, api: info.api, apiKeyEnvName, modelId });
|
|
165
|
+
restartGateway();
|
|
166
|
+
return { ok: true, payload: { id } };
|
|
167
|
+
} catch (err) {
|
|
168
|
+
return { ok: false, error: String(err) };
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function cmdDelete(params: Record<string, unknown>): Promise<LocalResult> {
|
|
173
|
+
try {
|
|
174
|
+
const id = params.id as string;
|
|
175
|
+
if (!id) return { ok: false, error: "id required" };
|
|
176
|
+
await deleteProvider(id);
|
|
177
|
+
restartGateway();
|
|
178
|
+
return { ok: true };
|
|
179
|
+
} catch (err) {
|
|
180
|
+
return { ok: false, error: String(err) };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function cmdSetDefault(params: Record<string, unknown>): Promise<LocalResult> {
|
|
185
|
+
try {
|
|
186
|
+
const id = params.id as string;
|
|
187
|
+
if (!id) return { ok: false, error: "id required" };
|
|
188
|
+
await setDefaultProvider(id);
|
|
189
|
+
restartGateway();
|
|
190
|
+
return { ok: true };
|
|
191
|
+
} catch (err) {
|
|
192
|
+
return { ok: false, error: String(err) };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ---------------------------------------------------------------------------
|
|
197
|
+
// Main dispatch
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
|
|
200
|
+
export function handleProviderCommand(
|
|
201
|
+
method: string,
|
|
202
|
+
params: unknown
|
|
203
|
+
): Promise<LocalResult> | null {
|
|
204
|
+
if (!method.startsWith("clawpilot.provider.")) return null;
|
|
205
|
+
const p = (params ?? {}) as Record<string, unknown>;
|
|
206
|
+
|
|
207
|
+
switch (method) {
|
|
208
|
+
case "clawpilot.provider.list": return cmdList();
|
|
209
|
+
case "clawpilot.provider.validateKey": return cmdValidateKey(p);
|
|
210
|
+
case "clawpilot.provider.add": return cmdAdd(p);
|
|
211
|
+
case "clawpilot.provider.delete": return cmdDelete(p);
|
|
212
|
+
case "clawpilot.provider.setDefault": return cmdSetDefault(p);
|
|
213
|
+
default:
|
|
214
|
+
return Promise.resolve({ ok: false, error: `Unknown provider command: ${method}` });
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
export interface ProviderTypeInfo {
|
|
2
|
+
displayName: string;
|
|
3
|
+
defaultBaseUrl: string;
|
|
4
|
+
api: "anthropic-messages" | "openai-completions" | "openai-responses";
|
|
5
|
+
apiKeyEnvName: string;
|
|
6
|
+
validationPath: string;
|
|
7
|
+
validationAuth: "bearer" | "x-api-key" | "google-query-param" | "none";
|
|
8
|
+
requiresApiKey: boolean;
|
|
9
|
+
allowMultiple: boolean;
|
|
10
|
+
showBaseUrl: boolean;
|
|
11
|
+
showModelId: boolean;
|
|
12
|
+
defaultModelId?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const PROVIDER_REGISTRY: Record<string, ProviderTypeInfo> = {
|
|
16
|
+
anthropic: {
|
|
17
|
+
displayName: "Anthropic",
|
|
18
|
+
defaultBaseUrl: "https://api.anthropic.com",
|
|
19
|
+
api: "anthropic-messages",
|
|
20
|
+
apiKeyEnvName: "ANTHROPIC_API_KEY",
|
|
21
|
+
validationPath: "/v1/models",
|
|
22
|
+
validationAuth: "x-api-key",
|
|
23
|
+
requiresApiKey: true,
|
|
24
|
+
allowMultiple: false,
|
|
25
|
+
showBaseUrl: false,
|
|
26
|
+
showModelId: false,
|
|
27
|
+
},
|
|
28
|
+
openai: {
|
|
29
|
+
displayName: "OpenAI",
|
|
30
|
+
defaultBaseUrl: "https://api.openai.com",
|
|
31
|
+
api: "openai-responses",
|
|
32
|
+
apiKeyEnvName: "OPENAI_API_KEY",
|
|
33
|
+
validationPath: "/v1/models",
|
|
34
|
+
validationAuth: "bearer",
|
|
35
|
+
requiresApiKey: true,
|
|
36
|
+
allowMultiple: false,
|
|
37
|
+
showBaseUrl: false,
|
|
38
|
+
showModelId: false,
|
|
39
|
+
},
|
|
40
|
+
google: {
|
|
41
|
+
displayName: "Google",
|
|
42
|
+
defaultBaseUrl: "https://generativelanguage.googleapis.com",
|
|
43
|
+
api: "openai-completions",
|
|
44
|
+
apiKeyEnvName: "GOOGLE_API_KEY",
|
|
45
|
+
validationPath: "/v1beta/models",
|
|
46
|
+
validationAuth: "google-query-param",
|
|
47
|
+
requiresApiKey: true,
|
|
48
|
+
allowMultiple: false,
|
|
49
|
+
showBaseUrl: false,
|
|
50
|
+
showModelId: false,
|
|
51
|
+
},
|
|
52
|
+
openrouter: {
|
|
53
|
+
displayName: "OpenRouter",
|
|
54
|
+
defaultBaseUrl: "https://openrouter.ai",
|
|
55
|
+
api: "openai-completions",
|
|
56
|
+
apiKeyEnvName: "OPENROUTER_API_KEY",
|
|
57
|
+
validationPath: "/api/v1/models",
|
|
58
|
+
validationAuth: "bearer",
|
|
59
|
+
requiresApiKey: true,
|
|
60
|
+
allowMultiple: false,
|
|
61
|
+
showBaseUrl: false,
|
|
62
|
+
showModelId: false,
|
|
63
|
+
},
|
|
64
|
+
ark: {
|
|
65
|
+
displayName: "ByteDance (Ark)",
|
|
66
|
+
defaultBaseUrl: "https://ark.cn-beijing.volces.com",
|
|
67
|
+
api: "openai-completions",
|
|
68
|
+
apiKeyEnvName: "ARK_API_KEY",
|
|
69
|
+
validationPath: "/api/v3/models",
|
|
70
|
+
validationAuth: "bearer",
|
|
71
|
+
requiresApiKey: true,
|
|
72
|
+
allowMultiple: false,
|
|
73
|
+
showBaseUrl: false,
|
|
74
|
+
showModelId: false,
|
|
75
|
+
},
|
|
76
|
+
moonshot: {
|
|
77
|
+
displayName: "Moonshot (Kimi)",
|
|
78
|
+
defaultBaseUrl: "https://api.moonshot.cn",
|
|
79
|
+
api: "openai-completions",
|
|
80
|
+
apiKeyEnvName: "MOONSHOT_API_KEY",
|
|
81
|
+
validationPath: "/v1/models",
|
|
82
|
+
validationAuth: "bearer",
|
|
83
|
+
requiresApiKey: true,
|
|
84
|
+
allowMultiple: false,
|
|
85
|
+
showBaseUrl: false,
|
|
86
|
+
showModelId: false,
|
|
87
|
+
},
|
|
88
|
+
siliconflow: {
|
|
89
|
+
displayName: "SiliconFlow",
|
|
90
|
+
defaultBaseUrl: "https://api.siliconflow.cn",
|
|
91
|
+
api: "openai-completions",
|
|
92
|
+
apiKeyEnvName: "SILICONFLOW_API_KEY",
|
|
93
|
+
validationPath: "/v1/models",
|
|
94
|
+
validationAuth: "bearer",
|
|
95
|
+
requiresApiKey: true,
|
|
96
|
+
allowMultiple: false,
|
|
97
|
+
showBaseUrl: false,
|
|
98
|
+
showModelId: false,
|
|
99
|
+
},
|
|
100
|
+
ollama: {
|
|
101
|
+
displayName: "Ollama",
|
|
102
|
+
defaultBaseUrl: "http://localhost:11434",
|
|
103
|
+
api: "openai-completions",
|
|
104
|
+
apiKeyEnvName: "OLLAMA_API_KEY",
|
|
105
|
+
validationPath: "/api/tags",
|
|
106
|
+
validationAuth: "none",
|
|
107
|
+
requiresApiKey: false,
|
|
108
|
+
allowMultiple: false,
|
|
109
|
+
showBaseUrl: true,
|
|
110
|
+
showModelId: false,
|
|
111
|
+
},
|
|
112
|
+
custom: {
|
|
113
|
+
displayName: "Custom",
|
|
114
|
+
defaultBaseUrl: "",
|
|
115
|
+
api: "openai-completions",
|
|
116
|
+
apiKeyEnvName: "CUSTOM_API_KEY",
|
|
117
|
+
validationPath: "/v1/models",
|
|
118
|
+
validationAuth: "bearer",
|
|
119
|
+
requiresApiKey: false,
|
|
120
|
+
allowMultiple: true,
|
|
121
|
+
showBaseUrl: true,
|
|
122
|
+
showModelId: true,
|
|
123
|
+
defaultModelId: "custom-model",
|
|
124
|
+
},
|
|
125
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
+
import { createRequire } from "module";
|
|
3
4
|
import { pairCommand } from "./commands/pair.js";
|
|
4
5
|
import { runCommand } from "./commands/run.js";
|
|
5
6
|
import { installCommand, uninstallCommand, stopCommand, restartCommand, resetCommand } from "./commands/install.js";
|
|
6
7
|
import { statusCommand } from "./commands/status.js";
|
|
7
8
|
import { setTokenCommand } from "./commands/set-token.js";
|
|
8
9
|
|
|
9
|
-
const
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const { version } = require("../package.json") as { version: string };
|
|
10
12
|
|
|
11
13
|
const program = new Command();
|
|
12
14
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WebSocket } from "ws";
|
|
2
2
|
import { OpenClawGatewayClient } from "./gateway-client.js";
|
|
3
3
|
import { handleLocalCommand } from "../commands/local-handlers.js";
|
|
4
|
+
import { handleProviderCommand } from "../commands/provider-handlers.js";
|
|
4
5
|
import { homedir } from "os";
|
|
5
6
|
import { join } from "path";
|
|
6
7
|
import { mkdir, writeFile } from "fs/promises";
|
|
@@ -121,6 +122,23 @@ export async function runRelayManager(opts: RelayManagerOptions): Promise<boolea
|
|
|
121
122
|
const requestId = msg.id;
|
|
122
123
|
console.log(`[relay] cmd received method=${msg.method} id=${requestId ?? "(no-id)"}`);
|
|
123
124
|
|
|
125
|
+
// Handle clawpilot.provider.* commands locally (async)
|
|
126
|
+
const providerPromise = handleProviderCommand(msg.method, msg.params);
|
|
127
|
+
if (providerPromise !== null) {
|
|
128
|
+
const result = await providerPromise;
|
|
129
|
+
if (requestId) {
|
|
130
|
+
send({
|
|
131
|
+
type: "res",
|
|
132
|
+
id: requestId,
|
|
133
|
+
ok: result.ok,
|
|
134
|
+
...(result.ok
|
|
135
|
+
? { payload: result.payload }
|
|
136
|
+
: { error: { message: result.error } }),
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
124
142
|
// Handle clawpilot.* commands locally without forwarding to the gateway
|
|
125
143
|
const localResult = handleLocalCommand(msg.method);
|
|
126
144
|
if (localResult !== null) {
|