@openclaw/qwen-provider 0.0.0 → 2026.6.9-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -2
- package/dist/api.js +4 -0
- package/dist/index.js +201 -0
- package/dist/media-understanding-provider.js +67 -0
- package/dist/model-definitions.js +2 -0
- package/dist/models.js +175 -0
- package/dist/onboard.js +53 -0
- package/dist/provider-catalog.js +20 -0
- package/dist/stream.js +85 -0
- package/dist/video-generation-provider.js +76 -0
- package/npm-shrinkwrap.json +12 -0
- package/openclaw.plugin.json +325 -0
- package/package.json +44 -8
package/README.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
-
#
|
|
1
|
+
# OpenClaw Qwen Cloud Provider
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Official OpenClaw provider plugin for Qwen Cloud.
|
|
4
|
+
|
|
5
|
+
Install from OpenClaw:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
openclaw plugins install @openclaw/qwen-provider
|
|
9
|
+
openclaw gateway restart
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
See <https://docs.openclaw.ai/providers/qwen> for setup and configuration.
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MODELSTUDIO_BASE_URL, MODELSTUDIO_CN_BASE_URL, MODELSTUDIO_DEFAULT_COST, MODELSTUDIO_DEFAULT_MODEL_ID, MODELSTUDIO_DEFAULT_MODEL_REF, MODELSTUDIO_GLOBAL_BASE_URL, MODELSTUDIO_MODEL_CATALOG, MODELSTUDIO_STANDARD_CN_BASE_URL, MODELSTUDIO_STANDARD_GLOBAL_BASE_URL, QWEN_36_PLUS_MODEL_ID, QWEN_BASE_URL, QWEN_CN_BASE_URL, QWEN_DEFAULT_COST, QWEN_DEFAULT_MODEL_ID, QWEN_DEFAULT_MODEL_REF, QWEN_GLOBAL_BASE_URL, QWEN_MODEL_CATALOG, QWEN_STANDARD_CN_BASE_URL, QWEN_STANDARD_GLOBAL_BASE_URL, applyModelStudioNativeStreamingUsageCompat, applyQwenNativeStreamingUsageCompat, buildModelStudioDefaultModelDefinition, buildModelStudioModelDefinition, buildQwenDefaultModelDefinition, buildQwenModelCatalogForBaseUrl, buildQwenModelDefinition, isNativeModelStudioBaseUrl, isNativeQwenBaseUrl, isQwen36PlusSupportedBaseUrl, isQwenCodingPlanBaseUrl } from "./models.js";
|
|
2
|
+
import { buildModelStudioProvider, buildQwenProvider } from "./provider-catalog.js";
|
|
3
|
+
import { createQwenThinkingWrapper, wrapQwenProviderStream } from "./stream.js";
|
|
4
|
+
export { MODELSTUDIO_BASE_URL, MODELSTUDIO_CN_BASE_URL, MODELSTUDIO_DEFAULT_COST, MODELSTUDIO_DEFAULT_MODEL_ID, MODELSTUDIO_DEFAULT_MODEL_REF, MODELSTUDIO_GLOBAL_BASE_URL, MODELSTUDIO_MODEL_CATALOG, MODELSTUDIO_STANDARD_CN_BASE_URL, MODELSTUDIO_STANDARD_GLOBAL_BASE_URL, QWEN_36_PLUS_MODEL_ID, QWEN_BASE_URL, QWEN_CN_BASE_URL, QWEN_DEFAULT_COST, QWEN_DEFAULT_MODEL_ID, QWEN_DEFAULT_MODEL_REF, QWEN_GLOBAL_BASE_URL, QWEN_MODEL_CATALOG, QWEN_STANDARD_CN_BASE_URL, QWEN_STANDARD_GLOBAL_BASE_URL, applyModelStudioNativeStreamingUsageCompat, applyQwenNativeStreamingUsageCompat, buildModelStudioDefaultModelDefinition, buildModelStudioModelDefinition, buildModelStudioProvider, buildQwenDefaultModelDefinition, buildQwenModelCatalogForBaseUrl, buildQwenModelDefinition, buildQwenProvider, createQwenThinkingWrapper, isNativeModelStudioBaseUrl, isNativeQwenBaseUrl, isQwen36PlusSupportedBaseUrl, isQwenCodingPlanBaseUrl, wrapQwenProviderStream };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { QWEN_36_PLUS_MODEL_ID, QWEN_DEFAULT_MODEL_REF, QWEN_OAUTH_DEFAULT_MODEL_REF, QWEN_OAUTH_PROVIDER_ID, applyQwenNativeStreamingUsageCompat, isQwenCodingPlanBaseUrl } from "./models.js";
|
|
2
|
+
import { buildQwenOAuthProvider, buildQwenProvider } from "./provider-catalog.js";
|
|
3
|
+
import { wrapQwenProviderStream } from "./stream.js";
|
|
4
|
+
import "./api.js";
|
|
5
|
+
import { buildQwenMediaUnderstandingProvider } from "./media-understanding-provider.js";
|
|
6
|
+
import { applyQwenConfig, applyQwenConfigCn, applyQwenOAuthConfig, applyQwenStandardConfig, applyQwenStandardConfigCn } from "./onboard.js";
|
|
7
|
+
import { buildQwenVideoGenerationProvider } from "./video-generation-provider.js";
|
|
8
|
+
import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth-api-key";
|
|
9
|
+
import { defineSingleProviderPluginEntry } from "openclaw/plugin-sdk/provider-entry";
|
|
10
|
+
//#region extensions/qwen/index.ts
|
|
11
|
+
const PROVIDER_ID = "qwen";
|
|
12
|
+
const LEGACY_PROVIDER_ID = "modelstudio";
|
|
13
|
+
const QWEN_OAUTH_AUTH_PROVIDER_IDS = [
|
|
14
|
+
QWEN_OAUTH_PROVIDER_ID,
|
|
15
|
+
"qwen-portal",
|
|
16
|
+
"qwen-cli"
|
|
17
|
+
];
|
|
18
|
+
function normalizeProviderId(value) {
|
|
19
|
+
return value.trim().toLowerCase();
|
|
20
|
+
}
|
|
21
|
+
function resolveConfiguredQwenBaseUrl(config) {
|
|
22
|
+
const providers = config?.models?.providers;
|
|
23
|
+
if (!providers) return;
|
|
24
|
+
for (const [providerId, provider] of Object.entries(providers)) {
|
|
25
|
+
const normalized = normalizeProviderId(providerId);
|
|
26
|
+
if (normalized !== PROVIDER_ID && normalized !== LEGACY_PROVIDER_ID) continue;
|
|
27
|
+
const baseUrl = provider?.baseUrl?.trim();
|
|
28
|
+
if (baseUrl) return baseUrl;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
var qwen_default = defineSingleProviderPluginEntry({
|
|
32
|
+
id: PROVIDER_ID,
|
|
33
|
+
name: "Qwen Provider",
|
|
34
|
+
description: "Bundled Qwen Cloud provider plugin",
|
|
35
|
+
provider: {
|
|
36
|
+
label: "Qwen Cloud",
|
|
37
|
+
docsPath: "/providers/qwen",
|
|
38
|
+
aliases: ["modelstudio", "qwencloud"],
|
|
39
|
+
auth: [
|
|
40
|
+
{
|
|
41
|
+
methodId: "standard-api-key-cn",
|
|
42
|
+
label: "Standard API Key for China (pay-as-you-go)",
|
|
43
|
+
hint: "Endpoint: dashscope.aliyuncs.com",
|
|
44
|
+
optionKey: "modelstudioStandardApiKeyCn",
|
|
45
|
+
flagName: "--modelstudio-standard-api-key-cn",
|
|
46
|
+
envVar: "QWEN_API_KEY",
|
|
47
|
+
promptMessage: "Enter Qwen Cloud API key (China standard endpoint)",
|
|
48
|
+
defaultModel: QWEN_DEFAULT_MODEL_REF,
|
|
49
|
+
applyConfig: (cfg) => applyQwenStandardConfigCn(cfg),
|
|
50
|
+
noteMessage: [
|
|
51
|
+
"Manage API keys: https://home.qwencloud.com/api-keys",
|
|
52
|
+
"Docs: https://docs.qwencloud.com/",
|
|
53
|
+
"Endpoint: dashscope.aliyuncs.com/compatible-mode/v1",
|
|
54
|
+
"Models: qwen3.6-plus, qwen3.5-plus, qwen3-coder-plus, etc."
|
|
55
|
+
].join("\n"),
|
|
56
|
+
noteTitle: "Qwen Cloud Standard (China)",
|
|
57
|
+
wizard: {
|
|
58
|
+
choiceHint: "Endpoint: dashscope.aliyuncs.com",
|
|
59
|
+
groupLabel: "Qwen Cloud",
|
|
60
|
+
groupHint: "Standard / Coding Plan (CN / Global) + multimodal roadmap"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
methodId: "standard-api-key",
|
|
65
|
+
label: "Standard API Key for Global/Intl (pay-as-you-go)",
|
|
66
|
+
hint: "Endpoint: dashscope-intl.aliyuncs.com",
|
|
67
|
+
optionKey: "modelstudioStandardApiKey",
|
|
68
|
+
flagName: "--modelstudio-standard-api-key",
|
|
69
|
+
envVar: "QWEN_API_KEY",
|
|
70
|
+
promptMessage: "Enter Qwen Cloud API key (Global/Intl standard endpoint)",
|
|
71
|
+
defaultModel: QWEN_DEFAULT_MODEL_REF,
|
|
72
|
+
applyConfig: (cfg) => applyQwenStandardConfig(cfg),
|
|
73
|
+
noteMessage: [
|
|
74
|
+
"Manage API keys: https://home.qwencloud.com/api-keys",
|
|
75
|
+
"Docs: https://docs.qwencloud.com/",
|
|
76
|
+
"Endpoint: dashscope-intl.aliyuncs.com/compatible-mode/v1",
|
|
77
|
+
"Models: qwen3.6-plus, qwen3.5-plus, qwen3-coder-plus, etc."
|
|
78
|
+
].join("\n"),
|
|
79
|
+
noteTitle: "Qwen Cloud Standard (Global/Intl)",
|
|
80
|
+
wizard: {
|
|
81
|
+
choiceHint: "Endpoint: dashscope-intl.aliyuncs.com",
|
|
82
|
+
groupLabel: "Qwen Cloud",
|
|
83
|
+
groupHint: "Standard / Coding Plan (CN / Global) + multimodal roadmap"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
methodId: "api-key-cn",
|
|
88
|
+
label: "Coding Plan API Key for China (subscription)",
|
|
89
|
+
hint: "Endpoint: coding.dashscope.aliyuncs.com",
|
|
90
|
+
optionKey: "modelstudioApiKeyCn",
|
|
91
|
+
flagName: "--modelstudio-api-key-cn",
|
|
92
|
+
envVar: "QWEN_API_KEY",
|
|
93
|
+
promptMessage: "Enter Qwen Cloud Coding Plan API key (China)",
|
|
94
|
+
defaultModel: QWEN_DEFAULT_MODEL_REF,
|
|
95
|
+
applyConfig: (cfg) => applyQwenConfigCn(cfg),
|
|
96
|
+
noteMessage: [
|
|
97
|
+
"Manage API keys: https://home.qwencloud.com/api-keys",
|
|
98
|
+
"Docs: https://docs.qwencloud.com/",
|
|
99
|
+
"Endpoint: coding.dashscope.aliyuncs.com",
|
|
100
|
+
"Models: qwen3.5-plus, glm-5, kimi-k2.5, MiniMax-M2.5, etc."
|
|
101
|
+
].join("\n"),
|
|
102
|
+
noteTitle: "Qwen Cloud Coding Plan (China)",
|
|
103
|
+
wizard: {
|
|
104
|
+
choiceHint: "Endpoint: coding.dashscope.aliyuncs.com",
|
|
105
|
+
groupLabel: "Qwen Cloud",
|
|
106
|
+
groupHint: "Standard / Coding Plan (CN / Global) + multimodal roadmap"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
methodId: "api-key",
|
|
111
|
+
label: "Coding Plan API Key for Global/Intl (subscription)",
|
|
112
|
+
hint: "Endpoint: coding-intl.dashscope.aliyuncs.com",
|
|
113
|
+
optionKey: "modelstudioApiKey",
|
|
114
|
+
flagName: "--modelstudio-api-key",
|
|
115
|
+
envVar: "QWEN_API_KEY",
|
|
116
|
+
promptMessage: "Enter Qwen Cloud Coding Plan API key (Global/Intl)",
|
|
117
|
+
defaultModel: QWEN_DEFAULT_MODEL_REF,
|
|
118
|
+
applyConfig: (cfg) => applyQwenConfig(cfg),
|
|
119
|
+
noteMessage: [
|
|
120
|
+
"Manage API keys: https://home.qwencloud.com/api-keys",
|
|
121
|
+
"Docs: https://docs.qwencloud.com/",
|
|
122
|
+
"Endpoint: coding-intl.dashscope.aliyuncs.com",
|
|
123
|
+
"Models: qwen3.5-plus, glm-5, kimi-k2.5, MiniMax-M2.5, etc."
|
|
124
|
+
].join("\n"),
|
|
125
|
+
noteTitle: "Qwen Cloud Coding Plan (Global/Intl)",
|
|
126
|
+
wizard: {
|
|
127
|
+
choiceHint: "Endpoint: coding-intl.dashscope.aliyuncs.com",
|
|
128
|
+
groupLabel: "Qwen Cloud",
|
|
129
|
+
groupHint: "Standard / Coding Plan (CN / Global) + multimodal roadmap"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
],
|
|
133
|
+
catalog: { run: async (ctx) => {
|
|
134
|
+
const apiKey = ctx.resolveProviderApiKey(PROVIDER_ID).apiKey;
|
|
135
|
+
if (!apiKey) return null;
|
|
136
|
+
return { provider: {
|
|
137
|
+
...buildQwenProvider({ baseUrl: resolveConfiguredQwenBaseUrl(ctx.config) ?? "https://coding-intl.dashscope.aliyuncs.com/v1" }),
|
|
138
|
+
apiKey
|
|
139
|
+
} };
|
|
140
|
+
} },
|
|
141
|
+
applyNativeStreamingUsageCompat: ({ providerConfig }) => applyQwenNativeStreamingUsageCompat(providerConfig),
|
|
142
|
+
wrapStreamFn: wrapQwenProviderStream,
|
|
143
|
+
normalizeConfig: ({ providerConfig }) => {
|
|
144
|
+
if (!isQwenCodingPlanBaseUrl(providerConfig.baseUrl)) return;
|
|
145
|
+
const models = providerConfig.models?.filter((model) => model.id !== QWEN_36_PLUS_MODEL_ID);
|
|
146
|
+
return models && models.length !== providerConfig.models?.length ? {
|
|
147
|
+
...providerConfig,
|
|
148
|
+
models
|
|
149
|
+
} : void 0;
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
register(api) {
|
|
153
|
+
api.registerProvider({
|
|
154
|
+
id: QWEN_OAUTH_PROVIDER_ID,
|
|
155
|
+
label: "Qwen OAuth",
|
|
156
|
+
docsPath: "/providers/qwen",
|
|
157
|
+
aliases: ["qwen-portal", "qwen-cli"],
|
|
158
|
+
envVars: ["QWEN_API_KEY"],
|
|
159
|
+
auth: [createProviderApiKeyAuthMethod({
|
|
160
|
+
providerId: QWEN_OAUTH_PROVIDER_ID,
|
|
161
|
+
methodId: "api-key",
|
|
162
|
+
label: "Qwen OAuth token",
|
|
163
|
+
hint: "Portal token for portal.qwen.ai",
|
|
164
|
+
optionKey: "qwenOauthToken",
|
|
165
|
+
flagName: "--qwen-oauth-token",
|
|
166
|
+
envVar: "QWEN_API_KEY",
|
|
167
|
+
promptMessage: "Enter Qwen OAuth token",
|
|
168
|
+
defaultModel: QWEN_OAUTH_DEFAULT_MODEL_REF,
|
|
169
|
+
applyConfig: (cfg) => applyQwenOAuthConfig(cfg),
|
|
170
|
+
wizard: {
|
|
171
|
+
choiceId: QWEN_OAUTH_PROVIDER_ID,
|
|
172
|
+
choiceLabel: "Qwen OAuth",
|
|
173
|
+
choiceHint: "Portal token for portal.qwen.ai",
|
|
174
|
+
groupId: "qwen",
|
|
175
|
+
groupLabel: "Qwen Cloud",
|
|
176
|
+
groupHint: "Standard / Coding Plan / OAuth"
|
|
177
|
+
}
|
|
178
|
+
})],
|
|
179
|
+
catalog: {
|
|
180
|
+
order: "simple",
|
|
181
|
+
run: async (ctx) => {
|
|
182
|
+
const apiKey = QWEN_OAUTH_AUTH_PROVIDER_IDS.map((providerId) => ctx.resolveProviderApiKey(providerId).apiKey).find((candidate) => typeof candidate === "string" && candidate.length > 0);
|
|
183
|
+
if (!apiKey) return null;
|
|
184
|
+
return { provider: {
|
|
185
|
+
...buildQwenOAuthProvider(),
|
|
186
|
+
apiKey
|
|
187
|
+
} };
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
staticCatalog: {
|
|
191
|
+
order: "simple",
|
|
192
|
+
run: async () => ({ provider: buildQwenOAuthProvider() })
|
|
193
|
+
},
|
|
194
|
+
wrapStreamFn: wrapQwenProviderStream
|
|
195
|
+
});
|
|
196
|
+
api.registerMediaUnderstandingProvider(buildQwenMediaUnderstandingProvider());
|
|
197
|
+
api.registerVideoGenerationProvider(buildQwenVideoGenerationProvider());
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
//#endregion
|
|
201
|
+
export { qwen_default as default };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { QWEN_STANDARD_GLOBAL_BASE_URL } from "./models.js";
|
|
2
|
+
import { buildOpenAiCompatibleVideoRequestBody, coerceOpenAiCompatibleVideoText, describeImageWithModel, describeImagesWithModel, resolveMediaUnderstandingString } from "openclaw/plugin-sdk/media-understanding";
|
|
3
|
+
import { assertOkOrThrowHttpError, postJsonRequest, resolveProviderHttpRequestConfig } from "openclaw/plugin-sdk/provider-http";
|
|
4
|
+
//#region extensions/qwen/media-understanding-provider.ts
|
|
5
|
+
const DEFAULT_QWEN_VIDEO_MODEL = "qwen-vl-max-latest";
|
|
6
|
+
const DEFAULT_QWEN_VIDEO_PROMPT = "Describe the video in detail.";
|
|
7
|
+
async function describeQwenVideo(params) {
|
|
8
|
+
const fetchFn = params.fetchFn ?? fetch;
|
|
9
|
+
const model = resolveMediaUnderstandingString(params.model, DEFAULT_QWEN_VIDEO_MODEL);
|
|
10
|
+
const mime = resolveMediaUnderstandingString(params.mime, "video/mp4");
|
|
11
|
+
const prompt = resolveMediaUnderstandingString(params.prompt, DEFAULT_QWEN_VIDEO_PROMPT);
|
|
12
|
+
const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } = resolveProviderHttpRequestConfig({
|
|
13
|
+
baseUrl: params.baseUrl,
|
|
14
|
+
defaultBaseUrl: QWEN_STANDARD_GLOBAL_BASE_URL,
|
|
15
|
+
headers: params.headers,
|
|
16
|
+
request: params.request,
|
|
17
|
+
defaultHeaders: {
|
|
18
|
+
"content-type": "application/json",
|
|
19
|
+
authorization: `Bearer ${params.apiKey}`
|
|
20
|
+
},
|
|
21
|
+
provider: "qwen",
|
|
22
|
+
api: "openai-completions",
|
|
23
|
+
capability: "video",
|
|
24
|
+
transport: "media-understanding"
|
|
25
|
+
});
|
|
26
|
+
const { response: res, release } = await postJsonRequest({
|
|
27
|
+
url: `${baseUrl}/chat/completions`,
|
|
28
|
+
headers,
|
|
29
|
+
body: buildOpenAiCompatibleVideoRequestBody({
|
|
30
|
+
model,
|
|
31
|
+
prompt,
|
|
32
|
+
mime,
|
|
33
|
+
buffer: params.buffer
|
|
34
|
+
}),
|
|
35
|
+
timeoutMs: params.timeoutMs,
|
|
36
|
+
fetchFn,
|
|
37
|
+
allowPrivateNetwork,
|
|
38
|
+
dispatcherPolicy
|
|
39
|
+
});
|
|
40
|
+
try {
|
|
41
|
+
await assertOkOrThrowHttpError(res, "Qwen video description failed");
|
|
42
|
+
const text = coerceOpenAiCompatibleVideoText(await res.json());
|
|
43
|
+
if (!text) throw new Error("Qwen video description response missing content");
|
|
44
|
+
return {
|
|
45
|
+
text,
|
|
46
|
+
model
|
|
47
|
+
};
|
|
48
|
+
} finally {
|
|
49
|
+
await release();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function buildQwenMediaUnderstandingProvider() {
|
|
53
|
+
return {
|
|
54
|
+
id: "qwen",
|
|
55
|
+
capabilities: ["image", "video"],
|
|
56
|
+
defaultModels: {
|
|
57
|
+
image: "qwen-vl-max-latest",
|
|
58
|
+
video: DEFAULT_QWEN_VIDEO_MODEL
|
|
59
|
+
},
|
|
60
|
+
autoPriority: { video: 15 },
|
|
61
|
+
describeImage: describeImageWithModel,
|
|
62
|
+
describeImages: describeImagesWithModel,
|
|
63
|
+
describeVideo: describeQwenVideo
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { buildQwenMediaUnderstandingProvider, describeQwenVideo };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { MODELSTUDIO_CN_BASE_URL, MODELSTUDIO_DEFAULT_COST, MODELSTUDIO_DEFAULT_MODEL_ID, MODELSTUDIO_DEFAULT_MODEL_REF, MODELSTUDIO_GLOBAL_BASE_URL, MODELSTUDIO_STANDARD_CN_BASE_URL, MODELSTUDIO_STANDARD_GLOBAL_BASE_URL, QWEN_CN_BASE_URL, QWEN_DEFAULT_COST, QWEN_DEFAULT_MODEL_ID, QWEN_DEFAULT_MODEL_REF, QWEN_GLOBAL_BASE_URL, QWEN_STANDARD_CN_BASE_URL, QWEN_STANDARD_GLOBAL_BASE_URL, buildModelStudioDefaultModelDefinition, buildModelStudioModelDefinition, buildQwenDefaultModelDefinition, buildQwenModelDefinition } from "./models.js";
|
|
2
|
+
export { MODELSTUDIO_CN_BASE_URL, MODELSTUDIO_DEFAULT_COST, MODELSTUDIO_DEFAULT_MODEL_ID, MODELSTUDIO_DEFAULT_MODEL_REF, MODELSTUDIO_GLOBAL_BASE_URL, MODELSTUDIO_STANDARD_CN_BASE_URL, MODELSTUDIO_STANDARD_GLOBAL_BASE_URL, QWEN_CN_BASE_URL, QWEN_DEFAULT_COST, QWEN_DEFAULT_MODEL_ID, QWEN_DEFAULT_MODEL_REF, QWEN_GLOBAL_BASE_URL, QWEN_STANDARD_CN_BASE_URL, QWEN_STANDARD_GLOBAL_BASE_URL, buildModelStudioDefaultModelDefinition, buildModelStudioModelDefinition, buildQwenDefaultModelDefinition, buildQwenModelDefinition };
|
package/dist/models.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { applyProviderNativeStreamingUsageCompat, supportsNativeStreamingUsageCompat } from "openclaw/plugin-sdk/provider-catalog-shared";
|
|
2
|
+
//#region extensions/qwen/models.ts
|
|
3
|
+
const QWEN_BASE_URL = "https://coding-intl.dashscope.aliyuncs.com/v1";
|
|
4
|
+
const QWEN_GLOBAL_BASE_URL = QWEN_BASE_URL;
|
|
5
|
+
const QWEN_CN_BASE_URL = "https://coding.dashscope.aliyuncs.com/v1";
|
|
6
|
+
const QWEN_STANDARD_CN_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
|
|
7
|
+
const QWEN_STANDARD_GLOBAL_BASE_URL = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1";
|
|
8
|
+
const QWEN_OAUTH_PROVIDER_ID = "qwen-oauth";
|
|
9
|
+
const QWEN_OAUTH_BASE_URL = "https://portal.qwen.ai/v1";
|
|
10
|
+
const QWEN_DEFAULT_MODEL_ID = "qwen3.5-plus";
|
|
11
|
+
const QWEN_36_PLUS_MODEL_ID = "qwen3.6-plus";
|
|
12
|
+
const QWEN_DEFAULT_COST = {
|
|
13
|
+
input: 0,
|
|
14
|
+
output: 0,
|
|
15
|
+
cacheRead: 0,
|
|
16
|
+
cacheWrite: 0
|
|
17
|
+
};
|
|
18
|
+
const QWEN_DEFAULT_MODEL_REF = `qwen/${QWEN_DEFAULT_MODEL_ID}`;
|
|
19
|
+
const QWEN_OAUTH_DEFAULT_MODEL_REF = `qwen-oauth/${QWEN_DEFAULT_MODEL_ID}`;
|
|
20
|
+
const QWEN_MODEL_CATALOG = [
|
|
21
|
+
{
|
|
22
|
+
id: "qwen3.5-plus",
|
|
23
|
+
name: "qwen3.5-plus",
|
|
24
|
+
reasoning: false,
|
|
25
|
+
input: ["text", "image"],
|
|
26
|
+
cost: QWEN_DEFAULT_COST,
|
|
27
|
+
contextWindow: 1e6,
|
|
28
|
+
maxTokens: 65536
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: QWEN_36_PLUS_MODEL_ID,
|
|
32
|
+
name: QWEN_36_PLUS_MODEL_ID,
|
|
33
|
+
reasoning: false,
|
|
34
|
+
input: ["text", "image"],
|
|
35
|
+
cost: QWEN_DEFAULT_COST,
|
|
36
|
+
contextWindow: 1e6,
|
|
37
|
+
maxTokens: 65536
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "qwen3-max-2026-01-23",
|
|
41
|
+
name: "qwen3-max-2026-01-23",
|
|
42
|
+
reasoning: false,
|
|
43
|
+
input: ["text"],
|
|
44
|
+
cost: QWEN_DEFAULT_COST,
|
|
45
|
+
contextWindow: 262144,
|
|
46
|
+
maxTokens: 65536
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: "qwen3-coder-next",
|
|
50
|
+
name: "qwen3-coder-next",
|
|
51
|
+
reasoning: false,
|
|
52
|
+
input: ["text"],
|
|
53
|
+
cost: QWEN_DEFAULT_COST,
|
|
54
|
+
contextWindow: 262144,
|
|
55
|
+
maxTokens: 65536
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "qwen3-coder-plus",
|
|
59
|
+
name: "qwen3-coder-plus",
|
|
60
|
+
reasoning: false,
|
|
61
|
+
input: ["text"],
|
|
62
|
+
cost: QWEN_DEFAULT_COST,
|
|
63
|
+
contextWindow: 1e6,
|
|
64
|
+
maxTokens: 65536
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: "MiniMax-M2.5",
|
|
68
|
+
name: "MiniMax-M2.5",
|
|
69
|
+
reasoning: true,
|
|
70
|
+
input: ["text"],
|
|
71
|
+
cost: QWEN_DEFAULT_COST,
|
|
72
|
+
contextWindow: 1e6,
|
|
73
|
+
maxTokens: 65536
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: "glm-5",
|
|
77
|
+
name: "glm-5",
|
|
78
|
+
reasoning: false,
|
|
79
|
+
input: ["text"],
|
|
80
|
+
cost: QWEN_DEFAULT_COST,
|
|
81
|
+
contextWindow: 202752,
|
|
82
|
+
maxTokens: 16384
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: "glm-4.7",
|
|
86
|
+
name: "glm-4.7",
|
|
87
|
+
reasoning: false,
|
|
88
|
+
input: ["text"],
|
|
89
|
+
cost: QWEN_DEFAULT_COST,
|
|
90
|
+
contextWindow: 202752,
|
|
91
|
+
maxTokens: 16384
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
id: "kimi-k2.5",
|
|
95
|
+
name: "kimi-k2.5",
|
|
96
|
+
reasoning: false,
|
|
97
|
+
input: ["text", "image"],
|
|
98
|
+
cost: QWEN_DEFAULT_COST,
|
|
99
|
+
contextWindow: 262144,
|
|
100
|
+
maxTokens: 32768
|
|
101
|
+
}
|
|
102
|
+
];
|
|
103
|
+
function isQwenCodingPlanBaseUrl(baseUrl) {
|
|
104
|
+
const trimmed = baseUrl?.trim();
|
|
105
|
+
if (!trimmed) return false;
|
|
106
|
+
try {
|
|
107
|
+
const hostname = new URL(trimmed).hostname.toLowerCase().replace(/\.+$/, "");
|
|
108
|
+
return hostname === "coding.dashscope.aliyuncs.com" || hostname === "coding-intl.dashscope.aliyuncs.com";
|
|
109
|
+
} catch {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function isQwen36PlusSupportedBaseUrl(baseUrl) {
|
|
114
|
+
return !isQwenCodingPlanBaseUrl(baseUrl);
|
|
115
|
+
}
|
|
116
|
+
function buildQwenModelCatalogForBaseUrl(baseUrl) {
|
|
117
|
+
return isQwen36PlusSupportedBaseUrl(baseUrl) ? QWEN_MODEL_CATALOG : QWEN_MODEL_CATALOG.filter((model) => model.id !== QWEN_36_PLUS_MODEL_ID);
|
|
118
|
+
}
|
|
119
|
+
function isNativeQwenBaseUrl(baseUrl) {
|
|
120
|
+
return supportsNativeStreamingUsageCompat({
|
|
121
|
+
providerId: "qwen",
|
|
122
|
+
baseUrl
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function applyQwenNativeStreamingUsageCompat(provider) {
|
|
126
|
+
return applyProviderNativeStreamingUsageCompat({
|
|
127
|
+
providerId: "qwen",
|
|
128
|
+
providerConfig: provider
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function buildQwenModelDefinition(params) {
|
|
132
|
+
const catalog = QWEN_MODEL_CATALOG.find((model) => model.id === params.id);
|
|
133
|
+
return {
|
|
134
|
+
id: params.id,
|
|
135
|
+
name: params.name ?? catalog?.name ?? params.id,
|
|
136
|
+
reasoning: params.reasoning ?? catalog?.reasoning ?? false,
|
|
137
|
+
input: params.input ?? (catalog?.input ? [...catalog.input] : ["text"]),
|
|
138
|
+
cost: params.cost ?? catalog?.cost ?? QWEN_DEFAULT_COST,
|
|
139
|
+
contextWindow: params.contextWindow ?? catalog?.contextWindow ?? 262144,
|
|
140
|
+
maxTokens: params.maxTokens ?? catalog?.maxTokens ?? 65536
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function buildQwenDefaultModelDefinition() {
|
|
144
|
+
return buildQwenModelDefinition({ id: QWEN_DEFAULT_MODEL_ID });
|
|
145
|
+
}
|
|
146
|
+
function buildQwenOAuthModelCatalog() {
|
|
147
|
+
return QWEN_MODEL_CATALOG.map((model) => ({
|
|
148
|
+
...model,
|
|
149
|
+
maxTokens: 65536
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
/** @deprecated Use QWEN_BASE_URL. */
|
|
153
|
+
const MODELSTUDIO_BASE_URL = QWEN_BASE_URL;
|
|
154
|
+
/** @deprecated Use QWEN_GLOBAL_BASE_URL. */
|
|
155
|
+
const MODELSTUDIO_GLOBAL_BASE_URL = QWEN_GLOBAL_BASE_URL;
|
|
156
|
+
/** @deprecated Use QWEN_CN_BASE_URL. */
|
|
157
|
+
const MODELSTUDIO_CN_BASE_URL = QWEN_CN_BASE_URL;
|
|
158
|
+
/** @deprecated Use QWEN_STANDARD_CN_BASE_URL. */
|
|
159
|
+
const MODELSTUDIO_STANDARD_CN_BASE_URL = QWEN_STANDARD_CN_BASE_URL;
|
|
160
|
+
/** @deprecated Use QWEN_STANDARD_GLOBAL_BASE_URL. */
|
|
161
|
+
const MODELSTUDIO_STANDARD_GLOBAL_BASE_URL = QWEN_STANDARD_GLOBAL_BASE_URL;
|
|
162
|
+
/** @deprecated Use QWEN_DEFAULT_MODEL_ID. */
|
|
163
|
+
const MODELSTUDIO_DEFAULT_MODEL_ID = QWEN_DEFAULT_MODEL_ID;
|
|
164
|
+
/** @deprecated Use QWEN_DEFAULT_COST. */
|
|
165
|
+
const MODELSTUDIO_DEFAULT_COST = QWEN_DEFAULT_COST;
|
|
166
|
+
/** @deprecated Use qwen/${QWEN_DEFAULT_MODEL_ID}. */
|
|
167
|
+
const MODELSTUDIO_DEFAULT_MODEL_REF = `modelstudio/${QWEN_DEFAULT_MODEL_ID}`;
|
|
168
|
+
/** @deprecated Use QWEN_MODEL_CATALOG. */
|
|
169
|
+
const MODELSTUDIO_MODEL_CATALOG = QWEN_MODEL_CATALOG;
|
|
170
|
+
const isNativeModelStudioBaseUrl = isNativeQwenBaseUrl;
|
|
171
|
+
const applyModelStudioNativeStreamingUsageCompat = applyQwenNativeStreamingUsageCompat;
|
|
172
|
+
const buildModelStudioModelDefinition = buildQwenModelDefinition;
|
|
173
|
+
const buildModelStudioDefaultModelDefinition = buildQwenDefaultModelDefinition;
|
|
174
|
+
//#endregion
|
|
175
|
+
export { MODELSTUDIO_BASE_URL, MODELSTUDIO_CN_BASE_URL, MODELSTUDIO_DEFAULT_COST, MODELSTUDIO_DEFAULT_MODEL_ID, MODELSTUDIO_DEFAULT_MODEL_REF, MODELSTUDIO_GLOBAL_BASE_URL, MODELSTUDIO_MODEL_CATALOG, MODELSTUDIO_STANDARD_CN_BASE_URL, MODELSTUDIO_STANDARD_GLOBAL_BASE_URL, QWEN_36_PLUS_MODEL_ID, QWEN_BASE_URL, QWEN_CN_BASE_URL, QWEN_DEFAULT_COST, QWEN_DEFAULT_MODEL_ID, QWEN_DEFAULT_MODEL_REF, QWEN_GLOBAL_BASE_URL, QWEN_MODEL_CATALOG, QWEN_OAUTH_BASE_URL, QWEN_OAUTH_DEFAULT_MODEL_REF, QWEN_OAUTH_PROVIDER_ID, QWEN_STANDARD_CN_BASE_URL, QWEN_STANDARD_GLOBAL_BASE_URL, applyModelStudioNativeStreamingUsageCompat, applyQwenNativeStreamingUsageCompat, buildModelStudioDefaultModelDefinition, buildModelStudioModelDefinition, buildQwenDefaultModelDefinition, buildQwenModelCatalogForBaseUrl, buildQwenModelDefinition, buildQwenOAuthModelCatalog, isNativeModelStudioBaseUrl, isNativeQwenBaseUrl, isQwen36PlusSupportedBaseUrl, isQwenCodingPlanBaseUrl };
|
package/dist/onboard.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { QWEN_CN_BASE_URL, QWEN_DEFAULT_MODEL_REF, QWEN_GLOBAL_BASE_URL, QWEN_OAUTH_DEFAULT_MODEL_REF, QWEN_OAUTH_PROVIDER_ID, QWEN_STANDARD_CN_BASE_URL, QWEN_STANDARD_GLOBAL_BASE_URL } from "./models.js";
|
|
2
|
+
import { buildQwenOAuthProvider, buildQwenProvider } from "./provider-catalog.js";
|
|
3
|
+
import { createModelCatalogPresetAppliers } from "openclaw/plugin-sdk/provider-onboard";
|
|
4
|
+
//#region extensions/qwen/onboard.ts
|
|
5
|
+
const qwenPresetAppliers = createModelCatalogPresetAppliers({
|
|
6
|
+
primaryModelRef: QWEN_DEFAULT_MODEL_REF,
|
|
7
|
+
resolveParams: (_cfg, baseUrl) => {
|
|
8
|
+
const provider = buildQwenProvider({ baseUrl });
|
|
9
|
+
return {
|
|
10
|
+
providerId: "qwen",
|
|
11
|
+
api: provider.api ?? "openai-completions",
|
|
12
|
+
baseUrl,
|
|
13
|
+
catalogModels: provider.models ?? [],
|
|
14
|
+
aliases: [...(provider.models ?? []).flatMap((model) => [`qwen/${model.id}`, `modelstudio/${model.id}`]), {
|
|
15
|
+
modelRef: QWEN_DEFAULT_MODEL_REF,
|
|
16
|
+
alias: "Qwen"
|
|
17
|
+
}]
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
const qwenOAuthPresetAppliers = createModelCatalogPresetAppliers({
|
|
22
|
+
primaryModelRef: QWEN_OAUTH_DEFAULT_MODEL_REF,
|
|
23
|
+
resolveParams: () => {
|
|
24
|
+
const provider = buildQwenOAuthProvider();
|
|
25
|
+
return {
|
|
26
|
+
providerId: QWEN_OAUTH_PROVIDER_ID,
|
|
27
|
+
api: provider.api ?? "openai-completions",
|
|
28
|
+
baseUrl: provider.baseUrl,
|
|
29
|
+
catalogModels: provider.models ?? [],
|
|
30
|
+
aliases: [...(provider.models ?? []).map((model) => `qwen-oauth/${model.id}`), {
|
|
31
|
+
modelRef: QWEN_OAUTH_DEFAULT_MODEL_REF,
|
|
32
|
+
alias: "Qwen OAuth"
|
|
33
|
+
}]
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
function applyQwenConfig(cfg) {
|
|
38
|
+
return qwenPresetAppliers.applyConfig(cfg, QWEN_GLOBAL_BASE_URL);
|
|
39
|
+
}
|
|
40
|
+
function applyQwenConfigCn(cfg) {
|
|
41
|
+
return qwenPresetAppliers.applyConfig(cfg, QWEN_CN_BASE_URL);
|
|
42
|
+
}
|
|
43
|
+
function applyQwenStandardConfig(cfg) {
|
|
44
|
+
return qwenPresetAppliers.applyConfig(cfg, QWEN_STANDARD_GLOBAL_BASE_URL);
|
|
45
|
+
}
|
|
46
|
+
function applyQwenStandardConfigCn(cfg) {
|
|
47
|
+
return qwenPresetAppliers.applyConfig(cfg, QWEN_STANDARD_CN_BASE_URL);
|
|
48
|
+
}
|
|
49
|
+
function applyQwenOAuthConfig(cfg) {
|
|
50
|
+
return qwenOAuthPresetAppliers.applyConfig(cfg);
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
export { applyQwenConfig, applyQwenConfigCn, applyQwenOAuthConfig, applyQwenStandardConfig, applyQwenStandardConfigCn };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { QWEN_OAUTH_BASE_URL, buildQwenModelCatalogForBaseUrl, buildQwenOAuthModelCatalog } from "./models.js";
|
|
2
|
+
//#region extensions/qwen/provider-catalog.ts
|
|
3
|
+
function buildQwenProvider(params) {
|
|
4
|
+
const baseUrl = params?.baseUrl ?? "https://coding-intl.dashscope.aliyuncs.com/v1";
|
|
5
|
+
return {
|
|
6
|
+
baseUrl,
|
|
7
|
+
api: "openai-completions",
|
|
8
|
+
models: buildQwenModelCatalogForBaseUrl(baseUrl).map((model) => Object.assign({}, model))
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function buildQwenOAuthProvider() {
|
|
12
|
+
return {
|
|
13
|
+
baseUrl: QWEN_OAUTH_BASE_URL,
|
|
14
|
+
api: "openai-completions",
|
|
15
|
+
models: buildQwenOAuthModelCatalog().map((model) => Object.assign({}, model))
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
const buildModelStudioProvider = buildQwenProvider;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { buildModelStudioProvider, buildQwenOAuthProvider, buildQwenProvider };
|
package/dist/stream.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { normalizeProviderId } from "openclaw/plugin-sdk/provider-model-shared";
|
|
2
|
+
import { createPayloadPatchStreamWrapper, isOpenAICompatibleThinkingEnabled } from "openclaw/plugin-sdk/provider-stream-shared";
|
|
3
|
+
//#region extensions/qwen/stream.ts
|
|
4
|
+
function isQwenProviderId(providerId) {
|
|
5
|
+
const normalized = normalizeProviderId(providerId);
|
|
6
|
+
return normalized === "qwen" || normalized === "qwen-oauth" || normalized === "qwen-portal" || normalized === "qwen-cli" || normalized === "modelstudio" || normalized === "qwencloud" || normalized === "dashscope";
|
|
7
|
+
}
|
|
8
|
+
function isQwenOAuthProviderId(providerId) {
|
|
9
|
+
const normalized = normalizeProviderId(providerId);
|
|
10
|
+
return normalized === "qwen-oauth" || normalized === "qwen-portal" || normalized === "qwen-cli";
|
|
11
|
+
}
|
|
12
|
+
function normalizeQwenOAuthContent(content) {
|
|
13
|
+
if (typeof content === "string") return [{
|
|
14
|
+
type: "text",
|
|
15
|
+
text: content
|
|
16
|
+
}];
|
|
17
|
+
if (!Array.isArray(content)) return content;
|
|
18
|
+
const normalized = content.map((part) => {
|
|
19
|
+
if (typeof part === "string") return {
|
|
20
|
+
type: "text",
|
|
21
|
+
text: part
|
|
22
|
+
};
|
|
23
|
+
return part && typeof part === "object" ? part : void 0;
|
|
24
|
+
}).filter((part) => Boolean(part));
|
|
25
|
+
return normalized.length > 0 ? normalized : content;
|
|
26
|
+
}
|
|
27
|
+
function patchQwenOAuthPayload(payload) {
|
|
28
|
+
const messages = payload.messages;
|
|
29
|
+
if (!Array.isArray(messages)) return;
|
|
30
|
+
for (const message of messages) {
|
|
31
|
+
if (!message || typeof message !== "object") continue;
|
|
32
|
+
const record = message;
|
|
33
|
+
record.content = normalizeQwenOAuthContent(record.content);
|
|
34
|
+
if (record.role !== "system" || !Array.isArray(record.content) || record.content.length === 0) continue;
|
|
35
|
+
const last = record.content[record.content.length - 1];
|
|
36
|
+
if (last && typeof last === "object") last.cache_control = { type: "ephemeral" };
|
|
37
|
+
}
|
|
38
|
+
payload.vl_high_resolution_images = true;
|
|
39
|
+
}
|
|
40
|
+
function setQwenChatTemplateThinking(payload, enabled) {
|
|
41
|
+
const existing = payload.chat_template_kwargs;
|
|
42
|
+
if (existing && typeof existing === "object" && !Array.isArray(existing)) {
|
|
43
|
+
const next = {
|
|
44
|
+
...existing,
|
|
45
|
+
enable_thinking: enabled
|
|
46
|
+
};
|
|
47
|
+
if (!Object.hasOwn(next, "preserve_thinking")) next.preserve_thinking = true;
|
|
48
|
+
payload.chat_template_kwargs = next;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
payload.chat_template_kwargs = {
|
|
52
|
+
enable_thinking: enabled,
|
|
53
|
+
preserve_thinking: true
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
function readQwenThinkingFormatFromModel(model) {
|
|
57
|
+
if (model.api !== "openai-completions") return;
|
|
58
|
+
const compat = model.compat && typeof model.compat === "object" ? model.compat : void 0;
|
|
59
|
+
return typeof compat?.thinkingFormat === "string" ? compat.thinkingFormat : void 0;
|
|
60
|
+
}
|
|
61
|
+
function createQwenThinkingWrapper(baseStreamFn, thinkingLevel, thinkingFormat) {
|
|
62
|
+
return createPayloadPatchStreamWrapper(baseStreamFn, ({ payload: payloadObj, model, options }) => {
|
|
63
|
+
const enableThinking = isOpenAICompatibleThinkingEnabled({
|
|
64
|
+
thinkingLevel,
|
|
65
|
+
options
|
|
66
|
+
});
|
|
67
|
+
if ((thinkingFormat ?? readQwenThinkingFormatFromModel(model)) === "qwen-chat-template") {
|
|
68
|
+
setQwenChatTemplateThinking(payloadObj, enableThinking);
|
|
69
|
+
delete payloadObj.enable_thinking;
|
|
70
|
+
} else payloadObj.enable_thinking = enableThinking;
|
|
71
|
+
delete payloadObj.reasoning_effort;
|
|
72
|
+
delete payloadObj.reasoningEffort;
|
|
73
|
+
delete payloadObj.reasoning;
|
|
74
|
+
}, { shouldPatch: ({ model }) => model.api === "openai-completions" && model.reasoning });
|
|
75
|
+
}
|
|
76
|
+
function wrapQwenProviderStream(ctx) {
|
|
77
|
+
if (!isQwenProviderId(ctx.provider) || ctx.model && ctx.model.api !== "openai-completions") return;
|
|
78
|
+
const streamFn = createQwenThinkingWrapper(ctx.streamFn, ctx.thinkingLevel, ctx.model ? readQwenThinkingFormatFromModel(ctx.model) : void 0);
|
|
79
|
+
if (!isQwenOAuthProviderId(ctx.provider)) return streamFn;
|
|
80
|
+
return createPayloadPatchStreamWrapper(streamFn, ({ payload, model }) => {
|
|
81
|
+
if (model.api === "openai-completions") patchQwenOAuthPayload(payload);
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
export { createQwenThinkingWrapper, wrapQwenProviderStream };
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import "./models.js";
|
|
2
|
+
import { resolveProviderHttpRequestConfig } from "openclaw/plugin-sdk/provider-http";
|
|
3
|
+
import { isProviderApiKeyConfigured } from "openclaw/plugin-sdk/provider-auth";
|
|
4
|
+
import { resolveApiKeyForProvider } from "openclaw/plugin-sdk/provider-auth-runtime";
|
|
5
|
+
import { DASHSCOPE_WAN_VIDEO_CAPABILITIES, DASHSCOPE_WAN_VIDEO_MODELS, DEFAULT_DASHSCOPE_WAN_VIDEO_MODEL, DEFAULT_VIDEO_GENERATION_TIMEOUT_MS, runDashscopeVideoGenerationTask } from "openclaw/plugin-sdk/video-generation";
|
|
6
|
+
//#region extensions/qwen/video-generation-provider.ts
|
|
7
|
+
const DEFAULT_QWEN_VIDEO_BASE_URL = "https://dashscope-intl.aliyuncs.com";
|
|
8
|
+
const DEFAULT_QWEN_VIDEO_MODEL = DEFAULT_DASHSCOPE_WAN_VIDEO_MODEL;
|
|
9
|
+
function resolveQwenVideoBaseUrl(req) {
|
|
10
|
+
const direct = req.cfg?.models?.providers?.qwen?.baseUrl?.trim();
|
|
11
|
+
if (!direct) return DEFAULT_QWEN_VIDEO_BASE_URL;
|
|
12
|
+
try {
|
|
13
|
+
return new URL(direct).toString();
|
|
14
|
+
} catch {
|
|
15
|
+
return DEFAULT_QWEN_VIDEO_BASE_URL;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function resolveDashscopeAigcApiBaseUrl(baseUrl) {
|
|
19
|
+
try {
|
|
20
|
+
const url = new URL(baseUrl);
|
|
21
|
+
if (url.hostname === "coding-intl.dashscope.aliyuncs.com" || url.hostname === "coding.dashscope.aliyuncs.com" || url.hostname === "dashscope-intl.aliyuncs.com" || url.hostname === "dashscope.aliyuncs.com") return url.origin;
|
|
22
|
+
} catch {}
|
|
23
|
+
if (baseUrl.startsWith("https://dashscope.aliyuncs.com/compatible-mode/v1")) return "https://dashscope.aliyuncs.com";
|
|
24
|
+
if (baseUrl.startsWith("https://dashscope-intl.aliyuncs.com/compatible-mode/v1")) return DEFAULT_QWEN_VIDEO_BASE_URL;
|
|
25
|
+
return baseUrl.replace(/\/+$/u, "");
|
|
26
|
+
}
|
|
27
|
+
function buildQwenVideoGenerationProvider() {
|
|
28
|
+
return {
|
|
29
|
+
id: "qwen",
|
|
30
|
+
label: "Qwen Cloud",
|
|
31
|
+
defaultModel: DEFAULT_QWEN_VIDEO_MODEL,
|
|
32
|
+
models: [...DASHSCOPE_WAN_VIDEO_MODELS],
|
|
33
|
+
isConfigured: ({ agentDir }) => isProviderApiKeyConfigured({
|
|
34
|
+
provider: "qwen",
|
|
35
|
+
agentDir
|
|
36
|
+
}),
|
|
37
|
+
capabilities: DASHSCOPE_WAN_VIDEO_CAPABILITIES,
|
|
38
|
+
async generateVideo(req) {
|
|
39
|
+
const fetchFn = fetch;
|
|
40
|
+
const auth = await resolveApiKeyForProvider({
|
|
41
|
+
provider: "qwen",
|
|
42
|
+
cfg: req.cfg,
|
|
43
|
+
agentDir: req.agentDir,
|
|
44
|
+
store: req.authStore
|
|
45
|
+
});
|
|
46
|
+
if (!auth.apiKey) throw new Error("Qwen API key missing");
|
|
47
|
+
const { baseUrl, allowPrivateNetwork, headers, dispatcherPolicy } = resolveProviderHttpRequestConfig({
|
|
48
|
+
baseUrl: resolveQwenVideoBaseUrl(req),
|
|
49
|
+
defaultBaseUrl: DEFAULT_QWEN_VIDEO_BASE_URL,
|
|
50
|
+
defaultHeaders: {
|
|
51
|
+
Authorization: `Bearer ${auth.apiKey}`,
|
|
52
|
+
"Content-Type": "application/json",
|
|
53
|
+
"X-DashScope-Async": "enable"
|
|
54
|
+
},
|
|
55
|
+
provider: "qwen",
|
|
56
|
+
capability: "video",
|
|
57
|
+
transport: "http"
|
|
58
|
+
});
|
|
59
|
+
return await runDashscopeVideoGenerationTask({
|
|
60
|
+
providerLabel: "Qwen",
|
|
61
|
+
model: req.model?.trim() || DEFAULT_QWEN_VIDEO_MODEL,
|
|
62
|
+
req,
|
|
63
|
+
url: `${resolveDashscopeAigcApiBaseUrl(baseUrl)}/api/v1/services/aigc/video-generation/video-synthesis`,
|
|
64
|
+
headers,
|
|
65
|
+
baseUrl: resolveDashscopeAigcApiBaseUrl(baseUrl),
|
|
66
|
+
timeoutMs: req.timeoutMs,
|
|
67
|
+
fetchFn,
|
|
68
|
+
allowPrivateNetwork,
|
|
69
|
+
dispatcherPolicy,
|
|
70
|
+
defaultTimeoutMs: DEFAULT_VIDEO_GENERATION_TIMEOUT_MS
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { buildQwenVideoGenerationProvider };
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "qwen",
|
|
3
|
+
"activation": {
|
|
4
|
+
"onStartup": false
|
|
5
|
+
},
|
|
6
|
+
"enabledByDefault": true,
|
|
7
|
+
"providers": ["qwen", "qwencloud", "modelstudio", "dashscope", "qwen-oauth", "qwen-portal", "qwen-cli"],
|
|
8
|
+
"providerAuthAliases": {
|
|
9
|
+
"qwen-portal": "qwen-oauth",
|
|
10
|
+
"qwen-cli": "qwen-oauth"
|
|
11
|
+
},
|
|
12
|
+
"providerEndpoints": [
|
|
13
|
+
{
|
|
14
|
+
"endpointClass": "modelstudio-native",
|
|
15
|
+
"baseUrls": [
|
|
16
|
+
"https://coding-intl.dashscope.aliyuncs.com/v1",
|
|
17
|
+
"https://coding.dashscope.aliyuncs.com/v1",
|
|
18
|
+
"https://dashscope.aliyuncs.com/compatible-mode/v1",
|
|
19
|
+
"https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"endpointClass": "qwen-portal-native",
|
|
24
|
+
"baseUrls": ["https://portal.qwen.ai/v1"]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"providerRequest": {
|
|
28
|
+
"providers": {
|
|
29
|
+
"qwen": {
|
|
30
|
+
"family": "modelstudio"
|
|
31
|
+
},
|
|
32
|
+
"qwencloud": {
|
|
33
|
+
"family": "modelstudio"
|
|
34
|
+
},
|
|
35
|
+
"modelstudio": {
|
|
36
|
+
"family": "modelstudio"
|
|
37
|
+
},
|
|
38
|
+
"dashscope": {
|
|
39
|
+
"family": "modelstudio"
|
|
40
|
+
},
|
|
41
|
+
"qwen-oauth": {
|
|
42
|
+
"family": "qwen-portal"
|
|
43
|
+
},
|
|
44
|
+
"qwen-portal": {
|
|
45
|
+
"family": "qwen-portal"
|
|
46
|
+
},
|
|
47
|
+
"qwen-cli": {
|
|
48
|
+
"family": "qwen-portal"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"modelCatalog": {
|
|
53
|
+
"aliases": {
|
|
54
|
+
"qwen-portal": {
|
|
55
|
+
"provider": "qwen-oauth"
|
|
56
|
+
},
|
|
57
|
+
"qwen-cli": {
|
|
58
|
+
"provider": "qwen-oauth"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"suppressions": [
|
|
62
|
+
{
|
|
63
|
+
"provider": "qwen",
|
|
64
|
+
"model": "qwen3.6-plus",
|
|
65
|
+
"reason": "qwen3.6-plus is not supported on the Qwen Coding Plan endpoint; use a Standard pay-as-you-go Qwen endpoint or choose qwen/qwen3.5-plus.",
|
|
66
|
+
"when": {
|
|
67
|
+
"baseUrlHosts": ["coding.dashscope.aliyuncs.com", "coding-intl.dashscope.aliyuncs.com"],
|
|
68
|
+
"providerConfigApiIn": ["qwen", "modelstudio"]
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"provider": "modelstudio",
|
|
73
|
+
"model": "qwen3.6-plus",
|
|
74
|
+
"reason": "qwen3.6-plus is not supported on the Qwen Coding Plan endpoint; use a Standard pay-as-you-go Qwen endpoint or choose qwen/qwen3.5-plus.",
|
|
75
|
+
"when": {
|
|
76
|
+
"baseUrlHosts": ["coding.dashscope.aliyuncs.com", "coding-intl.dashscope.aliyuncs.com"],
|
|
77
|
+
"providerConfigApiIn": ["qwen", "modelstudio"]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
"providers": {
|
|
82
|
+
"qwen-oauth": {
|
|
83
|
+
"baseUrl": "https://portal.qwen.ai/v1",
|
|
84
|
+
"api": "openai-completions",
|
|
85
|
+
"models": [
|
|
86
|
+
{
|
|
87
|
+
"id": "qwen3.5-plus",
|
|
88
|
+
"name": "qwen3.5-plus",
|
|
89
|
+
"reasoning": false,
|
|
90
|
+
"input": ["text", "image"],
|
|
91
|
+
"cost": {
|
|
92
|
+
"input": 0,
|
|
93
|
+
"output": 0,
|
|
94
|
+
"cacheRead": 0,
|
|
95
|
+
"cacheWrite": 0
|
|
96
|
+
},
|
|
97
|
+
"contextWindow": 1000000,
|
|
98
|
+
"maxTokens": 65536
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"id": "qwen3.6-plus",
|
|
102
|
+
"name": "qwen3.6-plus",
|
|
103
|
+
"reasoning": false,
|
|
104
|
+
"input": ["text", "image"],
|
|
105
|
+
"cost": {
|
|
106
|
+
"input": 0,
|
|
107
|
+
"output": 0,
|
|
108
|
+
"cacheRead": 0,
|
|
109
|
+
"cacheWrite": 0
|
|
110
|
+
},
|
|
111
|
+
"contextWindow": 1000000,
|
|
112
|
+
"maxTokens": 65536
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"id": "qwen3-max-2026-01-23",
|
|
116
|
+
"name": "qwen3-max-2026-01-23",
|
|
117
|
+
"reasoning": false,
|
|
118
|
+
"input": ["text"],
|
|
119
|
+
"cost": {
|
|
120
|
+
"input": 0,
|
|
121
|
+
"output": 0,
|
|
122
|
+
"cacheRead": 0,
|
|
123
|
+
"cacheWrite": 0
|
|
124
|
+
},
|
|
125
|
+
"contextWindow": 262144,
|
|
126
|
+
"maxTokens": 65536
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"id": "qwen3-coder-next",
|
|
130
|
+
"name": "qwen3-coder-next",
|
|
131
|
+
"reasoning": false,
|
|
132
|
+
"input": ["text"],
|
|
133
|
+
"cost": {
|
|
134
|
+
"input": 0,
|
|
135
|
+
"output": 0,
|
|
136
|
+
"cacheRead": 0,
|
|
137
|
+
"cacheWrite": 0
|
|
138
|
+
},
|
|
139
|
+
"contextWindow": 262144,
|
|
140
|
+
"maxTokens": 65536
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"id": "qwen3-coder-plus",
|
|
144
|
+
"name": "qwen3-coder-plus",
|
|
145
|
+
"reasoning": false,
|
|
146
|
+
"input": ["text"],
|
|
147
|
+
"cost": {
|
|
148
|
+
"input": 0,
|
|
149
|
+
"output": 0,
|
|
150
|
+
"cacheRead": 0,
|
|
151
|
+
"cacheWrite": 0
|
|
152
|
+
},
|
|
153
|
+
"contextWindow": 1000000,
|
|
154
|
+
"maxTokens": 65536
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"id": "MiniMax-M2.5",
|
|
158
|
+
"name": "MiniMax-M2.5",
|
|
159
|
+
"reasoning": true,
|
|
160
|
+
"input": ["text"],
|
|
161
|
+
"cost": {
|
|
162
|
+
"input": 0,
|
|
163
|
+
"output": 0,
|
|
164
|
+
"cacheRead": 0,
|
|
165
|
+
"cacheWrite": 0
|
|
166
|
+
},
|
|
167
|
+
"contextWindow": 1000000,
|
|
168
|
+
"maxTokens": 65536
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"id": "glm-5",
|
|
172
|
+
"name": "glm-5",
|
|
173
|
+
"reasoning": false,
|
|
174
|
+
"input": ["text"],
|
|
175
|
+
"cost": {
|
|
176
|
+
"input": 0,
|
|
177
|
+
"output": 0,
|
|
178
|
+
"cacheRead": 0,
|
|
179
|
+
"cacheWrite": 0
|
|
180
|
+
},
|
|
181
|
+
"contextWindow": 202752,
|
|
182
|
+
"maxTokens": 65536
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"id": "glm-4.7",
|
|
186
|
+
"name": "glm-4.7",
|
|
187
|
+
"reasoning": false,
|
|
188
|
+
"input": ["text"],
|
|
189
|
+
"cost": {
|
|
190
|
+
"input": 0,
|
|
191
|
+
"output": 0,
|
|
192
|
+
"cacheRead": 0,
|
|
193
|
+
"cacheWrite": 0
|
|
194
|
+
},
|
|
195
|
+
"contextWindow": 202752,
|
|
196
|
+
"maxTokens": 65536
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
"id": "kimi-k2.5",
|
|
200
|
+
"name": "kimi-k2.5",
|
|
201
|
+
"reasoning": false,
|
|
202
|
+
"input": ["text", "image"],
|
|
203
|
+
"cost": {
|
|
204
|
+
"input": 0,
|
|
205
|
+
"output": 0,
|
|
206
|
+
"cacheRead": 0,
|
|
207
|
+
"cacheWrite": 0
|
|
208
|
+
},
|
|
209
|
+
"contextWindow": 262144,
|
|
210
|
+
"maxTokens": 65536
|
|
211
|
+
}
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
"contracts": {
|
|
217
|
+
"mediaUnderstandingProviders": ["qwen"],
|
|
218
|
+
"videoGenerationProviders": ["qwen"]
|
|
219
|
+
},
|
|
220
|
+
"mediaUnderstandingProviderMetadata": {
|
|
221
|
+
"qwen": {
|
|
222
|
+
"capabilities": ["image", "video"],
|
|
223
|
+
"defaultModels": {
|
|
224
|
+
"image": "qwen-vl-max-latest",
|
|
225
|
+
"video": "qwen-vl-max-latest"
|
|
226
|
+
},
|
|
227
|
+
"autoPriority": {
|
|
228
|
+
"video": 15
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
"setup": {
|
|
233
|
+
"providers": [
|
|
234
|
+
{
|
|
235
|
+
"id": "qwen",
|
|
236
|
+
"envVars": ["QWEN_API_KEY", "MODELSTUDIO_API_KEY", "DASHSCOPE_API_KEY"]
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"id": "qwen-oauth",
|
|
240
|
+
"envVars": ["QWEN_API_KEY"]
|
|
241
|
+
}
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
"providerAuthChoices": [
|
|
245
|
+
{
|
|
246
|
+
"provider": "qwen",
|
|
247
|
+
"method": "standard-api-key-cn",
|
|
248
|
+
"choiceId": "qwen-standard-api-key-cn",
|
|
249
|
+
"deprecatedChoiceIds": ["modelstudio-standard-api-key-cn"],
|
|
250
|
+
"choiceLabel": "Standard API Key for China (pay-as-you-go)",
|
|
251
|
+
"choiceHint": "Endpoint: dashscope.aliyuncs.com",
|
|
252
|
+
"groupId": "qwen",
|
|
253
|
+
"groupLabel": "Qwen Cloud",
|
|
254
|
+
"groupHint": "Standard / Coding Plan (CN / Global) + multimodal roadmap",
|
|
255
|
+
"optionKey": "modelstudioStandardApiKeyCn",
|
|
256
|
+
"cliFlag": "--modelstudio-standard-api-key-cn",
|
|
257
|
+
"cliOption": "--modelstudio-standard-api-key-cn <key>",
|
|
258
|
+
"cliDescription": "Qwen Cloud standard API key (China)"
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
"provider": "qwen",
|
|
262
|
+
"method": "standard-api-key",
|
|
263
|
+
"choiceId": "qwen-standard-api-key",
|
|
264
|
+
"deprecatedChoiceIds": ["modelstudio-standard-api-key"],
|
|
265
|
+
"choiceLabel": "Standard API Key for Global/Intl (pay-as-you-go)",
|
|
266
|
+
"choiceHint": "Endpoint: dashscope-intl.aliyuncs.com",
|
|
267
|
+
"groupId": "qwen",
|
|
268
|
+
"groupLabel": "Qwen Cloud",
|
|
269
|
+
"groupHint": "Standard / Coding Plan (CN / Global) + multimodal roadmap",
|
|
270
|
+
"optionKey": "modelstudioStandardApiKey",
|
|
271
|
+
"cliFlag": "--modelstudio-standard-api-key",
|
|
272
|
+
"cliOption": "--modelstudio-standard-api-key <key>",
|
|
273
|
+
"cliDescription": "Qwen Cloud standard API key (Global/Intl)"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"provider": "qwen",
|
|
277
|
+
"method": "api-key-cn",
|
|
278
|
+
"choiceId": "qwen-api-key-cn",
|
|
279
|
+
"deprecatedChoiceIds": ["modelstudio-api-key-cn"],
|
|
280
|
+
"choiceLabel": "Coding Plan API Key for China (subscription)",
|
|
281
|
+
"choiceHint": "Endpoint: coding.dashscope.aliyuncs.com",
|
|
282
|
+
"groupId": "qwen",
|
|
283
|
+
"groupLabel": "Qwen Cloud",
|
|
284
|
+
"groupHint": "Standard / Coding Plan (CN / Global) + multimodal roadmap",
|
|
285
|
+
"optionKey": "modelstudioApiKeyCn",
|
|
286
|
+
"cliFlag": "--modelstudio-api-key-cn",
|
|
287
|
+
"cliOption": "--modelstudio-api-key-cn <key>",
|
|
288
|
+
"cliDescription": "Qwen Cloud Coding Plan API key (China)"
|
|
289
|
+
},
|
|
290
|
+
{
|
|
291
|
+
"provider": "qwen",
|
|
292
|
+
"method": "api-key",
|
|
293
|
+
"choiceId": "qwen-api-key",
|
|
294
|
+
"deprecatedChoiceIds": ["modelstudio-api-key"],
|
|
295
|
+
"choiceLabel": "Coding Plan API Key for Global/Intl (subscription)",
|
|
296
|
+
"choiceHint": "Endpoint: coding-intl.dashscope.aliyuncs.com",
|
|
297
|
+
"groupId": "qwen",
|
|
298
|
+
"groupLabel": "Qwen Cloud",
|
|
299
|
+
"groupHint": "Standard / Coding Plan (CN / Global) + multimodal roadmap",
|
|
300
|
+
"optionKey": "modelstudioApiKey",
|
|
301
|
+
"cliFlag": "--modelstudio-api-key",
|
|
302
|
+
"cliOption": "--modelstudio-api-key <key>",
|
|
303
|
+
"cliDescription": "Qwen Cloud Coding Plan API key (Global/Intl)"
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
"provider": "qwen-oauth",
|
|
307
|
+
"method": "api-key",
|
|
308
|
+
"choiceId": "qwen-oauth",
|
|
309
|
+
"choiceLabel": "Qwen OAuth",
|
|
310
|
+
"choiceHint": "Portal token for portal.qwen.ai",
|
|
311
|
+
"groupId": "qwen",
|
|
312
|
+
"groupLabel": "Qwen Cloud",
|
|
313
|
+
"groupHint": "Standard / Coding Plan / OAuth",
|
|
314
|
+
"optionKey": "qwenOauthToken",
|
|
315
|
+
"cliFlag": "--qwen-oauth-token",
|
|
316
|
+
"cliOption": "--qwen-oauth-token <token>",
|
|
317
|
+
"cliDescription": "Qwen OAuth token"
|
|
318
|
+
}
|
|
319
|
+
],
|
|
320
|
+
"configSchema": {
|
|
321
|
+
"type": "object",
|
|
322
|
+
"additionalProperties": false,
|
|
323
|
+
"properties": {}
|
|
324
|
+
}
|
|
325
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/qwen-provider",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"license": "MIT",
|
|
3
|
+
"version": "2026.6.9-beta.1",
|
|
4
|
+
"description": "OpenClaw Qwen Cloud provider plugin.",
|
|
6
5
|
"repository": {
|
|
7
6
|
"type": "git",
|
|
8
|
-
"url": "
|
|
7
|
+
"url": "https://github.com/openclaw/openclaw"
|
|
9
8
|
},
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
|
|
9
|
+
"type": "module",
|
|
10
|
+
"openclaw": {
|
|
11
|
+
"extensions": [
|
|
12
|
+
"./index.ts"
|
|
13
|
+
],
|
|
14
|
+
"install": {
|
|
15
|
+
"clawhubSpec": "clawhub:@openclaw/qwen-provider",
|
|
16
|
+
"npmSpec": "@openclaw/qwen-provider",
|
|
17
|
+
"defaultChoice": "npm",
|
|
18
|
+
"minHostVersion": ">=2026.6.8"
|
|
19
|
+
},
|
|
20
|
+
"compat": {
|
|
21
|
+
"pluginApi": ">=2026.6.9-beta.1"
|
|
22
|
+
},
|
|
23
|
+
"build": {
|
|
24
|
+
"openclawVersion": "2026.6.9-beta.1",
|
|
25
|
+
"bundledDist": false
|
|
26
|
+
},
|
|
27
|
+
"release": {
|
|
28
|
+
"publishToClawHub": true,
|
|
29
|
+
"publishToNpm": true
|
|
30
|
+
},
|
|
31
|
+
"runtimeExtensions": [
|
|
32
|
+
"./dist/index.js"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist/**",
|
|
37
|
+
"openclaw.plugin.json",
|
|
38
|
+
"npm-shrinkwrap.json",
|
|
39
|
+
"README.md"
|
|
40
|
+
],
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"openclaw": ">=2026.6.9-beta.1"
|
|
43
|
+
},
|
|
44
|
+
"peerDependenciesMeta": {
|
|
45
|
+
"openclaw": {
|
|
46
|
+
"optional": true
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"bundledDependencies": []
|
|
14
50
|
}
|