@coclaw/openclaw-coclaw 0.25.1 → 0.26.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/index.js
CHANGED
|
@@ -810,11 +810,14 @@ const plugin = {
|
|
|
810
810
|
loadSdk: () => import('openclaw/plugin-sdk/provider-auth'),
|
|
811
811
|
loadConfigMutation: () => import('openclaw/plugin-sdk/config-mutation'),
|
|
812
812
|
// provider-catalog-runtime 供通用 device-code 扫码登录(B1)拿 resolvePluginProviders,
|
|
813
|
-
// 驱动 provider 自带的 device_code 登录方法(codex/copilot 及以后任意 device_code provider
|
|
813
|
+
// 驱动 provider 自带的 device_code 登录方法(codex/copilot 及以后任意 device_code provider);
|
|
814
|
+
// 同时供 providerAuth.catalog 拿 setup 全集(mode:'setup')
|
|
814
815
|
loadProviderCatalogRuntime: () => import('openclaw/plugin-sdk/provider-catalog-runtime'),
|
|
816
|
+
// agent-runtime 供 providerAuth.catalog 的 hasCred 别名归一基座 id(resolveProviderIdForAuth)
|
|
817
|
+
loadAgentRuntime: () => import('openclaw/plugin-sdk/agent-runtime'),
|
|
815
818
|
});
|
|
816
819
|
|
|
817
|
-
// 模型默认配置 RPC(coclaw.model.set / list / listUsable
|
|
820
|
+
// 模型默认配置 RPC(coclaw.model.set / list / listAvailable + listUsable 过渡别名)。三个 SDK 子入口的字面量
|
|
818
821
|
// dynamic import 必须留在本入口源码——OpenClaw plugin loader 只扫入口源码
|
|
819
822
|
// 命中 `openclaw/plugin-sdk/*` 字面量并触发 jiti 重写;藏在子模块的字面量
|
|
820
823
|
// loader 看不到 → 原生 Node 解析必败。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coclaw/openclaw-coclaw",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"description": "OpenClaw plugin for remote chat over WebRTC. Run `openclaw coclaw enroll` after install.",
|
|
@@ -55,6 +55,10 @@
|
|
|
55
55
|
"verify": "pnpm check && pnpm test",
|
|
56
56
|
"link": "bash ./scripts/link.sh",
|
|
57
57
|
"unlink": "bash ./scripts/unlink.sh",
|
|
58
|
+
"wt:up": "bash ./scripts/worktree-gateway.sh up",
|
|
59
|
+
"wt:reload": "bash ./scripts/worktree-gateway.sh reload",
|
|
60
|
+
"wt:call": "bash ./scripts/worktree-gateway.sh call",
|
|
61
|
+
"wt:down": "bash ./scripts/worktree-gateway.sh down",
|
|
58
62
|
"install:npm": "bash ./scripts/install-npm.sh",
|
|
59
63
|
"uninstall:npm": "bash ./scripts/uninstall-npm.sh",
|
|
60
64
|
"release:pre": "bash ./scripts/prerelease.sh",
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* model-default/handlers.js —— coclaw.model.set / list /
|
|
2
|
+
* model-default/handlers.js —— coclaw.model.set / list / listAvailable 三个 RPC 的纯函数实现
|
|
3
|
+
* (listAvailable 即原 listUsable 改名;index.js 把 listUsable 留作过渡别名映到同一 handler)
|
|
3
4
|
*
|
|
4
5
|
* 设计要点(详见 docs/model-config-api.md § 3):
|
|
5
6
|
* - DI 注入 sdk(mutateConfigFile / loadModelCatalog / provider-auth 凭据探针 / resolveProviderIdForAuth)
|
|
6
7
|
* + loadConfig + resolveAgentDir,便于单测;产线注入在 ./index.js
|
|
7
8
|
* - **出参不加 status wrap**(gateway-method-design skill 约定):set → {};list → { default, agents };
|
|
8
|
-
*
|
|
9
|
+
* listAvailable → { byProvider }(configuredProviders 已迁出,UI 加 provider 排除改吃 catalog.hasCred)
|
|
9
10
|
* - 错误码只用 INVALID_ARGS / IO_FAILED,参考 provider-auth/handlers.js
|
|
10
11
|
* 既有 plugin 的 respondError 用 INTERNAL_ERROR 与本节契约不一致,所以本模块自带局部 helper
|
|
11
12
|
* - set 校验 fail-fast 顺序:params shape → 拒未知字段 → agentId → primary 类型 → primary 形态
|
|
12
13
|
* (纯字符串:含 '/'、'/' 不在端点;不依赖 cfg)→ loadConfig → 凭据门 → 存在性
|
|
13
14
|
* 形态校验**前置在 loadConfig 之前**,cfg 不可读时非法形态仍是 INVALID_ARGS 而非 IO_FAILED
|
|
14
15
|
* - 凭据门 + 选模型器枚举 + list 信号全部走统一别名感知原语(resolve.js),杜绝跨界面口径分叉(§ 3.2.1)
|
|
15
|
-
* - set 存在性 +
|
|
16
|
+
* - set 存在性 + listAvailable 枚举走同一目录源 loadModelCatalog({readOnly:false}):选得到 ⇒ 设得上(红线天然成立)。
|
|
16
17
|
* 用 readOnly:false(含 manifest 合并)才带进 openai-codex/* 等 manifest-only provider;readOnly:true 只读落盘,
|
|
17
18
|
* 这类从不落盘的 provider 缺失(oauth 已授权却选不出,本次回归根因)。
|
|
18
19
|
*/
|
|
@@ -21,7 +22,7 @@ import { listAllPrimariesWithCredentials, computeProviderUsable, enumerateUsable
|
|
|
21
22
|
import { writePrimary } from './persist.js';
|
|
22
23
|
|
|
23
24
|
const SET_ALLOWED_KEYS = new Set(['agentId', 'primary']);
|
|
24
|
-
const
|
|
25
|
+
const LISTAVAILABLE_ALLOWED_KEYS = new Set(['agentId']);
|
|
25
26
|
|
|
26
27
|
function respondInvalid(respond, message) {
|
|
27
28
|
respond(false, undefined, { code: 'INVALID_ARGS', message });
|
|
@@ -52,7 +53,7 @@ function parseProviderModel(primary) {
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
/**
|
|
55
|
-
* 构造 set /
|
|
56
|
+
* 构造 set / listAvailable 用的统一别名感知凭据 deps。
|
|
56
57
|
* @param {object} sdk
|
|
57
58
|
* @param {string} agentDir
|
|
58
59
|
* @returns {object}
|
|
@@ -95,19 +96,19 @@ async function validateProviderCredAndCatalog({ provider, model, primary, cfg, s
|
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
/**
|
|
98
|
-
* 构造 set / list /
|
|
99
|
+
* 构造 set / list / listAvailable 三个 handler。
|
|
99
100
|
*
|
|
100
101
|
* @param {object} opts
|
|
101
102
|
* @param {object} opts.sdk
|
|
102
103
|
* @param {Function} opts.sdk.mutateConfigFile - openclaw/plugin-sdk/config-mutation(set 写盘)
|
|
103
|
-
* @param {Function} opts.sdk.loadModelCatalog - openclaw/plugin-sdk/agent-runtime(set 存在性 +
|
|
104
|
+
* @param {Function} opts.sdk.loadModelCatalog - openclaw/plugin-sdk/agent-runtime(set 存在性 + listAvailable 枚举的目录源)
|
|
104
105
|
* @param {Function} opts.sdk.isProviderApiKeyConfigured - openclaw/plugin-sdk/provider-auth(env+账本凭据信号,别名感知)
|
|
105
106
|
* @param {Function} opts.sdk.hasConfiguredSecretInput - openclaw/plugin-sdk/provider-auth(内联 key 判定)
|
|
106
|
-
* @param {Function} opts.sdk.ensureAuthProfileStore - openclaw/plugin-sdk/provider-auth
|
|
107
|
+
* @param {Function} opts.sdk.ensureAuthProfileStore - openclaw/plugin-sdk/provider-auth(账本非空判定)
|
|
107
108
|
* @param {Function} opts.sdk.resolveProviderIdForAuth - openclaw/plugin-sdk/agent-runtime(别名归一)
|
|
108
109
|
* @param {Function} opts.loadConfig - 返回当前 cfg snapshot;缺失时返回 null
|
|
109
110
|
* @param {Function} opts.resolveAgentDir - 返回 agent /agent 子目录全路径(默认 main agent;agentId 贯穿)
|
|
110
|
-
* @returns {{ set: Function, list: Function,
|
|
111
|
+
* @returns {{ set: Function, list: Function, listAvailable: Function }}
|
|
111
112
|
*/
|
|
112
113
|
export function buildModelDefaultHandlers({ sdk, loadConfig, resolveAgentDir }) {
|
|
113
114
|
async function set({ params, respond }) {
|
|
@@ -207,14 +208,14 @@ export function buildModelDefaultHandlers({ sdk, loadConfig, resolveAgentDir })
|
|
|
207
208
|
}
|
|
208
209
|
}
|
|
209
210
|
|
|
210
|
-
async function
|
|
211
|
+
async function listAvailable({ params, respond }) {
|
|
211
212
|
try {
|
|
212
213
|
if (!params || typeof params !== 'object' || Array.isArray(params)) {
|
|
213
214
|
respondInvalid(respond, 'params must be an object');
|
|
214
215
|
return;
|
|
215
216
|
}
|
|
216
217
|
for (const key of Object.keys(params)) {
|
|
217
|
-
if (!
|
|
218
|
+
if (!LISTAVAILABLE_ALLOWED_KEYS.has(key)) {
|
|
218
219
|
respondInvalid(respond, `unknown field: ${key}`);
|
|
219
220
|
return;
|
|
220
221
|
}
|
|
@@ -238,15 +239,10 @@ export function buildModelDefaultHandlers({ sdk, loadConfig, resolveAgentDir })
|
|
|
238
239
|
|
|
239
240
|
// 目录源 loadModelCatalog({readOnly:false}):含 manifest 合并,才有 openai-codex/* 这类 manifest-only provider
|
|
240
241
|
// (readOnly:true 只读落盘缺它们 → oauth 已授权却选不出,本次回归根因)。
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
entries = await sdk.loadModelCatalog({ readOnly: false });
|
|
246
|
-
}
|
|
247
|
-
catch {
|
|
248
|
-
entries = [];
|
|
249
|
-
}
|
|
242
|
+
// 抛错(罕见,如 runtime config 取不到)→ 走外层 catch 映射 IO_FAILED,不吞成空 entries:
|
|
243
|
+
// byProvider 同时驱动前端 primary 有效性(计算属性),把"清单没加载出来"伪装成"权威空清单"会让前端
|
|
244
|
+
// 误报主模型失效。如实暴露失败 → UI 维持 available=null="先不下结论",与"真空(无凭据)"区分开。
|
|
245
|
+
const entries = await sdk.loadModelCatalog({ readOnly: false });
|
|
250
246
|
|
|
251
247
|
respond(true, enumerateUsableModels(entries, cfg, deps));
|
|
252
248
|
}
|
|
@@ -255,5 +251,5 @@ export function buildModelDefaultHandlers({ sdk, loadConfig, resolveAgentDir })
|
|
|
255
251
|
}
|
|
256
252
|
}
|
|
257
253
|
|
|
258
|
-
return { set, list,
|
|
254
|
+
return { set, list, listAvailable };
|
|
259
255
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* model-default 注册入口 —— 把 coclaw.model.set / list /
|
|
2
|
+
* model-default 注册入口 —— 把 coclaw.model.set / list / listAvailable 接到 gateway
|
|
3
|
+
*(listAvailable 即原 listUsable 改名;listUsable 作过渡别名继续注册、映到同一 handler)。
|
|
3
4
|
*
|
|
4
5
|
* 设计(同 provider-auth/index.js):
|
|
5
6
|
* - 三个 SDK 子入口(config-mutation / provider-auth / agent-runtime)懒加载,
|
|
@@ -34,7 +35,7 @@ function defaultLoadProviderAuth() {
|
|
|
34
35
|
}
|
|
35
36
|
function defaultLoadAgentRuntime() {
|
|
36
37
|
// agent-runtime barrel 同时给:resolveProviderIdForAuth(别名归一)+ loadModelCatalog(干净目录,
|
|
37
|
-
// set 存在性 /
|
|
38
|
+
// set 存在性 / listAvailable 选模型器枚举同源)。barrel re-export provider-auth-aliases.js + model-catalog.js。
|
|
38
39
|
_agentRuntimeP ??= import('openclaw/plugin-sdk/agent-runtime');
|
|
39
40
|
return _agentRuntimeP;
|
|
40
41
|
}
|
|
@@ -49,7 +50,8 @@ export function __resetSdkCaches() {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
/**
|
|
52
|
-
* 在 gateway api 上注册 `coclaw.model.set` / `coclaw.model.list` / `coclaw.model.
|
|
53
|
+
* 在 gateway api 上注册 `coclaw.model.set` / `coclaw.model.list` / `coclaw.model.listAvailable`
|
|
54
|
+
*(外加过渡别名 `coclaw.model.listUsable`,与 listAvailable 映同一 handler)。
|
|
53
55
|
*
|
|
54
56
|
* 仅 `register(api)` 的 `if (api.registrationMode === 'full')` 分支调;
|
|
55
57
|
* 其它 mode 注册副作用违规(参 plugins/openclaw/CLAUDE.md "Service / register 副作用边界")。
|
|
@@ -80,13 +82,13 @@ export function registerModelDefaultHandlers(api, opts = {}) {
|
|
|
80
82
|
]);
|
|
81
83
|
const sdk = {
|
|
82
84
|
mutateConfigFile: configMutation.mutateConfigFile,
|
|
83
|
-
// 干净目录(set 存在性 +
|
|
85
|
+
// 干净目录(set 存在性 + listAvailable 枚举同源):agent-runtime barrel re-export model-catalog.js
|
|
84
86
|
loadModelCatalog: agentRuntime.loadModelCatalog,
|
|
85
|
-
// 凭据信号(providerUsable / hasAnyUsableCredential /
|
|
87
|
+
// 凭据信号(providerUsable / hasAnyUsableCredential / 凭据门)
|
|
86
88
|
isProviderApiKeyConfigured: providerAuth.isProviderApiKeyConfigured,
|
|
87
89
|
hasConfiguredSecretInput: providerAuth.hasConfiguredSecretInput,
|
|
88
90
|
ensureAuthProfileStore: providerAuth.ensureAuthProfileStore,
|
|
89
|
-
// 别名归一(内联凭据信号 +
|
|
91
|
+
// 别名归一(内联凭据信号 + 选模型器枚举)
|
|
90
92
|
resolveProviderIdForAuth: agentRuntime.resolveProviderIdForAuth,
|
|
91
93
|
};
|
|
92
94
|
return buildModelDefaultHandlers({ sdk, loadConfig, resolveAgentDir });
|
|
@@ -114,5 +116,7 @@ export function registerModelDefaultHandlers(api, opts = {}) {
|
|
|
114
116
|
|
|
115
117
|
api.registerGatewayMethod('coclaw.model.set', wrap('set'));
|
|
116
118
|
api.registerGatewayMethod('coclaw.model.list', wrap('list'));
|
|
117
|
-
api.registerGatewayMethod('coclaw.model.
|
|
119
|
+
api.registerGatewayMethod('coclaw.model.listAvailable', wrap('listAvailable'));
|
|
120
|
+
// 过渡别名:旧 UI 仍调 listUsable,映到同一 handler(决策1:纯过渡,不加任何额外兜底)
|
|
121
|
+
api.registerGatewayMethod('coclaw.model.listUsable', wrap('listAvailable'));
|
|
118
122
|
}
|
|
@@ -285,7 +285,7 @@ export function computeConfiguredProviders(cfg, deps) {
|
|
|
285
285
|
* @param {object[]} catalogEntries - loadModelCatalog({readOnly:false}) 的结果(ModelCatalogEntry[])
|
|
286
286
|
* @param {object} cfg
|
|
287
287
|
* @param {object} deps - { agentDir, isProviderApiKeyConfigured, hasConfiguredSecretInput, resolveProviderIdForAuth, ensureAuthProfileStore }
|
|
288
|
-
* @returns {{ byProvider: Record<string, string[]
|
|
288
|
+
* @returns {{ byProvider: Record<string, string[]> }}
|
|
289
289
|
*/
|
|
290
290
|
export function enumerateUsableModels(catalogEntries, cfg, deps) {
|
|
291
291
|
const grouped = new Map(); // provider -> Set<modelId>
|
|
@@ -307,7 +307,9 @@ export function enumerateUsableModels(catalogEntries, cfg, deps) {
|
|
|
307
307
|
byProvider[provider] = [...ids].sort();
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
|
-
|
|
310
|
+
// 只返回 byProvider;configuredProviders 已迁出(catalog 经 computeConfiguredProviders 单独算 hasCred,
|
|
311
|
+
// UI 加 provider 排除改吃 catalog.hasCred)。computeConfiguredProviders 仍具名导出供 catalog 复用。
|
|
312
|
+
return { byProvider };
|
|
311
313
|
}
|
|
312
314
|
|
|
313
315
|
/**
|
|
@@ -38,7 +38,7 @@ import { PORTAL_PROVIDER_ID, CONFIG_DEFAULT_BASE_URL, VALID_REGIONS } from './mi
|
|
|
38
38
|
import { getPortalModels } from './portal-model-catalog.js';
|
|
39
39
|
import { remoteLog } from '../remote-log.js';
|
|
40
40
|
import { getClawConfig } from '../claw-config.js';
|
|
41
|
-
import { listAllPrimaries, providerSegmentOf } from '../model-default/resolve.js';
|
|
41
|
+
import { listAllPrimaries, providerSegmentOf, computeConfiguredProviders } from '../model-default/resolve.js';
|
|
42
42
|
import { deepMergeInto } from '../utils/deep-merge.js';
|
|
43
43
|
import {
|
|
44
44
|
isVerificationNote,
|
|
@@ -50,6 +50,14 @@ import {
|
|
|
50
50
|
const VALID_CRED_TYPES = new Set(['api_key', 'oauth', 'token']);
|
|
51
51
|
const PORTAL_PROFILE_ID = `${PORTAL_PROVIDER_ID}:default`;
|
|
52
52
|
|
|
53
|
+
// catalog 出参的 authMethods 映射(一条规则零特判):只露这三 kind,token/custom 不进出参。
|
|
54
|
+
// kind 五值见上游 types.ts(oauth|api_key|token|device_code|custom)。
|
|
55
|
+
const KIND_TO_AUTH_METHOD = {
|
|
56
|
+
device_code: 'oauth-device-code',
|
|
57
|
+
oauth: 'oauth-login',
|
|
58
|
+
api_key: 'api-key',
|
|
59
|
+
};
|
|
60
|
+
|
|
53
61
|
function respondInvalid(respond, message) {
|
|
54
62
|
respond(false, undefined, { code: 'INVALID_ARGS', message });
|
|
55
63
|
}
|
|
@@ -84,7 +92,9 @@ function isNonEmptyString(v) {
|
|
|
84
92
|
* @param {Function} [opts.logRemote] - (text) → void,OAuth 终态诊断推送;默认模块级 remoteLog(测试注入 spy)
|
|
85
93
|
* @param {Function} [opts.resolveConfig] - () → OpenClaw runtime config 快照;通用 device-code 登录(B1)拿 config 用,默认 getClawConfig
|
|
86
94
|
* @param {Function} [opts.resolveProviders] - ({ config, providerRefs }) → ProviderPlugin[];B1 经它拿 provider 的 auth 方法(生产由入口注入,内部 activate:false),默认抛错
|
|
87
|
-
* @
|
|
95
|
+
* @param {Function} [opts.resolveSetupProviders] - ({ config }) → ProviderPlugin[];catalog 经它拿 setup 全集(mode:'setup', activate:false, cache:true,生产由入口注入),默认抛错
|
|
96
|
+
* @param {Function} [opts.loadProviderIdResolver] - () → Promise<resolveProviderIdForAuth>;catalog 算 hasCred 时别名归一基座 id(生产由入口惰性加载 agent-runtime),默认抛错
|
|
97
|
+
* @returns {{ setApiKey, list, remove, loginOauth, cancelOauth, catalog }}
|
|
88
98
|
*/
|
|
89
99
|
export function buildProviderAuthHandlers({
|
|
90
100
|
sdk,
|
|
@@ -96,6 +106,8 @@ export function buildProviderAuthHandlers({
|
|
|
96
106
|
logRemote = remoteLog,
|
|
97
107
|
resolveConfig = getClawConfig,
|
|
98
108
|
resolveProviders = () => { throw new Error('provider catalog runtime not injected'); },
|
|
109
|
+
resolveSetupProviders = () => { throw new Error('provider catalog runtime not injected'); },
|
|
110
|
+
loadProviderIdResolver = () => { throw new Error('agent runtime not injected'); },
|
|
99
111
|
}) {
|
|
100
112
|
// TODO: 将来若要支持"设默认模型 / 多账号顺序"等需要写 cfg 的操作,会撞上
|
|
101
113
|
// gateway 重启窗口的 UX 问题——参 docs/model-config-api.md § 3 / § 5(占位章节)。
|
|
@@ -553,7 +565,79 @@ export function buildProviderAuthHandlers({
|
|
|
553
565
|
}
|
|
554
566
|
}
|
|
555
567
|
|
|
556
|
-
|
|
568
|
+
// --- provider 目录(能力 1):枚举全集 provider + 各自认证方式 + 是否已配凭据 ---
|
|
569
|
+
|
|
570
|
+
// 无参;出参 { providers: [{ provider, authMethods, hasCred }] }(命名对象、不 wrap、不 undefined)。
|
|
571
|
+
// 数据源 = resolvePluginProviders(setup) 全集(含未配 provider);authMethods 一条规则零特判
|
|
572
|
+
// (device_code/oauth/api_key 三 kind 露出,token/custom 不露,authMethods 空则该 provider 不进出参);
|
|
573
|
+
// hasCred 复用 computeConfiguredProviders 三源(账本/内联/env)别名归一基座 id。
|
|
574
|
+
// 错误码:未知字段 → INVALID_ARGS(params:{} / undefined / null 都放行);解析/凭据探针/store 读抛错 → IO_FAILED。
|
|
575
|
+
async function catalog({ params, respond }) {
|
|
576
|
+
try {
|
|
577
|
+
// 无参方法:params 缺省(undefined / null)或空对象都放行;带任何字段即未知字段。
|
|
578
|
+
if (params !== undefined && params !== null) {
|
|
579
|
+
if (typeof params !== 'object' || Array.isArray(params)) {
|
|
580
|
+
respondInvalid(respond, 'params must be an object');
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
const keys = Object.keys(params);
|
|
584
|
+
if (keys.length > 0) {
|
|
585
|
+
respondInvalid(respond, `unknown field: ${keys[0]}`);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
const config = resolveConfig() ?? {};
|
|
591
|
+
// setup 全集(含未配):activate:false 零副作用、cache:true 复用进程内发现缓存。生产由入口注入。
|
|
592
|
+
const providers = await resolveSetupProviders({ config });
|
|
593
|
+
// 别名归一基座 id(hasCred 计算用):agent-runtime 惰性加载,失败走 IO_FAILED。
|
|
594
|
+
const resolveProviderIdForAuth = await loadProviderIdResolver();
|
|
595
|
+
// 三源 hasCred(账本/内联/env),全过 resolveProviderIdForAuth 归一基座 id。
|
|
596
|
+
const configuredSet = new Set(computeConfiguredProviders(config, {
|
|
597
|
+
agentDir: resolveAgentDir(),
|
|
598
|
+
isProviderApiKeyConfigured: sdk.isProviderApiKeyConfigured,
|
|
599
|
+
hasConfiguredSecretInput: sdk.hasConfiguredSecretInput,
|
|
600
|
+
ensureAuthProfileStore: sdk.ensureAuthProfileStore,
|
|
601
|
+
resolveProviderIdForAuth,
|
|
602
|
+
}));
|
|
603
|
+
|
|
604
|
+
const out = [];
|
|
605
|
+
for (const p of providers ?? []) {
|
|
606
|
+
const provider = p?.id;
|
|
607
|
+
if (typeof provider !== 'string' || provider.length === 0) continue;
|
|
608
|
+
const authMethods = mapAuthMethods(p.auth);
|
|
609
|
+
if (authMethods.length === 0) continue; // custom-only / token-only / 空 auth[] 自然排除
|
|
610
|
+
out.push({ provider, authMethods, hasCred: configuredSet.has(provider) });
|
|
611
|
+
}
|
|
612
|
+
respond(true, { providers: out });
|
|
613
|
+
}
|
|
614
|
+
catch (err) {
|
|
615
|
+
respondIoFailed(respond, err);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
return { setApiKey, list, remove, loginOauth, cancelOauth, catalog };
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* 把 provider 的 auth[] 映射成对外的 authMethods(catalog 用,一条规则零特判):
|
|
624
|
+
* device_code→oauth-device-code、oauth→oauth-login、api_key→api-key;token/custom 不露。
|
|
625
|
+
* 保留 auth[] 出现顺序,按方法名去重(一 provider 可多入口、同 kind 多条只算一次)。
|
|
626
|
+
* @param {Array<{kind?:string}>} authArr - resolvePluginProviders 返回项的 auth 数组
|
|
627
|
+
* @returns {string[]}
|
|
628
|
+
*/
|
|
629
|
+
function mapAuthMethods(authArr) {
|
|
630
|
+
const out = [];
|
|
631
|
+
const seen = new Set();
|
|
632
|
+
if (!Array.isArray(authArr)) return out;
|
|
633
|
+
for (const a of authArr) {
|
|
634
|
+
const method = KIND_TO_AUTH_METHOD[a?.kind];
|
|
635
|
+
if (method && !seen.has(method)) {
|
|
636
|
+
seen.add(method);
|
|
637
|
+
out.push(method);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return out;
|
|
557
641
|
}
|
|
558
642
|
|
|
559
643
|
/**
|
|
@@ -25,6 +25,7 @@ import { mainAgentDir } from '../claw-paths.js';
|
|
|
25
25
|
let _sdkPromise;
|
|
26
26
|
let _configMutationPromise;
|
|
27
27
|
let _catalogRuntimePromise;
|
|
28
|
+
let _agentRuntimePromise;
|
|
28
29
|
|
|
29
30
|
// 默认 loader 仅作 fallback:生产路径必须由入口(plugins/openclaw/index.js)注入,
|
|
30
31
|
// 因为 OpenClaw plugin loader 只扫入口源码识别 `openclaw/plugin-sdk/*` 字面量并触发 jiti 重写;
|
|
@@ -45,6 +46,12 @@ function defaultLoadProviderCatalogRuntime() {
|
|
|
45
46
|
return _catalogRuntimePromise;
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
function defaultLoadAgentRuntime() {
|
|
50
|
+
// agent-runtime barrel 提供 resolveProviderIdForAuth(别名归一基座 id)——catalog 算 hasCred 用。
|
|
51
|
+
_agentRuntimePromise ??= import('openclaw/plugin-sdk/agent-runtime');
|
|
52
|
+
return _agentRuntimePromise;
|
|
53
|
+
}
|
|
54
|
+
|
|
48
55
|
/**
|
|
49
56
|
* 测试辅助:清掉懒加载 SDK 缓存。
|
|
50
57
|
*/
|
|
@@ -52,6 +59,7 @@ export function __resetSdkCache() {
|
|
|
52
59
|
_sdkPromise = undefined;
|
|
53
60
|
_configMutationPromise = undefined;
|
|
54
61
|
_catalogRuntimePromise = undefined;
|
|
62
|
+
_agentRuntimePromise = undefined;
|
|
55
63
|
}
|
|
56
64
|
|
|
57
65
|
/**
|
|
@@ -65,7 +73,8 @@ export function __resetSdkCache() {
|
|
|
65
73
|
* @param {Function} [opts.resolveAgentDir] - 覆盖 agentDir 解析(默认 mainAgentDir)
|
|
66
74
|
* @param {Function} [opts.loadSdk] - 必传(生产由入口注入字面量 dynamic import);缺省回退仅为测试兜底
|
|
67
75
|
* @param {Function} [opts.loadConfigMutation] - 必传(同上,OAuth 写 cfg 用)
|
|
68
|
-
* @param {Function} [opts.loadProviderCatalogRuntime] - 必传(同上,通用 device-code 登录 B1
|
|
76
|
+
* @param {Function} [opts.loadProviderCatalogRuntime] - 必传(同上,通用 device-code 登录 B1 + catalog setup 全集拿 resolvePluginProviders 用)
|
|
77
|
+
* @param {Function} [opts.loadAgentRuntime] - 必传(同上,catalog 算 hasCred 拿 resolveProviderIdForAuth 用)
|
|
69
78
|
* @param {object} [opts.registry] - 覆盖 oauth-registry(默认模块级单例)
|
|
70
79
|
*/
|
|
71
80
|
export function registerProviderAuthHandlers(api, opts = {}) {
|
|
@@ -73,9 +82,10 @@ export function registerProviderAuthHandlers(api, opts = {}) {
|
|
|
73
82
|
const loadSdk = opts.loadSdk ?? defaultLoadSdk;
|
|
74
83
|
const loadConfigMutation = opts.loadConfigMutation ?? defaultLoadConfigMutation;
|
|
75
84
|
const loadProviderCatalogRuntime = opts.loadProviderCatalogRuntime ?? defaultLoadProviderCatalogRuntime;
|
|
85
|
+
const loadAgentRuntime = opts.loadAgentRuntime ?? defaultLoadAgentRuntime;
|
|
76
86
|
const registry = opts.registry ?? { registerLogin, getLogin, removeLogin };
|
|
77
87
|
|
|
78
|
-
// catalog-runtime 仅通用 device-code 登录(B1
|
|
88
|
+
// catalog-runtime 仅通用 device-code 登录(B1)与 catalog 才需要,独立惰性加载——不耦合进 getHandlers
|
|
79
89
|
// 的 Promise.all,避免 setApiKey / list / remove / minimax-oauth 因这个 SDK 子入口缺失而连带失败。
|
|
80
90
|
let catalogRuntimePromise;
|
|
81
91
|
const resolveProviders = async ({ config, providerRefs }) => {
|
|
@@ -89,6 +99,25 @@ export function registerProviderAuthHandlers(api, opts = {}) {
|
|
|
89
99
|
mode: 'runtime',
|
|
90
100
|
});
|
|
91
101
|
};
|
|
102
|
+
// catalog 用的 setup 全集解析(独立于上面的 runtime 闭包——B1 登录仍走 runtime):
|
|
103
|
+
// mode:'setup' 无条件返回全部 provider(含未配过的),activate:false 零副作用、cache:true 复用发现缓存。
|
|
104
|
+
const resolveSetupProviders = async ({ config }) => {
|
|
105
|
+
catalogRuntimePromise ??= loadProviderCatalogRuntime();
|
|
106
|
+
const catalogRuntime = await catalogRuntimePromise;
|
|
107
|
+
return catalogRuntime.resolvePluginProviders({
|
|
108
|
+
config,
|
|
109
|
+
activate: false,
|
|
110
|
+
cache: true,
|
|
111
|
+
mode: 'setup',
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
// agent-runtime 同样独立惰性加载(仅 catalog 的 hasCred 别名归一才需要),不耦合进 getHandlers。
|
|
115
|
+
let agentRuntimePromise;
|
|
116
|
+
const loadProviderIdResolver = async () => {
|
|
117
|
+
agentRuntimePromise ??= loadAgentRuntime();
|
|
118
|
+
const agentRuntime = await agentRuntimePromise;
|
|
119
|
+
return agentRuntime.resolveProviderIdForAuth;
|
|
120
|
+
};
|
|
92
121
|
|
|
93
122
|
let handlersPromise;
|
|
94
123
|
async function getHandlers() {
|
|
@@ -107,7 +136,15 @@ export function registerProviderAuthHandlers(api, opts = {}) {
|
|
|
107
136
|
generatePkce: providerAuthSdk.generatePkceVerifierChallenge,
|
|
108
137
|
toForm: providerAuthSdk.toFormUrlEncoded,
|
|
109
138
|
});
|
|
110
|
-
return buildProviderAuthHandlers({
|
|
139
|
+
return buildProviderAuthHandlers({
|
|
140
|
+
sdk,
|
|
141
|
+
resolveAgentDir,
|
|
142
|
+
oauth,
|
|
143
|
+
registry,
|
|
144
|
+
resolveProviders,
|
|
145
|
+
resolveSetupProviders,
|
|
146
|
+
loadProviderIdResolver,
|
|
147
|
+
});
|
|
111
148
|
})();
|
|
112
149
|
}
|
|
113
150
|
return handlersPromise;
|
|
@@ -136,4 +173,5 @@ export function registerProviderAuthHandlers(api, opts = {}) {
|
|
|
136
173
|
api.registerGatewayMethod('coclaw.providerAuth.remove', wrap('remove'));
|
|
137
174
|
api.registerGatewayMethod('coclaw.providerAuth.loginOauth', wrap('loginOauth'));
|
|
138
175
|
api.registerGatewayMethod('coclaw.providerAuth.cancelOauth', wrap('cancelOauth'));
|
|
176
|
+
api.registerGatewayMethod('coclaw.providerAuth.catalog', wrap('catalog'));
|
|
139
177
|
}
|