@openclaw/chutes-provider 2026.10.10-beta.5 → 2026.11.5-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/dist/.setup/{models-mN33VNCv.mjs → models-DnSR_ZQn.mjs} +31 -34
- package/dist/.source-module-urls/57a22cf71076c0f146ec663e0217b8dccda90f034c03a80a80ea8703fc31fe6a.json +1 -1
- package/dist/api.js +1 -1
- package/dist/index.js +1 -2
- package/dist/models.js +1 -1
- package/dist/oauth.js +84 -82
- package/dist/onboard.js +3 -4
- package/dist/pricing-api.js +1 -2
- package/dist/provider-catalog.js +3 -4
- package/package.json +4 -4
|
@@ -4,7 +4,7 @@ import { asPositiveSafeInteger, normalizeLowercaseStringOrEmpty, normalizeOption
|
|
|
4
4
|
import { withTrustedEnvProxyGuardedFetchMode } from "openclaw/plugin-sdk/fetch-runtime";
|
|
5
5
|
import { fetchWithSsrFGuard, ssrfPolicyFromHttpBaseUrlAllowedHostname } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
6
6
|
import { buildManifestModelProviderConfig } from "openclaw/plugin-sdk/provider-catalog-shared";
|
|
7
|
-
|
|
7
|
+
// extensions/chutes/openclaw.plugin.json
|
|
8
8
|
var openclaw_plugin_default = {
|
|
9
9
|
id: "chutes",
|
|
10
10
|
categories: ["models"],
|
|
@@ -136,8 +136,7 @@ var openclaw_plugin_default = {
|
|
|
136
136
|
"discovery": { "chutes": "refreshable" }
|
|
137
137
|
}
|
|
138
138
|
};
|
|
139
|
-
|
|
140
|
-
//#region extensions/chutes/models.ts
|
|
139
|
+
// extensions/chutes/models.ts
|
|
141
140
|
const CHUTES_MANIFEST_CATALOG = openclaw_plugin_default.modelCatalog.providers.chutes;
|
|
142
141
|
const CHUTES_BASE_URL = CHUTES_MANIFEST_CATALOG.baseUrl;
|
|
143
142
|
const CHUTES_DEFAULT_CONTEXT_WINDOW = 128e3;
|
|
@@ -156,34 +155,6 @@ const CHUTES_MODEL_CATALOG = buildManifestModelProviderConfig({
|
|
|
156
155
|
catalog: CHUTES_MANIFEST_CATALOG
|
|
157
156
|
}).models.map(decorateChutesModelDefinition);
|
|
158
157
|
const CACHE_TTL = 3e5;
|
|
159
|
-
function projectChutesModels(rows) {
|
|
160
|
-
const seen = /* @__PURE__ */ new Set();
|
|
161
|
-
const models = [];
|
|
162
|
-
for (const row of rows) {
|
|
163
|
-
if (!row || typeof row !== "object" || Array.isArray(row)) continue;
|
|
164
|
-
const entry = row;
|
|
165
|
-
const id = normalizeOptionalString(entry.id) ?? "";
|
|
166
|
-
if (!id || seen.has(id)) continue;
|
|
167
|
-
seen.add(id);
|
|
168
|
-
const lowerId = normalizeLowercaseStringOrEmpty(id);
|
|
169
|
-
models.push({
|
|
170
|
-
id,
|
|
171
|
-
name: id,
|
|
172
|
-
reasoning: entry.supported_features?.includes("reasoning") || lowerId.includes("r1") || lowerId.includes("thinking") || lowerId.includes("reason") || lowerId.includes("tee"),
|
|
173
|
-
input: (entry.input_modalities || ["text"]).filter((item) => item === "text" || item === "image"),
|
|
174
|
-
cost: normalizeChutesModelPricing(entry.pricing) ?? {
|
|
175
|
-
input: 0,
|
|
176
|
-
output: 0,
|
|
177
|
-
cacheRead: 0,
|
|
178
|
-
cacheWrite: 0
|
|
179
|
-
},
|
|
180
|
-
contextWindow: asPositiveSafeInteger(entry.context_length) ?? asPositiveSafeInteger(entry.max_model_len) ?? CHUTES_DEFAULT_CONTEXT_WINDOW,
|
|
181
|
-
maxTokens: asPositiveSafeInteger(entry.max_output_length) ?? CHUTES_DEFAULT_MAX_TOKENS,
|
|
182
|
-
compat: { supportsUsageInStreaming: false }
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
return models;
|
|
186
|
-
}
|
|
187
158
|
async function discoverChutesModels(accessToken, options = {}) {
|
|
188
159
|
return (await buildLiveModelProviderConfig({
|
|
189
160
|
...options,
|
|
@@ -193,7 +164,7 @@ async function discoverChutesModels(accessToken, options = {}) {
|
|
|
193
164
|
baseUrl: CHUTES_BASE_URL,
|
|
194
165
|
api: "openai-completions"
|
|
195
166
|
},
|
|
196
|
-
models:
|
|
167
|
+
models: CHUTES_MODEL_CATALOG,
|
|
197
168
|
discoveryApiKey: normalizeOptionalString(accessToken),
|
|
198
169
|
timeoutMs: 1e4,
|
|
199
170
|
ttlMs: CACHE_TTL,
|
|
@@ -201,8 +172,34 @@ async function discoverChutesModels(accessToken, options = {}) {
|
|
|
201
172
|
auditContext: "chutes-model-discovery",
|
|
202
173
|
fetchGuard: (params) => fetchWithSsrFGuard(withTrustedEnvProxyGuardedFetchMode(params)),
|
|
203
174
|
fallbackToAnonymousOnUnauthorized: true,
|
|
204
|
-
projectRows:
|
|
175
|
+
projectRows: (rows) => {
|
|
176
|
+
const seen = /* @__PURE__ */ new Set();
|
|
177
|
+
const models = [];
|
|
178
|
+
for (const row of rows) {
|
|
179
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) continue;
|
|
180
|
+
const entry = row;
|
|
181
|
+
const id = normalizeOptionalString(entry.id) ?? "";
|
|
182
|
+
if (!id || seen.has(id)) continue;
|
|
183
|
+
seen.add(id);
|
|
184
|
+
const lowerId = normalizeLowercaseStringOrEmpty(id);
|
|
185
|
+
models.push({
|
|
186
|
+
id,
|
|
187
|
+
name: id,
|
|
188
|
+
reasoning: entry.supported_features?.includes("reasoning") || lowerId.includes("r1") || lowerId.includes("thinking") || lowerId.includes("reason") || lowerId.includes("tee"),
|
|
189
|
+
input: (entry.input_modalities || ["text"]).filter((item) => item === "text" || item === "image"),
|
|
190
|
+
cost: normalizeChutesModelPricing(entry.pricing) ?? {
|
|
191
|
+
input: 0,
|
|
192
|
+
output: 0,
|
|
193
|
+
cacheRead: 0,
|
|
194
|
+
cacheWrite: 0
|
|
195
|
+
},
|
|
196
|
+
contextWindow: asPositiveSafeInteger(entry.context_length) ?? asPositiveSafeInteger(entry.max_model_len) ?? CHUTES_DEFAULT_CONTEXT_WINDOW,
|
|
197
|
+
maxTokens: asPositiveSafeInteger(entry.max_output_length) ?? CHUTES_DEFAULT_MAX_TOKENS,
|
|
198
|
+
compat: { supportsUsageInStreaming: false }
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return models;
|
|
202
|
+
}
|
|
205
203
|
})).models;
|
|
206
204
|
}
|
|
207
|
-
//#endregion
|
|
208
205
|
export { openclaw_plugin_default as i, CHUTES_MODEL_CATALOG as n, discoverChutesModels as r, CHUTES_BASE_URL as t };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"entries":[{"output":"api.js","source":"extensions/chutes/api.ts"},{"output":"index.js","source":"extensions/chutes/index.ts"},{"output":"models.js","source":"extensions/chutes/models.ts"},{"output":"oauth.js","source":"extensions/chutes/oauth.ts"},{"output":"onboard.js","source":"extensions/chutes/onboard.ts"},{"output":"pricing-api.js","source":"extensions/chutes/pricing-api.ts"},{"output":"provider-catalog.js","source":"extensions/chutes/provider-catalog.ts"}],"chunks":[{"output":".setup/models-
|
|
1
|
+
{"version":3,"entries":[{"output":"api.js","source":"extensions/chutes/api.ts"},{"output":"index.js","source":"extensions/chutes/index.ts"},{"output":"models.js","source":"extensions/chutes/models.ts"},{"output":"oauth.js","source":"extensions/chutes/oauth.ts"},{"output":"onboard.js","source":"extensions/chutes/onboard.ts"},{"output":"pricing-api.js","source":"extensions/chutes/pricing-api.ts"},{"output":"provider-catalog.js","source":"extensions/chutes/provider-catalog.ts"}],"chunks":[{"output":".setup/models-DnSR_ZQn.mjs","sha256":"c0eb3e452b5d452fe49b2669f500f77897a8a3156e5f5ce37b55d70a512f12d8","facadeSource":null,"sources":["extensions/chutes/models.ts","extensions/chutes/openclaw.plugin.json"]},{"output":"api.js","sha256":"fc74dd0090fb98d4c2963448b261db8899434cdca1cedd7f9833ab67d5e4d82e","facadeSource":"extensions/chutes/api.ts","sources":[]},{"output":"index.js","sha256":"5a04ca7dbbfcd1cd87363a7ba1e8c4533891f53a37e199d06a8ee50dd016b8f9","facadeSource":"extensions/chutes/index.ts","sources":["extensions/chutes/index.ts"]},{"output":"models.js","sha256":"76684ea5f997548a06bf7608fcf0e408d75ba8f8526df15fab090acf868e6c6a","facadeSource":"extensions/chutes/models.ts","sources":[]},{"output":"oauth.js","sha256":"f4df57cdbb47a76e098f70bd6f6f46b49af31df5acf24471bcdbe03367c1d351","facadeSource":"extensions/chutes/oauth.ts","sources":["extensions/chutes/oauth.ts"]},{"output":"onboard.js","sha256":"52c9409ef178eaa0fb29e6dae3ca4cfe9fa13c09e2343612158f5400e1bdd236","facadeSource":"extensions/chutes/onboard.ts","sources":["extensions/chutes/onboard.ts"]},{"output":"pricing-api.js","sha256":"9372d586e4032b5b2518810b16a4aaa092560d12e781c4ef19f87e7fd62467e2","facadeSource":"extensions/chutes/pricing-api.ts","sources":["extensions/chutes/pricing-api.ts"]},{"output":"provider-catalog.js","sha256":"8b076d0d9df8bc7a8bbfe982b384cc17b9a5a3442a30ea5d0deb97ffe9db72f0","facadeSource":"extensions/chutes/provider-catalog.ts","sources":["extensions/chutes/provider-catalog.ts"]}],"unrenderedSources":["extensions/chutes/api.ts"]}
|
package/dist/api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as CHUTES_MODEL_CATALOG, r as discoverChutesModels, t as CHUTES_BASE_URL } from "./.setup/models-
|
|
1
|
+
import { n as CHUTES_MODEL_CATALOG, r as discoverChutesModels, t as CHUTES_BASE_URL } from "./.setup/models-DnSR_ZQn.mjs";
|
|
2
2
|
import { CHUTES_DEFAULT_MODEL_ID, CHUTES_DEFAULT_MODEL_REF, applyChutesApiKeyConfig, applyChutesConfig, applyChutesProviderConfig } from "./onboard.js";
|
|
3
3
|
import { buildChutesProvider } from "./provider-catalog.js";
|
|
4
4
|
export { CHUTES_BASE_URL, CHUTES_DEFAULT_MODEL_ID, CHUTES_DEFAULT_MODEL_REF, CHUTES_MODEL_CATALOG, applyChutesApiKeyConfig, applyChutesConfig, applyChutesProviderConfig, buildChutesProvider, discoverChutesModels };
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { buildOauthProviderAuthResult, resolveOAuthApiKeyMarker } from "openclaw
|
|
|
6
6
|
import { createProviderApiKeyAuthMethod } from "openclaw/plugin-sdk/provider-auth-api-key";
|
|
7
7
|
import { runLiveProviderCatalog } from "openclaw/plugin-sdk/provider-catalog-live-runtime";
|
|
8
8
|
import { normalizeOptionalString, readStringValue } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
9
|
-
|
|
9
|
+
// extensions/chutes/index.ts
|
|
10
10
|
const PROVIDER_ID = "chutes";
|
|
11
11
|
async function runChutesOAuth(ctx) {
|
|
12
12
|
const isRemote = ctx.isRemote;
|
|
@@ -148,5 +148,4 @@ var chutes_default = definePluginEntry({
|
|
|
148
148
|
});
|
|
149
149
|
}
|
|
150
150
|
});
|
|
151
|
-
//#endregion
|
|
152
151
|
export { chutes_default as default };
|
package/dist/models.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { t as CHUTES_BASE_URL, n as CHUTES_MODEL_CATALOG, r as discoverChutesModels } from "./.setup/models-
|
|
1
|
+
export { t as CHUTES_BASE_URL, n as CHUTES_MODEL_CATALOG, r as discoverChutesModels } from "./.setup/models-DnSR_ZQn.mjs";
|
package/dist/oauth.js
CHANGED
|
@@ -5,40 +5,13 @@ import { withTrustedEnvProxyGuardedFetchMode } from "openclaw/plugin-sdk/fetch-r
|
|
|
5
5
|
import { resolveExpiresAtMsFromDurationSeconds } from "openclaw/plugin-sdk/number-runtime";
|
|
6
6
|
import { parseOAuthCallbackInput, waitForLocalOAuthCallback } from "openclaw/plugin-sdk/provider-auth-runtime";
|
|
7
7
|
import { assertOkOrThrowProviderError, readProviderJsonResponse } from "openclaw/plugin-sdk/provider-http";
|
|
8
|
-
import { buildOAuthRequestSignal } from "openclaw/plugin-sdk/provider-oauth-runtime";
|
|
8
|
+
import { buildOAuthRequestSignal, createOAuthRefreshError, createOAuthRefreshResponseError } from "openclaw/plugin-sdk/provider-oauth-runtime";
|
|
9
9
|
import { fetchWithSsrFGuard } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
10
|
-
|
|
10
|
+
// extensions/chutes/oauth.ts
|
|
11
11
|
const CHUTES_AUTHORIZE_ENDPOINT = "https://api.chutes.ai/idp/authorize";
|
|
12
12
|
const CHUTES_TOKEN_ENDPOINT = "https://api.chutes.ai/idp/token";
|
|
13
13
|
const CHUTES_USERINFO_ENDPOINT = "https://api.chutes.ai/idp/userinfo";
|
|
14
14
|
const CHUTES_OAUTH_REQUEST_TIMEOUT_MS = 3e4;
|
|
15
|
-
function parseRedirectUri(redirectUri) {
|
|
16
|
-
const url = new URL(redirectUri);
|
|
17
|
-
if (url.protocol !== "http:") throw new Error(`Chutes OAuth redirect URI must be http:// (got ${redirectUri})`);
|
|
18
|
-
const hostname = url.hostname === "[::1]" ? "::1" : url.hostname || "127.0.0.1";
|
|
19
|
-
if (hostname !== "localhost" && hostname !== "127.0.0.1" && hostname !== "::1") throw new Error(`Chutes OAuth redirect hostname must be loopback (got ${hostname}). Use http://127.0.0.1:<port>/...`);
|
|
20
|
-
return {
|
|
21
|
-
hostname,
|
|
22
|
-
port: url.port ? Number.parseInt(url.port, 10) : 80,
|
|
23
|
-
pathname: url.pathname || "/"
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
function parseManualOAuthInput(input, expectedState) {
|
|
27
|
-
const parsed = parseOAuthCallbackInput(input, {
|
|
28
|
-
invalidInput: "Paste the full redirect URL (must include code + state).",
|
|
29
|
-
missingState: "Missing 'state' parameter. Paste the full redirect URL."
|
|
30
|
-
});
|
|
31
|
-
if ("error" in parsed) throw new Error(parsed.error);
|
|
32
|
-
if (parsed.state !== expectedState) throw new Error("OAuth state mismatch - possible CSRF attack. Please retry login.");
|
|
33
|
-
return parsed;
|
|
34
|
-
}
|
|
35
|
-
function resolveChutesExpiresAt(value, now) {
|
|
36
|
-
return resolveExpiresAtMsFromDurationSeconds(value, {
|
|
37
|
-
nowMs: now,
|
|
38
|
-
bufferMs: 3e5,
|
|
39
|
-
minRemainingMs: 3e4
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
15
|
async function requestChutesTokenGrant(params) {
|
|
43
16
|
const { response, release } = await fetchWithSsrFGuard(withTrustedEnvProxyGuardedFetchMode({
|
|
44
17
|
url: CHUTES_TOKEN_ENDPOINT,
|
|
@@ -53,15 +26,37 @@ async function requestChutesTokenGrant(params) {
|
|
|
53
26
|
})
|
|
54
27
|
}));
|
|
55
28
|
try {
|
|
56
|
-
await assertOkOrThrowProviderError(response, `${params.responseLabel} failed`);
|
|
29
|
+
if (params.responseLabel === "Chutes token exchange") await assertOkOrThrowProviderError(response, `${params.responseLabel} failed`);
|
|
57
30
|
const data = await readProviderJsonResponse(response, params.responseLabel);
|
|
31
|
+
if (!response.ok || data.error !== void 0) throw createOAuthRefreshResponseError(params.responseLabel, response.status, data);
|
|
58
32
|
const access = normalizeOptionalString(data.access_token);
|
|
59
|
-
const expires =
|
|
60
|
-
|
|
61
|
-
|
|
33
|
+
const expires = resolveExpiresAtMsFromDurationSeconds(data.expires_in, {
|
|
34
|
+
nowMs: params.now ?? Date.now(),
|
|
35
|
+
bufferMs: 3e5,
|
|
36
|
+
minRemainingMs: 3e4
|
|
37
|
+
});
|
|
38
|
+
if (!access) throw createOAuthRefreshError(`${params.responseLabel} returned no access_token`, {
|
|
39
|
+
version: 1,
|
|
40
|
+
phase: "after-token-response",
|
|
41
|
+
outcome: "unknown",
|
|
42
|
+
status: response.status
|
|
43
|
+
});
|
|
44
|
+
if (expires === void 0) throw createOAuthRefreshError(`${params.responseLabel} returned invalid expires_in`, {
|
|
45
|
+
version: 1,
|
|
46
|
+
phase: "after-token-response",
|
|
47
|
+
outcome: "unknown",
|
|
48
|
+
status: response.status
|
|
49
|
+
});
|
|
50
|
+
const refresh = normalizeOptionalString(data.refresh_token);
|
|
51
|
+
if (data.refresh_token !== void 0 && !refresh) throw createOAuthRefreshError(`${params.responseLabel} returned invalid refresh_token`, {
|
|
52
|
+
version: 1,
|
|
53
|
+
phase: "after-token-response",
|
|
54
|
+
outcome: "unknown",
|
|
55
|
+
status: response.status
|
|
56
|
+
});
|
|
62
57
|
return {
|
|
63
58
|
access,
|
|
64
|
-
refresh
|
|
59
|
+
refresh,
|
|
65
60
|
expires
|
|
66
61
|
};
|
|
67
62
|
} finally {
|
|
@@ -85,41 +80,6 @@ async function fetchChutesUserInfo(params) {
|
|
|
85
80
|
await release();
|
|
86
81
|
}
|
|
87
82
|
}
|
|
88
|
-
async function exchangeChutesCodeForTokens(params) {
|
|
89
|
-
const now = Date.now();
|
|
90
|
-
const body = new URLSearchParams({
|
|
91
|
-
grant_type: "authorization_code",
|
|
92
|
-
client_id: params.app.clientId,
|
|
93
|
-
code: params.code,
|
|
94
|
-
redirect_uri: params.app.redirectUri,
|
|
95
|
-
code_verifier: params.codeVerifier
|
|
96
|
-
});
|
|
97
|
-
if (params.app.clientSecret) body.set("client_secret", params.app.clientSecret);
|
|
98
|
-
const token = await requestChutesTokenGrant({
|
|
99
|
-
body,
|
|
100
|
-
responseLabel: "Chutes token exchange",
|
|
101
|
-
now,
|
|
102
|
-
...params.signal ? { signal: params.signal } : {}
|
|
103
|
-
});
|
|
104
|
-
if (!token.refresh) throw new Error("Chutes token exchange returned no refresh_token");
|
|
105
|
-
let info = null;
|
|
106
|
-
try {
|
|
107
|
-
info = await fetchChutesUserInfo({
|
|
108
|
-
accessToken: token.access,
|
|
109
|
-
...params.signal ? { signal: params.signal } : {}
|
|
110
|
-
});
|
|
111
|
-
} catch (error) {
|
|
112
|
-
if (params.signal?.aborted) throw error;
|
|
113
|
-
}
|
|
114
|
-
return {
|
|
115
|
-
access: token.access,
|
|
116
|
-
refresh: token.refresh,
|
|
117
|
-
expires: token.expires,
|
|
118
|
-
email: info?.username,
|
|
119
|
-
accountId: info?.sub,
|
|
120
|
-
clientId: params.app.clientId
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
83
|
/** Refreshes a stored Chutes OAuth credential through the provider token endpoint. */
|
|
124
84
|
async function refreshChutesOAuthCredential(credential) {
|
|
125
85
|
const refreshToken = normalizeOptionalString(credential.refresh);
|
|
@@ -159,25 +119,39 @@ async function loginChutes(params) {
|
|
|
159
119
|
code_challenge_method: "S256"
|
|
160
120
|
});
|
|
161
121
|
const url = `${CHUTES_AUTHORIZE_ENDPOINT}?${query}`;
|
|
162
|
-
const promptForCode = async () =>
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
122
|
+
const promptForCode = async () => {
|
|
123
|
+
const parsed = parseOAuthCallbackInput(await params.onPrompt({
|
|
124
|
+
message: "Paste the redirect URL",
|
|
125
|
+
placeholder: `${params.app.redirectUri}?code=...&state=...`
|
|
126
|
+
}), {
|
|
127
|
+
invalidInput: "Paste the full redirect URL (must include code + state).",
|
|
128
|
+
missingState: "Missing 'state' parameter. Paste the full redirect URL."
|
|
129
|
+
});
|
|
130
|
+
if ("error" in parsed) throw new Error(parsed.error);
|
|
131
|
+
if (parsed.state !== state) throw new Error("OAuth state mismatch - possible CSRF attack. Please retry login.");
|
|
132
|
+
return parsed;
|
|
133
|
+
};
|
|
166
134
|
let codeAndState;
|
|
167
135
|
if (params.manual) {
|
|
168
136
|
await params.onAuth({ url });
|
|
169
137
|
params.onProgress?.("Waiting for redirect URL...");
|
|
170
138
|
codeAndState = await promptForCode();
|
|
171
139
|
} else {
|
|
172
|
-
const
|
|
140
|
+
const redirectUri = params.app.redirectUri;
|
|
141
|
+
const redirect = new URL(redirectUri);
|
|
142
|
+
if (redirect.protocol !== "http:") throw new Error(`Chutes OAuth redirect URI must be http:// (got ${redirectUri})`);
|
|
143
|
+
const hostname = redirect.hostname === "[::1]" ? "::1" : redirect.hostname || "127.0.0.1";
|
|
144
|
+
if (hostname !== "localhost" && hostname !== "127.0.0.1" && hostname !== "::1") throw new Error(`Chutes OAuth redirect hostname must be loopback (got ${hostname}). Use http://127.0.0.1:<port>/...`);
|
|
145
|
+
const port = redirect.port ? Number.parseInt(redirect.port, 10) : 80;
|
|
146
|
+
const pathname = redirect.pathname || "/";
|
|
173
147
|
const callback = waitForLocalOAuthCallback({
|
|
174
148
|
expectedState: state,
|
|
175
149
|
timeoutMs: 18e4,
|
|
176
|
-
port
|
|
177
|
-
callbackPath:
|
|
150
|
+
port,
|
|
151
|
+
callbackPath: pathname,
|
|
178
152
|
redirectUri: params.app.redirectUri,
|
|
179
153
|
successTitle: "Chutes OAuth complete",
|
|
180
|
-
hostname
|
|
154
|
+
hostname,
|
|
181
155
|
onProgress: params.onProgress,
|
|
182
156
|
...params.signal ? { signal: params.signal } : {}
|
|
183
157
|
}).catch(async (error) => {
|
|
@@ -189,12 +163,40 @@ async function loginChutes(params) {
|
|
|
189
163
|
codeAndState = await callback;
|
|
190
164
|
}
|
|
191
165
|
params.onProgress?.("Exchanging code for tokens...");
|
|
192
|
-
|
|
193
|
-
|
|
166
|
+
const app = params.app;
|
|
167
|
+
const signal = params.signal;
|
|
168
|
+
const now = Date.now();
|
|
169
|
+
const body = new URLSearchParams({
|
|
170
|
+
grant_type: "authorization_code",
|
|
171
|
+
client_id: app.clientId,
|
|
194
172
|
code: codeAndState.code,
|
|
195
|
-
|
|
196
|
-
|
|
173
|
+
redirect_uri: app.redirectUri,
|
|
174
|
+
code_verifier: verifier
|
|
175
|
+
});
|
|
176
|
+
if (app.clientSecret) body.set("client_secret", app.clientSecret);
|
|
177
|
+
const token = await requestChutesTokenGrant({
|
|
178
|
+
body,
|
|
179
|
+
responseLabel: "Chutes token exchange",
|
|
180
|
+
now,
|
|
181
|
+
...signal ? { signal } : {}
|
|
197
182
|
});
|
|
183
|
+
if (!token.refresh) throw new Error("Chutes token exchange returned no refresh_token");
|
|
184
|
+
let info = null;
|
|
185
|
+
try {
|
|
186
|
+
info = await fetchChutesUserInfo({
|
|
187
|
+
accessToken: token.access,
|
|
188
|
+
...signal ? { signal } : {}
|
|
189
|
+
});
|
|
190
|
+
} catch (error) {
|
|
191
|
+
if (signal?.aborted) throw error;
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
access: token.access,
|
|
195
|
+
refresh: token.refresh,
|
|
196
|
+
expires: token.expires,
|
|
197
|
+
email: info?.username,
|
|
198
|
+
accountId: info?.sub,
|
|
199
|
+
clientId: app.clientId
|
|
200
|
+
};
|
|
198
201
|
}
|
|
199
|
-
//#endregion
|
|
200
202
|
export { loginChutes, refreshChutesOAuthCredential };
|
package/dist/onboard.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { i as openclaw_plugin_default, n as CHUTES_MODEL_CATALOG, t as CHUTES_BASE_URL } from "./.setup/models-
|
|
1
|
+
import { i as openclaw_plugin_default, n as CHUTES_MODEL_CATALOG, t as CHUTES_BASE_URL } from "./.setup/models-DnSR_ZQn.mjs";
|
|
2
2
|
import { readManifestProviderDefaultModelRef } from "openclaw/plugin-sdk/provider-catalog-shared";
|
|
3
3
|
import { applyAgentDefaultModelPrimary, createModelCatalogPresetAppliers } from "openclaw/plugin-sdk/provider-onboard";
|
|
4
|
-
|
|
4
|
+
// extensions/chutes/onboard.ts
|
|
5
5
|
const CHUTES_DEFAULT_MODEL_ID = openclaw_plugin_default.modelCatalog.providers.chutes.defaultModel;
|
|
6
6
|
const CHUTES_DEFAULT_MODEL_REF = readManifestProviderDefaultModelRef(openclaw_plugin_default, "chutes");
|
|
7
7
|
const { applyProviderConfig: applyChutesProviderConfig } = createModelCatalogPresetAppliers({
|
|
@@ -10,7 +10,7 @@ const { applyProviderConfig: applyChutesProviderConfig } = createModelCatalogPre
|
|
|
10
10
|
providerId: "chutes",
|
|
11
11
|
api: "openai-completions",
|
|
12
12
|
baseUrl: CHUTES_BASE_URL,
|
|
13
|
-
catalogModels: cfg.models?.mode === "replace" ?
|
|
13
|
+
catalogModels: cfg.models?.mode === "replace" ? CHUTES_MODEL_CATALOG : [],
|
|
14
14
|
aliases: [
|
|
15
15
|
...CHUTES_MODEL_CATALOG.map((model) => `chutes/${model.id}`),
|
|
16
16
|
{
|
|
@@ -47,5 +47,4 @@ function applyChutesConfig(cfg) {
|
|
|
47
47
|
function applyChutesApiKeyConfig(cfg) {
|
|
48
48
|
return applyAgentDefaultModelPrimary(applyChutesProviderConfig(cfg), CHUTES_DEFAULT_MODEL_REF);
|
|
49
49
|
}
|
|
50
|
-
//#endregion
|
|
51
50
|
export { CHUTES_DEFAULT_MODEL_ID, CHUTES_DEFAULT_MODEL_REF, applyChutesApiKeyConfig, applyChutesConfig, applyChutesProviderConfig };
|
package/dist/pricing-api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { asFiniteNumberInRange, asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
2
2
|
import { normalizeModelPricingCatalog } from "openclaw/plugin-sdk/model-catalog-pricing";
|
|
3
|
-
|
|
3
|
+
// extensions/chutes/pricing-api.ts
|
|
4
4
|
/** Chutes publishes numeric USD-per-million rates, not OpenRouter's per-token strings. */
|
|
5
5
|
function normalizeChutesModelPricing(value) {
|
|
6
6
|
const pricing = asOptionalRecord(value);
|
|
@@ -18,5 +18,4 @@ function normalizeChutesModelPricing(value) {
|
|
|
18
18
|
function parseChutesPricingCatalog(payload) {
|
|
19
19
|
return normalizeModelPricingCatalog(asOptionalRecord(payload)?.data, normalizeChutesModelPricing);
|
|
20
20
|
}
|
|
21
|
-
//#endregion
|
|
22
21
|
export { normalizeChutesModelPricing, parseChutesPricingCatalog };
|
package/dist/provider-catalog.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { n as CHUTES_MODEL_CATALOG, r as discoverChutesModels, t as CHUTES_BASE_URL } from "./.setup/models-
|
|
2
|
-
|
|
1
|
+
import { n as CHUTES_MODEL_CATALOG, r as discoverChutesModels, t as CHUTES_BASE_URL } from "./.setup/models-DnSR_ZQn.mjs";
|
|
2
|
+
// extensions/chutes/provider-catalog.ts
|
|
3
3
|
function buildStaticChutesProvider() {
|
|
4
4
|
return {
|
|
5
5
|
baseUrl: CHUTES_BASE_URL,
|
|
6
6
|
api: "openai-completions",
|
|
7
|
-
models:
|
|
7
|
+
models: CHUTES_MODEL_CATALOG
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
10
|
async function buildChutesProvider(accessToken, options = {}) {
|
|
@@ -14,5 +14,4 @@ async function buildChutesProvider(accessToken, options = {}) {
|
|
|
14
14
|
models: await discoverChutesModels(accessToken, options)
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
-
//#endregion
|
|
18
17
|
export { buildChutesProvider, buildStaticChutesProvider };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/chutes-provider",
|
|
3
|
-
"version": "2026.
|
|
3
|
+
"version": "2026.11.5-beta.1",
|
|
4
4
|
"description": "OpenClaw Chutes.ai provider plugin.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"minHostVersion": ">=2026.6.8"
|
|
19
19
|
},
|
|
20
20
|
"compat": {
|
|
21
|
-
"pluginApi": ">=2026.
|
|
21
|
+
"pluginApi": ">=2026.11.5-beta.1"
|
|
22
22
|
},
|
|
23
23
|
"build": {
|
|
24
|
-
"openclawVersion": "2026.
|
|
24
|
+
"openclawVersion": "2026.11.5-beta.1",
|
|
25
25
|
"bundledDist": false
|
|
26
26
|
},
|
|
27
27
|
"release": {
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"assets/activity.svg"
|
|
41
41
|
],
|
|
42
42
|
"peerDependencies": {
|
|
43
|
-
"openclaw": ">=2026.
|
|
43
|
+
"openclaw": ">=2026.11.5-beta.1"
|
|
44
44
|
},
|
|
45
45
|
"peerDependenciesMeta": {
|
|
46
46
|
"openclaw": {
|