@openclaw/clickclack 2026.8.1-beta.2 → 2026.8.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/api.js +2 -2
- package/dist/{channel-DaHgaTy1.js → channel-Byi8SvFt.js} +45 -15
- package/dist/channel-plugin-api.js +1 -1
- package/dist/index.js +1 -1
- package/dist/{runtime-api-CPL3m5AD.js → runtime-api-DynyiJBy.js} +4 -4
- package/dist/runtime-api.js +3 -3
- package/dist/{setup-claim-CQjgPGxU.js → setup-claim-D_6JQdu5.js} +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{setup-surface-DjT-gmMe.js → setup-surface-1p34fBnm.js} +59 -19
- package/node_modules/ws/lib/permessage-deflate.js +3 -1
- package/node_modules/ws/package.json +1 -1
- package/openclaw.plugin.json +19 -0
- package/package.json +5 -5
package/dist/api.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { _ as DEFAULT_ACCOUNT_ID, b as resolveClickClackAccount, p as clickClackConfigSchema, u as createClickClackClient, v as listClickClackAccountIds, x as resolveDefaultClickClackAccountId, y as listEnabledClickClackAccounts } from "./setup-surface-
|
|
2
|
-
import { a as setClickClackRuntime, i as getClickClackRuntime, n as buildClickClackTarget, r as parseClickClackTarget, t as clickClackPlugin } from "./channel-
|
|
1
|
+
import { _ as DEFAULT_ACCOUNT_ID, b as resolveClickClackAccount, p as clickClackConfigSchema, u as createClickClackClient, v as listClickClackAccountIds, x as resolveDefaultClickClackAccountId, y as listEnabledClickClackAccounts } from "./setup-surface-1p34fBnm.js";
|
|
2
|
+
import { a as setClickClackRuntime, i as getClickClackRuntime, n as buildClickClackTarget, r as parseClickClackTarget, t as clickClackPlugin } from "./channel-Byi8SvFt.js";
|
|
3
3
|
export { DEFAULT_ACCOUNT_ID, buildClickClackTarget, clickClackConfigSchema, clickClackPlugin, createClickClackClient, getClickClackRuntime, listClickClackAccountIds, listEnabledClickClackAccounts, parseClickClackTarget, resolveClickClackAccount, resolveDefaultClickClackAccountId, setClickClackRuntime };
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { _ as DEFAULT_ACCOUNT_ID, b as resolveClickClackAccount, c as resolveWorkspaceId, f as normalizeClickClackCorrelationId, g as clickClackMeta, h as clickClackConfigAdapter, l as ClickClackHttpError, m as CLICKCLACK_CHANNEL_ID, n as clickClackSetupContract, p as clickClackConfigSchema, s as resolveChannelId, t as clickClackSetupWizard, u as createClickClackClient, y as listEnabledClickClackAccounts } from "./setup-surface-
|
|
1
|
+
import { _ as DEFAULT_ACCOUNT_ID, b as resolveClickClackAccount, c as resolveWorkspaceId, f as normalizeClickClackCorrelationId, g as clickClackMeta, h as clickClackConfigAdapter, l as ClickClackHttpError, m as CLICKCLACK_CHANNEL_ID, n as clickClackSetupContract, p as clickClackConfigSchema, s as resolveChannelId, t as clickClackSetupWizard, u as createClickClackClient, y as listEnabledClickClackAccounts } from "./setup-surface-1p34fBnm.js";
|
|
2
2
|
import { n as collectRuntimeConfigAssignments, r as secretTargetRegistryEntries } from "./secret-contract-BKkzzjBA.js";
|
|
3
|
+
import { resolveChannelMediaMaxBytes } from "openclaw/plugin-sdk/account-helpers";
|
|
3
4
|
import { parseDateStringTimestampMs } from "openclaw/plugin-sdk/number-runtime";
|
|
4
5
|
import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
|
|
5
6
|
import { readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
6
7
|
import { buildChannelOutboundSessionRoute, buildThreadAwareOutboundSessionRoute, createChatChannelPlugin } from "openclaw/plugin-sdk/channel-core";
|
|
7
|
-
import { buildChannelProgressDraftLine, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, deriveDurableFinalDeliveryRequirements } from "openclaw/plugin-sdk/channel-outbound";
|
|
8
|
+
import { buildChannelProgressDraftLine, createChannelMessageReplyPipeline, createMessageReceiptFromOutboundResults, defineChannelMessageAdapter, deriveDurableFinalDeliveryRequirements } from "openclaw/plugin-sdk/channel-outbound";
|
|
8
9
|
import { createComputedAccountStatusAdapter, createDefaultChannelRuntimeState } from "openclaw/plugin-sdk/status-helpers";
|
|
9
10
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
10
11
|
import { channelReadyPatch, channelStoppedPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
@@ -866,15 +867,16 @@ async function syncClickClackCommandMenu(params) {
|
|
|
866
867
|
await params.client.setBotCommands(commands);
|
|
867
868
|
} catch (error) {
|
|
868
869
|
const status = errorStatus(error);
|
|
870
|
+
const messagePrefix = `[${params.accountId}] ClickClack command menu sync`;
|
|
869
871
|
if (status === 403) {
|
|
870
|
-
params.log?.warn?.(
|
|
872
|
+
params.log?.warn?.(`${messagePrefix} skipped: ${formatErrorMessage(error)}; verify token/workspace command permissions or set commandMenu: false if menus are not needed`);
|
|
871
873
|
return;
|
|
872
874
|
}
|
|
873
875
|
if (status === 404) {
|
|
874
|
-
params.log?.debug?.(
|
|
876
|
+
params.log?.debug?.(`${messagePrefix} skipped: server does not support /api/bots/self/commands`);
|
|
875
877
|
return;
|
|
876
878
|
}
|
|
877
|
-
params.log?.warn?.(
|
|
879
|
+
params.log?.warn?.(`${messagePrefix} failed: ${formatErrorMessage(error)}`);
|
|
878
880
|
}
|
|
879
881
|
}
|
|
880
882
|
//#endregion
|
|
@@ -1210,13 +1212,18 @@ async function sendClickClackMedia(params) {
|
|
|
1210
1212
|
deliveryQueueId: params.deliveryQueueId,
|
|
1211
1213
|
deliveryPartIndex: params.deliveryPartIndex
|
|
1212
1214
|
});
|
|
1215
|
+
const { account, client } = createOutboundContext(params);
|
|
1216
|
+
const maxBytes = Math.min(resolveChannelMediaMaxBytes({
|
|
1217
|
+
cfg: params.cfg,
|
|
1218
|
+
accountId: account.accountId,
|
|
1219
|
+
resolveChannelLimitMb: () => account.config.mediaMaxMb
|
|
1220
|
+
}) ?? CLICKCLACK_MAX_UPLOAD_BYTES, CLICKCLACK_MAX_UPLOAD_BYTES);
|
|
1213
1221
|
const preloadedMedia = nonces.upload ? void 0 : await loadOutboundMediaFromUrl(params.mediaUrl, {
|
|
1214
|
-
maxBytes
|
|
1222
|
+
maxBytes,
|
|
1215
1223
|
mediaAccess: params.mediaAccess,
|
|
1216
1224
|
mediaLocalRoots: params.mediaLocalRoots,
|
|
1217
1225
|
mediaReadFile: params.mediaReadFile
|
|
1218
1226
|
});
|
|
1219
|
-
const { account, client } = createOutboundContext(params);
|
|
1220
1227
|
const workspaceId = await resolveWorkspaceId(client, account.workspace);
|
|
1221
1228
|
const persistedUpload = nonces.upload ? await client.findUploadByNonce({
|
|
1222
1229
|
workspaceId,
|
|
@@ -1227,7 +1234,7 @@ async function sendClickClackMedia(params) {
|
|
|
1227
1234
|
let mediaFilename = preloadedMedia?.fileName?.trim();
|
|
1228
1235
|
if (!upload) {
|
|
1229
1236
|
const media = preloadedMedia ?? await loadOutboundMediaFromUrl(params.mediaUrl, {
|
|
1230
|
-
maxBytes
|
|
1237
|
+
maxBytes,
|
|
1231
1238
|
mediaAccess: params.mediaAccess,
|
|
1232
1239
|
mediaLocalRoots: params.mediaLocalRoots,
|
|
1233
1240
|
mediaReadFile: params.mediaReadFile
|
|
@@ -1591,7 +1598,7 @@ function resolveClickClackAgentRunId(messageId) {
|
|
|
1591
1598
|
}
|
|
1592
1599
|
async function dispatchModelReply(params) {
|
|
1593
1600
|
const runtime = getClickClackRuntime();
|
|
1594
|
-
const
|
|
1601
|
+
const result = await runtime.llm.complete({
|
|
1595
1602
|
agentId: params.route.agentId,
|
|
1596
1603
|
model: params.account.model,
|
|
1597
1604
|
purpose: "clickclack bot reply",
|
|
@@ -1600,14 +1607,28 @@ async function dispatchModelReply(params) {
|
|
|
1600
1607
|
role: "user",
|
|
1601
1608
|
content: params.message.body
|
|
1602
1609
|
}]
|
|
1603
|
-
})
|
|
1604
|
-
|
|
1610
|
+
});
|
|
1611
|
+
const completion = result.text.trim();
|
|
1612
|
+
if (!completion) {
|
|
1605
1613
|
runtime.logging.getChildLogger({
|
|
1606
1614
|
plugin: "clickclack",
|
|
1607
1615
|
feature: "model-reply"
|
|
1608
1616
|
}).warn(`[${params.account.accountId}] ClickClack model reply produced no sendable text`);
|
|
1609
1617
|
return;
|
|
1610
1618
|
}
|
|
1619
|
+
const replyPipeline = createChannelMessageReplyPipeline({
|
|
1620
|
+
cfg: params.cfg,
|
|
1621
|
+
agentId: params.route.agentId,
|
|
1622
|
+
channel: CHANNEL_ID$1,
|
|
1623
|
+
accountId: params.account.accountId
|
|
1624
|
+
});
|
|
1625
|
+
replyPipeline.onModelSelected?.({
|
|
1626
|
+
provider: result.provider,
|
|
1627
|
+
model: result.model,
|
|
1628
|
+
thinkLevel: void 0
|
|
1629
|
+
});
|
|
1630
|
+
const responsePrefix = replyPipeline.resolveResponsePrefix?.();
|
|
1631
|
+
const text = responsePrefix && !completion.startsWith(responsePrefix) ? `${responsePrefix} ${completion}` : completion;
|
|
1611
1632
|
await sendClickClackText({
|
|
1612
1633
|
cfg: params.cfg,
|
|
1613
1634
|
accountId: params.account.accountId,
|
|
@@ -1868,7 +1889,7 @@ function parseSocketEvent(data) {
|
|
|
1868
1889
|
}
|
|
1869
1890
|
async function processEvent(params) {
|
|
1870
1891
|
if (params.event.type !== "message.created" && params.event.type !== "thread.reply_created") return;
|
|
1871
|
-
if (payloadString(params.event, "author_id") === params.botUserId) return;
|
|
1892
|
+
if (params.abortSignal.aborted || payloadString(params.event, "author_id") === params.botUserId) return;
|
|
1872
1893
|
const correlationId = eventCorrelationId(params.event);
|
|
1873
1894
|
const message = await resolveEventMessage({
|
|
1874
1895
|
client: correlationId ? createClickClackClient({
|
|
@@ -1882,12 +1903,13 @@ async function processEvent(params) {
|
|
|
1882
1903
|
params.log?.warn?.(`[${params.account.accountId}] skipped unreadable ClickClack message before agent dispatch: type=${params.event.type} messageId=${payloadString(params.event, "message_id") || "unknown"}`);
|
|
1883
1904
|
return;
|
|
1884
1905
|
}
|
|
1885
|
-
if (message.author_id === params.botUserId) return;
|
|
1906
|
+
if (params.abortSignal.aborted || message.author_id === params.botUserId) return;
|
|
1886
1907
|
const access = await resolveClickClackInboundAccess({
|
|
1887
1908
|
account: params.account,
|
|
1888
1909
|
config: params.config,
|
|
1889
1910
|
message
|
|
1890
1911
|
});
|
|
1912
|
+
if (params.abortSignal.aborted) return;
|
|
1891
1913
|
if (!access.shouldDispatch) {
|
|
1892
1914
|
params.log?.info(`[${params.account.accountId}] skipped ClickClack message before agent dispatch: kind=${message.direct_conversation_id ? "dm" : "group"} requireMention=${access.requireMention ?? "unknown"} wasMentioned=${access.mentionFacts.wasMentioned} hasAnyMention=${access.mentionFacts.hasAnyMention ?? "unknown"} commandAuthorized=${access.commandAuthorized}`);
|
|
1893
1915
|
return;
|
|
@@ -1937,6 +1959,7 @@ async function startClickClackGatewayAccount(ctx) {
|
|
|
1937
1959
|
botHandle: me.handle
|
|
1938
1960
|
};
|
|
1939
1961
|
const processIncomingEvent = (event) => processEvent({
|
|
1962
|
+
abortSignal: ctx.abortSignal,
|
|
1940
1963
|
account,
|
|
1941
1964
|
config: ctx.cfg,
|
|
1942
1965
|
client,
|
|
@@ -1948,7 +1971,8 @@ async function startClickClackGatewayAccount(ctx) {
|
|
|
1948
1971
|
if (account.commandMenu) await syncClickClackCommandMenu({
|
|
1949
1972
|
cfg: ctx.cfg,
|
|
1950
1973
|
client,
|
|
1951
|
-
log: ctx.log
|
|
1974
|
+
log: ctx.log,
|
|
1975
|
+
accountId: account.accountId
|
|
1952
1976
|
});
|
|
1953
1977
|
ctx.setStatus({
|
|
1954
1978
|
accountId: account.accountId,
|
|
@@ -2015,6 +2039,7 @@ async function startClickClackGatewayAccount(ctx) {
|
|
|
2015
2039
|
socket.on("message", (data) => {
|
|
2016
2040
|
if (closing || settled) return;
|
|
2017
2041
|
messageQueue = messageQueue.then(async () => {
|
|
2042
|
+
if (ctx.abortSignal.aborted) return;
|
|
2018
2043
|
const event = parseSocketEvent(data);
|
|
2019
2044
|
if (!event) {
|
|
2020
2045
|
ctx.log?.warn?.(`[${account.accountId}] skipped malformed ClickClack websocket event`);
|
|
@@ -2156,6 +2181,7 @@ const clickClackPlugin = createChatChannelPlugin({
|
|
|
2156
2181
|
capabilities: {
|
|
2157
2182
|
chatTypes: ["direct", "group"],
|
|
2158
2183
|
threads: true,
|
|
2184
|
+
media: true,
|
|
2159
2185
|
blockStreaming: true
|
|
2160
2186
|
},
|
|
2161
2187
|
reload: { configPrefixes: ["channels.clickclack"] },
|
|
@@ -2222,7 +2248,11 @@ const clickClackPlugin = createChatChannelPlugin({
|
|
|
2222
2248
|
name: account.name,
|
|
2223
2249
|
enabled: account.enabled,
|
|
2224
2250
|
configured: account.configured,
|
|
2225
|
-
|
|
2251
|
+
extra: {
|
|
2252
|
+
baseUrl: account.baseUrl,
|
|
2253
|
+
tokenSource: account.tokenSource,
|
|
2254
|
+
tokenStatus: account.tokenStatus
|
|
2255
|
+
}
|
|
2226
2256
|
})
|
|
2227
2257
|
}),
|
|
2228
2258
|
gateway: { startAccount: startClickClackGatewayAccount },
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as clickClackPlugin } from "./channel-
|
|
1
|
+
import { t as clickClackPlugin } from "./channel-Byi8SvFt.js";
|
|
2
2
|
export { clickClackPlugin };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as registerClickClackDiscussions } from "./runtime-api-
|
|
1
|
+
import { t as registerClickClackDiscussions } from "./runtime-api-DynyiJBy.js";
|
|
2
2
|
import { defineBundledChannelEntry } from "openclaw/plugin-sdk/channel-entry-contract";
|
|
3
3
|
//#region extensions/clickclack/index.ts
|
|
4
4
|
/**
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { b as resolveClickClackAccount, d as isClickClackChannelNameConflict, l as ClickClackHttpError, u as createClickClackClient, v as listClickClackAccountIds } from "./setup-surface-
|
|
2
|
-
import { C as slugifyDiscussionLabel, D as listPendingDiscussionOpens, E as clearPendingDiscussionOpen, O as recordPendingDiscussionOpen, S as resolveDiscussionLabel, T as clearDiscussionBindingGeneration, _ as getClickClackDiscussionBindingStore, b as fallbackDiscussionLabel, c as markClickClackDiscussionChannelIdentityRevoked, d as discussionInfoForBinding, f as normalizedServerBaseUrl, g as bindingMatchesActiveSessionIncarnation, h as attachBindingToCurrentActiveSession, k as reserveDiscussionBindingGeneration, l as markClickClackDiscussionChannelRevoked, o as clearClickClackDiscussionChannelRevoked, p as resolveDiscussionBindingAccount, s as isClickClackDiscussionChannelRevoked, u as discussionAccounts, v as discussionCredentialFingerprint, w as truncateDiscussionDisplayTitle, x as isDiscussionSessionKey, y as discussionExternalRef } from "./channel-
|
|
1
|
+
import { b as resolveClickClackAccount, d as isClickClackChannelNameConflict, l as ClickClackHttpError, u as createClickClackClient, v as listClickClackAccountIds } from "./setup-surface-1p34fBnm.js";
|
|
2
|
+
import { C as slugifyDiscussionLabel, D as listPendingDiscussionOpens, E as clearPendingDiscussionOpen, O as recordPendingDiscussionOpen, S as resolveDiscussionLabel, T as clearDiscussionBindingGeneration, _ as getClickClackDiscussionBindingStore, b as fallbackDiscussionLabel, c as markClickClackDiscussionChannelIdentityRevoked, d as discussionInfoForBinding, f as normalizedServerBaseUrl, g as bindingMatchesActiveSessionIncarnation, h as attachBindingToCurrentActiveSession, k as reserveDiscussionBindingGeneration, l as markClickClackDiscussionChannelRevoked, o as clearClickClackDiscussionChannelRevoked, p as resolveDiscussionBindingAccount, s as isClickClackDiscussionChannelRevoked, u as discussionAccounts, v as discussionCredentialFingerprint, w as truncateDiscussionDisplayTitle, x as isDiscussionSessionKey, y as discussionExternalRef } from "./channel-Byi8SvFt.js";
|
|
3
3
|
import "./api.js";
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
5
|
import { buildControlUiSessionPath, registerSessionDiscussionProvider } from "openclaw/plugin-sdk/session-discussion";
|
|
6
6
|
import { createSessionVisibilityChecker } from "openclaw/plugin-sdk/session-visibility";
|
|
7
|
-
import {
|
|
7
|
+
import { resolveSessionAgentIdStrict } from "openclaw/plugin-sdk/agent-scope-runtime";
|
|
8
8
|
import { textResult } from "openclaw/plugin-sdk/tool-results";
|
|
9
9
|
//#region extensions/clickclack/src/discussions/binding-retention.ts
|
|
10
10
|
var DetachedDiscussionBindingRetention = class {
|
|
@@ -257,7 +257,7 @@ async function openClickClackDiscussionBinding(params) {
|
|
|
257
257
|
if (listPendingDiscussionOpens(runtime).some((pending) => pending.sessionKey === sessionKey)) throw new Error("A previous ClickClack discussion open is still unresolved; restore its credential and retry");
|
|
258
258
|
}
|
|
259
259
|
const config = runtime.config.current();
|
|
260
|
-
const agentId =
|
|
260
|
+
const agentId = resolveSessionAgentIdStrict({
|
|
261
261
|
config,
|
|
262
262
|
sessionKey
|
|
263
263
|
});
|
package/dist/runtime-api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b as resolveClickClackAccount, u as createClickClackClient } from "./setup-surface-
|
|
2
|
-
import { a as setClickClackRuntime, r as parseClickClackTarget } from "./channel-
|
|
3
|
-
import { t as registerClickClackDiscussions } from "./runtime-api-
|
|
1
|
+
import { b as resolveClickClackAccount, u as createClickClackClient } from "./setup-surface-1p34fBnm.js";
|
|
2
|
+
import { a as setClickClackRuntime, r as parseClickClackTarget } from "./channel-Byi8SvFt.js";
|
|
3
|
+
import { t as registerClickClackDiscussions } from "./runtime-api-DynyiJBy.js";
|
|
4
4
|
export { createClickClackClient, parseClickClackTarget, registerClickClackDiscussions, resolveClickClackAccount, setClickClackRuntime };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as isClickClackSetupLoopbackHost, i as buildClickClackSetupClaimUrl, o as requireClickClackSetupApiBaseUrl } from "./setup-surface-
|
|
1
|
+
import { a as isClickClackSetupLoopbackHost, i as buildClickClackSetupClaimUrl, o as requireClickClackSetupApiBaseUrl } from "./setup-surface-1p34fBnm.js";
|
|
2
2
|
import { createProviderOperationDeadline, readProviderJsonResponse, readResponseTextLimited, resolveProviderOperationTimeoutMs } from "openclaw/plugin-sdk/provider-http";
|
|
3
3
|
import { fetchWithSsrFGuard, resolvePinnedHostnameWithPolicy, ssrfPolicyFromHttpBaseUrlAllowedHostname } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
4
4
|
import { withTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
|
package/dist/setup-plugin-api.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as clickClackMeta, h as clickClackConfigAdapter, n as clickClackSetupContract, p as clickClackConfigSchema, t as clickClackSetupWizard } from "./setup-surface-
|
|
1
|
+
import { g as clickClackMeta, h as clickClackConfigAdapter, n as clickClackSetupContract, p as clickClackConfigSchema, t as clickClackSetupWizard } from "./setup-surface-1p34fBnm.js";
|
|
2
2
|
//#region extensions/clickclack/src/channel.setup.ts
|
|
3
3
|
const clickClackSetupPlugin = {
|
|
4
4
|
id: "clickclack",
|
|
@@ -3,9 +3,9 @@ import { DEFAULT_ACCOUNT_ID, DEFAULT_ACCOUNT_ID as DEFAULT_ACCOUNT_ID$2, normali
|
|
|
3
3
|
import { resolveNormalizedAccountEntry } from "openclaw/plugin-sdk/account-resolution-runtime";
|
|
4
4
|
import { resolveIntegerOption } from "openclaw/plugin-sdk/number-runtime";
|
|
5
5
|
import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
|
|
6
|
-
import { resolveDefaultSecretProviderAlias } from "openclaw/plugin-sdk/provider-auth";
|
|
7
6
|
import { tryReadSecretFileSync } from "openclaw/plugin-sdk/secret-file-runtime";
|
|
8
|
-
import { buildSecretInputSchema,
|
|
7
|
+
import { buildSecretInputSchema, normalizeSecretInputString, resolveSecretInputString } from "openclaw/plugin-sdk/secret-input";
|
|
8
|
+
import { canResolveEnvSecretRefInReadOnlyPath } from "openclaw/plugin-sdk/secret-ref-readonly";
|
|
9
9
|
import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
10
10
|
import { getChatChannelMeta } from "openclaw/plugin-sdk/channel-plugin-common";
|
|
11
11
|
import { ChannelBotLoopProtectionSchema, buildChannelAllowBotsSchema, buildChannelConfigSchema, buildMultiAccountChannelSchema } from "openclaw/plugin-sdk/channel-config-schema";
|
|
@@ -87,7 +87,20 @@ function resolveClickClackAccountConfig(cfg, accountId) {
|
|
|
87
87
|
}
|
|
88
88
|
function resolveClickClackToken(params) {
|
|
89
89
|
const tokenFile = params.tokenFile?.trim();
|
|
90
|
-
if (tokenFile)
|
|
90
|
+
if (tokenFile) {
|
|
91
|
+
const accountTokenFile = resolveNormalizedAccountEntry(params.cfg.channels?.clickclack?.accounts, params.accountId, normalizeAccountId)?.tokenFile?.trim();
|
|
92
|
+
const result = tryReadSecretFileSync(tokenFile, "ClickClack bot token", { rejectSymlink: true }, { configPath: accountTokenFile ? `channels.clickclack.accounts.${params.accountId}.tokenFile` : "channels.clickclack.tokenFile" });
|
|
93
|
+
return result.status === "available" ? {
|
|
94
|
+
token: result.value,
|
|
95
|
+
tokenSource: "tokenFile",
|
|
96
|
+
tokenStatus: "available"
|
|
97
|
+
} : {
|
|
98
|
+
token: "",
|
|
99
|
+
tokenSource: "tokenFile",
|
|
100
|
+
tokenStatus: "configured_unavailable",
|
|
101
|
+
credentialDiagnostics: [result.diagnostic]
|
|
102
|
+
};
|
|
103
|
+
}
|
|
91
104
|
const resolved = resolveSecretInputString({
|
|
92
105
|
value: params.value,
|
|
93
106
|
path: params.accountId === DEFAULT_ACCOUNT_ID$2 ? "channels.clickclack.token" : `channels.clickclack.accounts.${params.accountId}.token`,
|
|
@@ -95,21 +108,46 @@ function resolveClickClackToken(params) {
|
|
|
95
108
|
mode: "inspect"
|
|
96
109
|
});
|
|
97
110
|
if (resolved.status !== "available") {
|
|
98
|
-
if (resolved.status === "missing" && params.accountId === DEFAULT_ACCOUNT_ID$2)
|
|
111
|
+
if (resolved.status === "missing" && params.accountId === DEFAULT_ACCOUNT_ID$2) {
|
|
112
|
+
const token = normalizeSecretInputString((params.env ?? process.env).CLICKCLACK_BOT_TOKEN);
|
|
113
|
+
return token ? {
|
|
114
|
+
token,
|
|
115
|
+
tokenSource: "env",
|
|
116
|
+
tokenStatus: "available"
|
|
117
|
+
} : {
|
|
118
|
+
token: "",
|
|
119
|
+
tokenSource: "none",
|
|
120
|
+
tokenStatus: "missing"
|
|
121
|
+
};
|
|
122
|
+
}
|
|
99
123
|
if (resolved.status === "configured_unavailable" && resolved.ref.source === "env") {
|
|
100
|
-
|
|
101
|
-
|
|
124
|
+
if (!canResolveEnvSecretRefInReadOnlyPath({
|
|
125
|
+
cfg: params.cfg,
|
|
126
|
+
...resolved.ref
|
|
127
|
+
})) {
|
|
128
|
+
const providerConfig = params.cfg.secrets?.providers?.[resolved.ref.provider];
|
|
129
|
+
if (!providerConfig) throw new Error(`Secret provider "${resolved.ref.provider}" is not configured (ref: env:${resolved.ref.provider}:${resolved.ref.id}).`);
|
|
102
130
|
if (providerConfig.source !== "env") throw new Error(`Secret provider "${resolved.ref.provider}" has source "${providerConfig.source}" but ref requests "env".`);
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
131
|
+
throw new Error(`Environment variable "${resolved.ref.id}" is not allowlisted in secrets.providers.${resolved.ref.provider}.allowlist.`);
|
|
132
|
+
}
|
|
133
|
+
const token = normalizeSecretInputString((params.env ?? process.env)[resolved.ref.id]);
|
|
134
|
+
return {
|
|
135
|
+
token: token ?? "",
|
|
136
|
+
tokenSource: "config",
|
|
137
|
+
tokenStatus: token ? "available" : "configured_unavailable"
|
|
138
|
+
};
|
|
106
139
|
}
|
|
107
|
-
return
|
|
140
|
+
return {
|
|
141
|
+
token: "",
|
|
142
|
+
tokenSource: resolved.status === "missing" ? "none" : "config",
|
|
143
|
+
tokenStatus: resolved.status
|
|
144
|
+
};
|
|
108
145
|
}
|
|
109
|
-
return
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
146
|
+
return {
|
|
147
|
+
token: resolved.value,
|
|
148
|
+
tokenSource: "config",
|
|
149
|
+
tokenStatus: "available"
|
|
150
|
+
};
|
|
113
151
|
}
|
|
114
152
|
/**
|
|
115
153
|
* Builds the normalized account snapshot used by gateway, outbound delivery,
|
|
@@ -134,10 +172,10 @@ function resolveClickClackAccount(params) {
|
|
|
134
172
|
return {
|
|
135
173
|
accountId,
|
|
136
174
|
enabled,
|
|
137
|
-
configured: Boolean(baseUrl && token && workspace),
|
|
175
|
+
configured: Boolean(baseUrl && token.tokenStatus !== "missing" && workspace),
|
|
138
176
|
name: normalizeOptionalString(merged.name),
|
|
139
177
|
baseUrl,
|
|
140
|
-
token,
|
|
178
|
+
...token,
|
|
141
179
|
workspace,
|
|
142
180
|
botUserId: normalizeOptionalString(merged.botUserId),
|
|
143
181
|
agentId: normalizeOptionalString(merged.agentId),
|
|
@@ -212,6 +250,8 @@ const ClickClackAccountConfigSchema = z.object({
|
|
|
212
250
|
name: z.string().optional(),
|
|
213
251
|
enabled: z.boolean().optional(),
|
|
214
252
|
configWrites: z.boolean().optional(),
|
|
253
|
+
mediaMaxMb: z.number().positive().optional(),
|
|
254
|
+
responsePrefix: z.string().optional(),
|
|
215
255
|
baseUrl: z.string().url().optional(),
|
|
216
256
|
apiBaseUrl: z.string().url().optional(),
|
|
217
257
|
token: buildSecretInputSchema().optional(),
|
|
@@ -250,7 +290,7 @@ const ClickClackAccountConfigSchema = z.object({
|
|
|
250
290
|
* Config schema exported to core so `openclaw doctor` and config validation
|
|
251
291
|
* understand both default and named ClickClack accounts.
|
|
252
292
|
*/
|
|
253
|
-
const clickClackConfigSchema = buildChannelConfigSchema(buildMultiAccountChannelSchema(ClickClackAccountConfigSchema, { accountSchema: ClickClackAccountConfigSchema.partial() }));
|
|
293
|
+
const clickClackConfigSchema = buildChannelConfigSchema(buildMultiAccountChannelSchema(ClickClackAccountConfigSchema.extend({ historyLimit: z.number().int().min(0).optional() }), { accountSchema: ClickClackAccountConfigSchema.partial() }));
|
|
254
294
|
//#endregion
|
|
255
295
|
//#region extensions/clickclack/src/http-client.ts
|
|
256
296
|
/**
|
|
@@ -482,7 +522,7 @@ function createClickClackClient(options) {
|
|
|
482
522
|
},
|
|
483
523
|
createUpload: async (params) => {
|
|
484
524
|
const form = new FormData();
|
|
485
|
-
const bytes = new Uint8Array(params.buffer);
|
|
525
|
+
const bytes = params.buffer.buffer instanceof ArrayBuffer ? new Uint8Array(params.buffer.buffer, params.buffer.byteOffset, params.buffer.byteLength) : Uint8Array.from(params.buffer);
|
|
486
526
|
form.append("file", new Blob([bytes], { type: params.contentType }), params.filename);
|
|
487
527
|
const query = new URLSearchParams({ workspace_id: params.workspaceId });
|
|
488
528
|
if (params.nonce) query.set("nonce", params.nonce);
|
|
@@ -779,7 +819,7 @@ const clickClackSetupAdapter = {
|
|
|
779
819
|
const claimUrl = setup.exactClaimUrl && !privateApiBaseUrl ? setup.exactClaimUrl : buildClickClackSetupClaimUrl(privateApiBaseUrl ?? setup.baseUrl);
|
|
780
820
|
let claim;
|
|
781
821
|
try {
|
|
782
|
-
const { claimClickClackSetupCode } = await import("./setup-claim-
|
|
822
|
+
const { claimClickClackSetupCode } = await import("./setup-claim-D_6JQdu5.js");
|
|
783
823
|
claim = await claimClickClackSetupCode({
|
|
784
824
|
claimUrl,
|
|
785
825
|
code: setup.code,
|
|
@@ -167,7 +167,9 @@ class PerMessageDeflate {
|
|
|
167
167
|
(typeof opts.serverMaxWindowBits === 'number' &&
|
|
168
168
|
opts.serverMaxWindowBits > params.server_max_window_bits))) ||
|
|
169
169
|
(typeof opts.clientMaxWindowBits === 'number' &&
|
|
170
|
-
|
|
170
|
+
(typeof params.client_max_window_bits === 'number'
|
|
171
|
+
? opts.clientMaxWindowBits > params.client_max_window_bits
|
|
172
|
+
: !params.client_max_window_bits))
|
|
171
173
|
) {
|
|
172
174
|
return false;
|
|
173
175
|
}
|
package/openclaw.plugin.json
CHANGED
|
@@ -24,6 +24,13 @@
|
|
|
24
24
|
"configWrites": {
|
|
25
25
|
"type": "boolean"
|
|
26
26
|
},
|
|
27
|
+
"mediaMaxMb": {
|
|
28
|
+
"type": "number",
|
|
29
|
+
"exclusiveMinimum": 0
|
|
30
|
+
},
|
|
31
|
+
"responsePrefix": {
|
|
32
|
+
"type": "string"
|
|
33
|
+
},
|
|
27
34
|
"baseUrl": {
|
|
28
35
|
"type": "string",
|
|
29
36
|
"format": "uri"
|
|
@@ -306,6 +313,11 @@
|
|
|
306
313
|
},
|
|
307
314
|
"additionalProperties": false
|
|
308
315
|
},
|
|
316
|
+
"historyLimit": {
|
|
317
|
+
"type": "integer",
|
|
318
|
+
"minimum": 0,
|
|
319
|
+
"maximum": 9007199254740991
|
|
320
|
+
},
|
|
309
321
|
"accounts": {
|
|
310
322
|
"type": "object",
|
|
311
323
|
"propertyNames": {
|
|
@@ -323,6 +335,13 @@
|
|
|
323
335
|
"configWrites": {
|
|
324
336
|
"type": "boolean"
|
|
325
337
|
},
|
|
338
|
+
"mediaMaxMb": {
|
|
339
|
+
"type": "number",
|
|
340
|
+
"exclusiveMinimum": 0
|
|
341
|
+
},
|
|
342
|
+
"responsePrefix": {
|
|
343
|
+
"type": "string"
|
|
344
|
+
},
|
|
326
345
|
"baseUrl": {
|
|
327
346
|
"type": "string",
|
|
328
347
|
"format": "uri"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openclaw/clickclack",
|
|
3
|
-
"version": "2026.8.1
|
|
3
|
+
"version": "2026.8.1",
|
|
4
4
|
"description": "OpenClaw ClickClack channel plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
"./runtime-api.js": "./dist/runtime-api.js"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"ws": "8.21.
|
|
12
|
+
"ws": "8.21.3",
|
|
13
13
|
"zod": "4.4.3"
|
|
14
14
|
},
|
|
15
15
|
"peerDependencies": {
|
|
16
|
-
"openclaw": ">=2026.8.1
|
|
16
|
+
"openclaw": ">=2026.8.1"
|
|
17
17
|
},
|
|
18
18
|
"peerDependenciesMeta": {
|
|
19
19
|
"openclaw": {
|
|
@@ -139,10 +139,10 @@
|
|
|
139
139
|
"allowInvalidConfigRecovery": true
|
|
140
140
|
},
|
|
141
141
|
"compat": {
|
|
142
|
-
"pluginApi": ">=2026.8.1
|
|
142
|
+
"pluginApi": ">=2026.8.1"
|
|
143
143
|
},
|
|
144
144
|
"build": {
|
|
145
|
-
"openclawVersion": "2026.8.1
|
|
145
|
+
"openclawVersion": "2026.8.1",
|
|
146
146
|
"bundledDist": false
|
|
147
147
|
},
|
|
148
148
|
"release": {
|