@vibe-lark/larkpal 0.1.86 → 0.1.87
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/account-id-BM1T6029-BzQ_cMoi.mjs +1 -0
- package/dist/activation-context--5yu1dPF-XV0Y0pTy.mjs +1 -0
- package/dist/anthropic-CFZUCb1w.mjs +39 -0
- package/dist/assistant-visible-text-DuFWokAt-BOJV_zwc.mjs +9 -0
- package/dist/azure-openai-responses-BEuiMaF-.mjs +1 -0
- package/dist/boundary-file-read-BSd9MXPy-gnNVhPKT.mjs +1 -0
- package/dist/browser-lifecycle-cleanup-BdNsMhMD-BM97qA_M.mjs +1 -0
- package/dist/build-Bkj0hOS2.mjs +3 -0
- package/dist/bundled-compat-BpaDaAAu-DJtrIX6i.mjs +27 -0
- package/dist/bundled-dir-U738ay4K-BxbzrJOo.mjs +1 -0
- package/dist/call-DimWbpgJ-B4pv55RH.mjs +20 -0
- package/dist/channel-bootstrap.runtime-BVclcGv1-CEZ0-JP9.mjs +1 -0
- package/dist/channel-bootstrap.runtime-Cwcr38m2-Dt6QlQkX.mjs +1 -0
- package/dist/chunk-DHbaKqs-.mjs +1 -0
- package/dist/cli.mjs +7 -92
- package/dist/command-format-LSnUCVVF-Dn4h9IOh.mjs +16 -0
- package/dist/config-Bim2pi8a-03N-28sw.mjs +1 -0
- package/dist/delivery-context.shared-j5hC5qb1-BSLQG47q.mjs +1 -0
- package/dist/diagnostic-ClMwNnUA-BMKvPQJT.mjs +1 -0
- package/dist/dist-J5UB83Ws.mjs +601 -0
- package/dist/dist-coestTs9.mjs +5 -0
- package/dist/env-api-keys-Cuz5irWW.mjs +1 -0
- package/dist/event-stream-B7Ei41Bu.mjs +1 -0
- package/dist/facade-loader-DFzIYYt_-4bzFvy-b.mjs +1 -0
- package/dist/from-Ba69_5cR.mjs +14 -0
- package/dist/gateway-method-policy-C7rf0SeV-CTJcMQCE.mjs +1 -0
- package/dist/github-copilot-headers-BfhryVuU.mjs +1 -0
- package/dist/google-ABo-1guT.mjs +1 -0
- package/dist/google-gemini-cli-CGlN1zUA.mjs +2 -0
- package/dist/google-shared-C60sNhwd.mjs +301 -0
- package/dist/google-vertex-De0nAItu.mjs +1 -0
- package/dist/hash-Dw-N8Y9l.mjs +1 -0
- package/dist/headers-Bpsp70B9.mjs +1 -0
- package/dist/home-dir-C44RaPME-B5iLWwCq.mjs +1 -0
- package/dist/ids-BPsM98Uu-CJBJAeVC.mjs +1 -0
- package/dist/image-2w3cApg7-CrpUMCvm.mjs +3 -0
- package/dist/interactive-init-C5MFL5MW.mjs +8 -0
- package/dist/io-CH2g3vsv-JJtUIa_U.mjs +10 -0
- package/dist/jiti-loader-cache-Bat69wam-DNIteTtO.mjs +9 -0
- package/dist/json-file-BQRNuxmK-hRjIgOXI.mjs +1 -0
- package/dist/json-parse-BESd8UAM.mjs +3 -0
- package/dist/jws-YaZ38F_i.mjs +12 -0
- package/dist/lark-cli-provider-BLMxH6CN.mjs +4 -0
- package/dist/lark-logger-xpMKNNtY.mjs +1 -0
- package/dist/live-smoke-DpURW676.mjs +33 -0
- package/dist/load-context-mb7uvLSn-3xYwSnOZ.mjs +1 -0
- package/dist/loader-708jrx4Y-BbJRXNlQ.mjs +4 -0
- package/dist/main.mjs +153 -74571
- package/dist/manifest-registry-_hxKCS2K-OL8KK_o4.mjs +15 -0
- package/dist/mcp-server.mjs +4 -527
- package/dist/message-channel-Bk_YHfQg-n2Hw2Y0L.mjs +1 -0
- package/dist/message-channel-core-DTA--Gjh-CIh10vfo.mjs +1 -0
- package/dist/message.config.runtime-K-k4XOyq-F_h0Cgkl.mjs +1 -0
- package/dist/message.gateway.runtime-DqHOHRTQ-ge4c5p4s.mjs +1 -0
- package/dist/mistral-DyL3Zo1b.mjs +7 -0
- package/dist/model-auth-env-oyg2Hexc-DJbt9J3o.mjs +1 -0
- package/dist/models-config-BmpSQJQF-BL6S5qAo.mjs +1 -0
- package/dist/models-config.runtime-SOhLEw-f.mjs +1 -0
- package/dist/multipart-parser-B9dwXBqu.mjs +2 -0
- package/dist/oauth-25y2wc7K.mjs +75 -0
- package/dist/openai-C-rgGb7X.mjs +16 -0
- package/dist/openai-codex-responses-BbyAPsP1.mjs +7 -0
- package/dist/openai-completions-Bu5qvQzb.mjs +5 -0
- package/dist/openai-responses-pIdwQBc4.mjs +1 -0
- package/dist/openai-responses-shared-DqW1JSux.mjs +10 -0
- package/dist/paths-D6msg0S1-BO4XgM1u.mjs +1 -0
- package/dist/paths-D92DjaZ--DdtJ-zYp.mjs +1 -0
- package/dist/pi-model-discovery-Bd0TWzo8-DvSM0eWu.mjs +1 -0
- package/dist/pi-model-discovery-runtime-PrjWOmsV.mjs +1 -0
- package/dist/pi-tools.before-tool-call.runtime-Bn7uqKie-WPxU5oNX.mjs +2 -0
- package/dist/plugin-auto-enable-DdH3n9V8-Dr_bUXkG.mjs +1 -0
- package/dist/process-scoped-map-B2cWkYET-Co-i-MXA.mjs +1 -0
- package/dist/provider-discovery.runtime-DY0VWQ81.mjs +1 -0
- package/dist/provider-model-compat-CFqcq0it-BUwZENrz.mjs +1 -0
- package/dist/provider-runtime-C8rljsNs-BDvu6FW3.mjs +1 -0
- package/dist/provider-runtime-CT50mNIX-DImw7ZZu.mjs +79 -0
- package/dist/provider-stream-COLujAAo-Dpq1DSIk.mjs +248 -0
- package/dist/providers.runtime-Ba7tOlq7-B4t6ywCr.mjs +1 -0
- package/dist/public-surface-loader-BVl0NQAE-TfJ3izj1.mjs +1 -0
- package/dist/resolve-C33B7eeu-DZM_z6Wr.mjs +1 -0
- package/dist/runtime-Cym-fqI8-1GOIuRRQ.mjs +1 -0
- package/dist/runtime-channel-state-CohMybAh-BBzhl07Q.mjs +1 -0
- package/dist/runtime-snapshot-C54O1-gI-DxusscPf.mjs +1 -0
- package/dist/runtime-state-IBOIXKOx-Cw1GA1td.mjs +1 -0
- package/dist/runtime-web-tools-fallback.runtime-Ca-qn1mj-BsYE2gOd.mjs +1 -0
- package/dist/runtime-web-tools-manifest.runtime-BgxQTjmq-P6MKP9gQ.mjs +1 -0
- package/dist/runtime-web-tools-public-artifacts.runtime-D9qcoWIX-5VoyjouO.mjs +1 -0
- package/dist/session-archive.runtime-B52_5vs4-cU2tYbBz.mjs +1 -0
- package/dist/session-key-Cn2QoOyX-QZeYmbxd.mjs +1 -0
- package/dist/session-transcript-files.fs-DEeFXruQ-CXIAFSsr.mjs +1 -0
- package/dist/src-CCDx_C-U.mjs +3 -0
- package/dist/src-DACmA9V6.mjs +5 -0
- package/dist/subagent-announce-L5WsQatW--rMn240x.mjs +2 -0
- package/dist/subagent-announce.registry.runtime-DiqZyeTs-DNfNHsls.mjs +1 -0
- package/dist/subagent-registry-steer-runtime-DFgZFC0j-XYS1_qwl.mjs +1 -0
- package/dist/subagent-system-prompt-C1qnN--K-CsU4f97T.mjs +23 -0
- package/dist/target-parsing-loaded-DKkb6jJY-B830OA1a.mjs +12 -0
- package/dist/task-registry-delivery-runtime-Dd1CUkZF-B2Hj2k8C.mjs +16 -0
- package/dist/task-registry-delivery-runtime-ragbeVx5-Bdvo2Q5u.mjs +1 -0
- package/dist/thinking-Bh-7MqXz-uApNUe6g.mjs +1 -0
- package/dist/transcript-E_-ISOkD-VTwb782D.mjs +5 -0
- package/dist/transcript.runtime-BqhvZZdl-B4E0TiX5.mjs +1 -0
- package/dist/transform-messages-BTA3xbAI.mjs +1 -0
- package/dist/web-provider-public-artifacts-BlpRwIUS-DbVhDOrY.mjs +1 -0
- package/dist/web-search-providers.runtime--0aUtC3b-Bjh4Bmrz.mjs +1 -0
- package/package.json +2 -3
- package/dist/account-id-BM1T6029-DYjVxojW.mjs +0 -46
- package/dist/activation-context--5yu1dPF-Bwsn3moT.mjs +0 -172
- package/dist/anthropic-TH8ERTXK.mjs +0 -5962
- package/dist/assistant-visible-text-DuFWokAt-CsbII5KS.mjs +0 -596
- package/dist/azure-openai-responses-Bt_Ag9Er.mjs +0 -166
- package/dist/boundary-file-read-BSd9MXPy--KThL5e6.mjs +0 -594
- package/dist/browser-lifecycle-cleanup-BdNsMhMD-O3tnAM4i.mjs +0 -60
- package/dist/build-DgTrEpge.mjs +0 -3333
- package/dist/bundled-compat-BpaDaAAu-D7oazKjD.mjs +0 -5216
- package/dist/bundled-dir-U738ay4K-DXK0q_TV.mjs +0 -258
- package/dist/call-DimWbpgJ-ColD4W-y.mjs +0 -9993
- package/dist/channel-bootstrap.runtime-BVclcGv1-DJv_Z-Kr.mjs +0 -2
- package/dist/channel-bootstrap.runtime-Cwcr38m2-VRfVCR-i.mjs +0 -33
- package/dist/chunk-D6SyT4dJ.mjs +0 -36
- package/dist/command-format-LSnUCVVF-BQ2SMKka.mjs +0 -685
- package/dist/config-Bim2pi8a-BQUdfiEi.mjs +0 -9
- package/dist/delivery-context.shared-j5hC5qb1-CI83RXXZ.mjs +0 -72
- package/dist/diagnostic-ClMwNnUA-D6nUtLnb.mjs +0 -140
- package/dist/dist-CEGw8-2W.mjs +0 -429
- package/dist/dist-DD2aJ2UL.mjs +0 -125135
- package/dist/env-api-keys-BVvSg7T2.mjs +0 -68
- package/dist/event-stream-xaQWmyas.mjs +0 -15226
- package/dist/facade-loader-DFzIYYt_-CIr4HKtE.mjs +0 -194
- package/dist/from-DF7cl2wz.mjs +0 -3842
- package/dist/gateway-method-policy-C7rf0SeV-CJQMEYIE.mjs +0 -28
- package/dist/github-copilot-headers-DjqWtUoP.mjs +0 -22
- package/dist/google-C2pVrgBZ.mjs +0 -336
- package/dist/google-gemini-cli-BBxgS5Ho.mjs +0 -623
- package/dist/google-shared-BsWgwEk1.mjs +0 -22791
- package/dist/google-vertex-BsVLJrrC.mjs +0 -358
- package/dist/hash-DAFtW_W7.mjs +0 -16
- package/dist/headers-R3HdCbAE.mjs +0 -8
- package/dist/home-dir-C44RaPME-CBRS4HLP.mjs +0 -93
- package/dist/ids-BPsM98Uu-CwuxvUai.mjs +0 -77
- package/dist/image-2w3cApg7-CxpHvoB5.mjs +0 -207
- package/dist/interactive-init-BXQBalNr.mjs +0 -450
- package/dist/io-CH2g3vsv-BOGlLlB8.mjs +0 -26218
- package/dist/jiti-loader-cache-Bat69wam-D6hCxboy.mjs +0 -5049
- package/dist/json-file-BQRNuxmK-DhJM5NsG.mjs +0 -108
- package/dist/json-parse-v_HIJjjI.mjs +0 -381
- package/dist/jws-GFcTvvVT.mjs +0 -2291
- package/dist/lark-cli-provider-BARgbbmo.mjs +0 -554
- package/dist/lark-logger-D7_pEVQc.mjs +0 -143
- package/dist/live-smoke-BhkBOcH9.mjs +0 -7135
- package/dist/load-context-mb7uvLSn-B10MAi3I.mjs +0 -29
- package/dist/loader-708jrx4Y-BOswuvpe.mjs +0 -5053
- package/dist/manifest-registry-_hxKCS2K-CZdeyN0f.mjs +0 -3512
- package/dist/message-channel-Bk_YHfQg-AeNrPPpp.mjs +0 -50
- package/dist/message-channel-core-DTA--Gjh-CY4Tkb7N.mjs +0 -29
- package/dist/message.config.runtime-K-k4XOyq-DZTmXomP.mjs +0 -2
- package/dist/message.gateway.runtime-DqHOHRTQ-DH4ml0YF.mjs +0 -2
- package/dist/mistral-CaR4DiLu.mjs +0 -28657
- package/dist/model-auth-env-oyg2Hexc-DU_rOUU5.mjs +0 -1306
- package/dist/models-config-BmpSQJQF-Gfvh1n3A.mjs +0 -1282
- package/dist/models-config.runtime-BsU_22xk.mjs +0 -2
- package/dist/multipart-parser-DedmaB5g.mjs +0 -294
- package/dist/oauth-DOJeGfcE.mjs +0 -6392
- package/dist/openai-BDtIh3Ja.mjs +0 -6693
- package/dist/openai-codex-responses-C5EORu31.mjs +0 -664
- package/dist/openai-completions-CR_cS6gX.mjs +0 -669
- package/dist/openai-responses-oGxwZyuC.mjs +0 -184
- package/dist/openai-responses-shared-BixMSDZE.mjs +0 -398
- package/dist/paths-D6msg0S1-C2lYuisN.mjs +0 -189
- package/dist/paths-D92DjaZ--CTOESW2b.mjs +0 -192
- package/dist/pi-model-discovery-Bd0TWzo8-BFsJmeMb.mjs +0 -227
- package/dist/pi-model-discovery-runtime-CCCZxkd8.mjs +0 -2
- package/dist/pi-tools.before-tool-call.runtime-Bn7uqKie-C5ewk8kK.mjs +0 -399
- package/dist/plugin-auto-enable-DdH3n9V8-DsA1isaF.mjs +0 -1456
- package/dist/process-scoped-map-B2cWkYET-CXwUZ8CZ.mjs +0 -61
- package/dist/provider-discovery.runtime-BPzz1PFj.mjs +0 -58
- package/dist/provider-model-compat-CFqcq0it-BDDuBI3A.mjs +0 -118
- package/dist/provider-runtime-C8rljsNs-CIT93zoy.mjs +0 -2
- package/dist/provider-runtime-CT50mNIX-BwEV6GyO.mjs +0 -573
- package/dist/provider-stream-COLujAAo-CbJPDngm.mjs +0 -35449
- package/dist/providers.runtime-Ba7tOlq7-CXkhkzU9.mjs +0 -219
- package/dist/public-surface-loader-BVl0NQAE-C0piXtsT.mjs +0 -117
- package/dist/resolve-C33B7eeu-BNvYTl6k.mjs +0 -1041
- package/dist/runtime-Cym-fqI8-DaSDMH-a.mjs +0 -120
- package/dist/runtime-channel-state-CohMybAh-hXR6y5Gx.mjs +0 -19
- package/dist/runtime-snapshot-C54O1-gI-40cbyi7P.mjs +0 -677
- package/dist/runtime-state-IBOIXKOx-Bf9tcLvc.mjs +0 -10
- package/dist/runtime-web-tools-fallback.runtime-Ca-qn1mj-BCVImm7a.mjs +0 -39
- package/dist/runtime-web-tools-manifest.runtime-BgxQTjmq-Cb4nJkRT.mjs +0 -2
- package/dist/runtime-web-tools-public-artifacts.runtime-D9qcoWIX-BrQdXzOQ.mjs +0 -2
- package/dist/session-archive.runtime-B52_5vs4-BG-_IwNJ.mjs +0 -2
- package/dist/session-key-Cn2QoOyX-CuHbJMgR.mjs +0 -82
- package/dist/session-transcript-files.fs-DEeFXruQ-B1PF6nLy.mjs +0 -147
- package/dist/src-BgCX0MLG.mjs +0 -813
- package/dist/src-DYbqlAqf.mjs +0 -1177
- package/dist/subagent-announce-L5WsQatW-CQWI9GMd.mjs +0 -344
- package/dist/subagent-announce.registry.runtime-DiqZyeTs-BKuniyi3.mjs +0 -28
- package/dist/subagent-registry-steer-runtime-DFgZFC0j-BhBz0roy.mjs +0 -211
- package/dist/subagent-system-prompt-C1qnN--K-DpnTFP47.mjs +0 -3061
- package/dist/target-parsing-loaded-DKkb6jJY-BMD4CkpS.mjs +0 -1002
- package/dist/task-registry-delivery-runtime-Dd1CUkZF-C8U40a3O.mjs +0 -2950
- package/dist/task-registry-delivery-runtime-ragbeVx5-CNbFAkjD.mjs +0 -2
- package/dist/thinking-Bh-7MqXz-D3woGbO7.mjs +0 -2
- package/dist/transcript-E_-ISOkD-DWCfZP2p.mjs +0 -2019
- package/dist/transcript.runtime-BqhvZZdl-BPy42vBP.mjs +0 -2
- package/dist/transform-messages-DbhIzTxq.mjs +0 -207
- package/dist/web-provider-public-artifacts-BlpRwIUS-CGPSV4W2.mjs +0 -295
- package/dist/web-search-providers.runtime--0aUtC3b-DyuhC95V.mjs +0 -200
|
@@ -1,2950 +0,0 @@
|
|
|
1
|
-
import { c as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty } from "./home-dir-C44RaPME-CBRS4HLP.mjs";
|
|
2
|
-
import { o as resolveStateDir } from "./paths-D92DjaZ--CTOESW2b.mjs";
|
|
3
|
-
import { n as normalizeAccountId } from "./account-id-BM1T6029-DYjVxojW.mjs";
|
|
4
|
-
import { c as resolveConfigDir, l as resolveUserPath } from "./bundled-dir-U738ay4K-DXK0q_TV.mjs";
|
|
5
|
-
import { S as resolveSilentReplySettings, _ as hasReplyChannelData, a as shouldSuppressReasoningPayload, b as renderMessagePresentationFallbackText, c as compileGlobPatterns, d as mergeAlsoAllowPolicy, f as normalizeToolName, g as hasMessagePresentationBlocks, h as hasInteractiveReplyBlocks, i as isRenderablePayload, l as matchesAnyGlobPattern, o as parseInlineDirectives, p as resolveToolProfilePolicy, r as formatBtwTextForExternalDelivery, s as buildOutboundSessionContext, u as expandToolGroups, v as hasReplyPayloadContent, w as isSilentReplyPayloadText, x as resolveSilentReplyRewriteText, y as normalizeMessagePresentation } from "./target-parsing-loaded-DKkb6jJY-BMD4CkpS.mjs";
|
|
6
|
-
import { D as resolveAccountEntry } from "./io-CH2g3vsv-BOGlLlB8.mjs";
|
|
7
|
-
import { Mt as formatErrorMessage, St as createSubsystemLogger, jt as resolvePreferredOpenClawTmpDir } from "./bundled-compat-BpaDaAAu-D7oazKjD.mjs";
|
|
8
|
-
import "./message-channel-core-DTA--Gjh-CY4Tkb7N.mjs";
|
|
9
|
-
import { c as normalizeMessageChannel, i as isDeliverableMessageChannel, n as GATEWAY_CLIENT_MODES, r as GATEWAY_CLIENT_NAMES, s as listDeliverableMessageChannels } from "./message-channel-Bk_YHfQg-AeNrPPpp.mjs";
|
|
10
|
-
import { P as defaultRuntime } from "./manifest-registry-_hxKCS2K-CZdeyN0f.mjs";
|
|
11
|
-
import { a as hasNodeErrorCode, c as isSymlinkOpenError, i as sameFileIdentity, o as isNotFoundPathError } from "./boundary-file-read-BSd9MXPy--KThL5e6.mjs";
|
|
12
|
-
import { S as listChannelPlugins, b as getChannelPlugin, d as resolveAgentWorkspaceDir, u as resolveAgentConfig, x as getLoadedChannelPlugin, y as logVerbose } from "./runtime-snapshot-C54O1-gI-40cbyi7P.mjs";
|
|
13
|
-
import { r as getActivePluginRegistry, t as getActivePluginChannelRegistry } from "./runtime-Cym-fqI8-DaSDMH-a.mjs";
|
|
14
|
-
import { c as createInternalHookEvent, d as getGlobalHookRunner, l as triggerInternalHook } from "./loader-708jrx4Y-BOswuvpe.mjs";
|
|
15
|
-
import { c as parseThreadSessionSuffix, s as parseRawSessionConversationRef } from "./session-key-Cn2QoOyX-CuHbJMgR.mjs";
|
|
16
|
-
import "./paths-D6msg0S1-C2lYuisN.mjs";
|
|
17
|
-
import { i as resolveSessionConversation, r as resolveMirroredTranscriptText } from "./transcript-E_-ISOkD-DWCfZP2p.mjs";
|
|
18
|
-
import "./delivery-context.shared-j5hC5qb1-CI83RXXZ.mjs";
|
|
19
|
-
import { t as formatCliCommand } from "./command-format-LSnUCVVF-BQ2SMKka.mjs";
|
|
20
|
-
import { t as bootstrapOutboundChannelPlugin } from "./channel-bootstrap.runtime-Cwcr38m2-VRfVCR-i.mjs";
|
|
21
|
-
import fs, { constants } from "node:fs";
|
|
22
|
-
import path from "node:path";
|
|
23
|
-
import { URL, fileURLToPath } from "node:url";
|
|
24
|
-
import fs$1 from "node:fs/promises";
|
|
25
|
-
import os from "node:os";
|
|
26
|
-
import "node:child_process";
|
|
27
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
28
|
-
import "node:stream/promises";
|
|
29
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/fences-CcpA8d2y.js
|
|
30
|
-
function parseFenceSpans(buffer) {
|
|
31
|
-
const spans = [];
|
|
32
|
-
let open;
|
|
33
|
-
let offset = 0;
|
|
34
|
-
while (offset <= buffer.length) {
|
|
35
|
-
const nextNewline = buffer.indexOf("\n", offset);
|
|
36
|
-
const lineEnd = nextNewline === -1 ? buffer.length : nextNewline;
|
|
37
|
-
const line = buffer.slice(offset, lineEnd);
|
|
38
|
-
const match = line.match(/^( {0,3})(`{3,}|~{3,})(.*)$/);
|
|
39
|
-
if (match) {
|
|
40
|
-
const indent = match[1];
|
|
41
|
-
const marker = match[2];
|
|
42
|
-
const markerChar = marker[0];
|
|
43
|
-
const markerLen = marker.length;
|
|
44
|
-
if (!open) open = {
|
|
45
|
-
start: offset,
|
|
46
|
-
markerChar,
|
|
47
|
-
markerLen,
|
|
48
|
-
openLine: line,
|
|
49
|
-
marker,
|
|
50
|
-
indent
|
|
51
|
-
};
|
|
52
|
-
else if (open.markerChar === markerChar && markerLen >= open.markerLen) {
|
|
53
|
-
const end = lineEnd;
|
|
54
|
-
spans.push({
|
|
55
|
-
start: open.start,
|
|
56
|
-
end,
|
|
57
|
-
openLine: open.openLine,
|
|
58
|
-
marker: open.marker,
|
|
59
|
-
indent: open.indent
|
|
60
|
-
});
|
|
61
|
-
open = void 0;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
if (nextNewline === -1) break;
|
|
65
|
-
offset = nextNewline + 1;
|
|
66
|
-
}
|
|
67
|
-
if (open) spans.push({
|
|
68
|
-
start: open.start,
|
|
69
|
-
end: buffer.length,
|
|
70
|
-
openLine: open.openLine,
|
|
71
|
-
marker: open.marker,
|
|
72
|
-
indent: open.indent
|
|
73
|
-
});
|
|
74
|
-
return spans;
|
|
75
|
-
}
|
|
76
|
-
function findFenceSpanAt(spans, index) {
|
|
77
|
-
let low = 0;
|
|
78
|
-
let high = spans.length - 1;
|
|
79
|
-
while (low <= high) {
|
|
80
|
-
const mid = Math.floor((low + high) / 2);
|
|
81
|
-
const span = spans[mid];
|
|
82
|
-
if (!span) break;
|
|
83
|
-
if (index <= span.start) {
|
|
84
|
-
high = mid - 1;
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (index >= span.end) {
|
|
88
|
-
low = mid + 1;
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
return span;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
function isSafeFenceBreak(spans, index) {
|
|
95
|
-
return !findFenceSpanAt(spans, index);
|
|
96
|
-
}
|
|
97
|
-
//#endregion
|
|
98
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/channel-streaming-Be5llNGp.js
|
|
99
|
-
function asObjectRecord(value) {
|
|
100
|
-
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
101
|
-
}
|
|
102
|
-
function asTextChunkMode(value) {
|
|
103
|
-
return value === "length" || value === "newline" ? value : void 0;
|
|
104
|
-
}
|
|
105
|
-
function getChannelStreamingConfigObject(entry) {
|
|
106
|
-
const streaming = asObjectRecord(entry?.streaming);
|
|
107
|
-
return streaming ? streaming : void 0;
|
|
108
|
-
}
|
|
109
|
-
function resolveChannelStreamingChunkMode(entry) {
|
|
110
|
-
return asTextChunkMode(getChannelStreamingConfigObject(entry)?.chunkMode) ?? asTextChunkMode(entry?.chunkMode);
|
|
111
|
-
}
|
|
112
|
-
//#endregion
|
|
113
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/text-chunking-RDGPC8zE.js
|
|
114
|
-
function chunkTextByBreakResolver(text, limit, resolveBreakIndex) {
|
|
115
|
-
if (!text) return [];
|
|
116
|
-
if (limit <= 0 || text.length <= limit) return [text];
|
|
117
|
-
const chunks = [];
|
|
118
|
-
let remaining = text;
|
|
119
|
-
while (remaining.length > limit) {
|
|
120
|
-
const candidateBreak = resolveBreakIndex(remaining.slice(0, limit));
|
|
121
|
-
const breakIdx = Number.isFinite(candidateBreak) && candidateBreak > 0 && candidateBreak <= limit ? candidateBreak : limit;
|
|
122
|
-
const chunk = remaining.slice(0, breakIdx).trimEnd();
|
|
123
|
-
if (chunk.length > 0) chunks.push(chunk);
|
|
124
|
-
const brokeOnSeparator = breakIdx < remaining.length && /\s/.test(remaining[breakIdx]);
|
|
125
|
-
const nextStart = Math.min(remaining.length, breakIdx + (brokeOnSeparator ? 1 : 0));
|
|
126
|
-
remaining = remaining.slice(nextStart).trimStart();
|
|
127
|
-
}
|
|
128
|
-
if (remaining.length) chunks.push(remaining);
|
|
129
|
-
return chunks;
|
|
130
|
-
}
|
|
131
|
-
//#endregion
|
|
132
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/chunk-CReBKZas.js
|
|
133
|
-
const DEFAULT_CHUNK_LIMIT = 4e3;
|
|
134
|
-
const DEFAULT_CHUNK_MODE = "length";
|
|
135
|
-
function resolveChunkLimitForProvider(cfgSection, accountId) {
|
|
136
|
-
if (!cfgSection) return;
|
|
137
|
-
const normalizedAccountId = normalizeAccountId(accountId);
|
|
138
|
-
const accounts = cfgSection.accounts;
|
|
139
|
-
if (accounts && typeof accounts === "object") {
|
|
140
|
-
const direct = resolveAccountEntry(accounts, normalizedAccountId);
|
|
141
|
-
if (typeof direct?.textChunkLimit === "number") return direct.textChunkLimit;
|
|
142
|
-
}
|
|
143
|
-
return cfgSection.textChunkLimit;
|
|
144
|
-
}
|
|
145
|
-
function resolveTextChunkLimit(cfg, provider, accountId, opts) {
|
|
146
|
-
const fallback = typeof opts?.fallbackLimit === "number" && opts.fallbackLimit > 0 ? opts.fallbackLimit : DEFAULT_CHUNK_LIMIT;
|
|
147
|
-
const providerOverride = (() => {
|
|
148
|
-
if (!provider || provider === "webchat") return;
|
|
149
|
-
return resolveChunkLimitForProvider((cfg?.channels)?.[provider] ?? cfg?.[provider], accountId);
|
|
150
|
-
})();
|
|
151
|
-
if (typeof providerOverride === "number" && providerOverride > 0) return providerOverride;
|
|
152
|
-
return fallback;
|
|
153
|
-
}
|
|
154
|
-
function resolveChunkModeForProvider(cfgSection, accountId) {
|
|
155
|
-
if (!cfgSection) return;
|
|
156
|
-
const normalizedAccountId = normalizeAccountId(accountId);
|
|
157
|
-
const accounts = cfgSection.accounts;
|
|
158
|
-
if (accounts && typeof accounts === "object") {
|
|
159
|
-
const directMode = resolveChannelStreamingChunkMode(resolveAccountEntry(accounts, normalizedAccountId));
|
|
160
|
-
if (directMode) return directMode;
|
|
161
|
-
}
|
|
162
|
-
return resolveChannelStreamingChunkMode(cfgSection) ?? cfgSection.chunkMode;
|
|
163
|
-
}
|
|
164
|
-
function resolveChunkMode(cfg, provider, accountId) {
|
|
165
|
-
if (!provider || provider === "webchat") return DEFAULT_CHUNK_MODE;
|
|
166
|
-
return resolveChunkModeForProvider((cfg?.channels)?.[provider] ?? cfg?.[provider], accountId) ?? DEFAULT_CHUNK_MODE;
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Split text into chunks on paragraph boundaries (blank lines), preserving lists and
|
|
170
|
-
* single-newline line wraps inside paragraphs.
|
|
171
|
-
*
|
|
172
|
-
* - Only breaks at paragraph separators ("\n\n" or more, allowing whitespace on blank lines)
|
|
173
|
-
* - Packs multiple paragraphs into a single chunk up to `limit`
|
|
174
|
-
* - Falls back to length-based splitting when a single paragraph exceeds `limit`
|
|
175
|
-
* (unless `splitLongParagraphs` is disabled)
|
|
176
|
-
*/
|
|
177
|
-
function chunkByParagraph(text, limit, opts) {
|
|
178
|
-
if (!text) return [];
|
|
179
|
-
if (limit <= 0) return [text];
|
|
180
|
-
const splitLongParagraphs = opts?.splitLongParagraphs !== false;
|
|
181
|
-
const normalized = text.replace(/\r\n?/g, "\n");
|
|
182
|
-
if (!/\n[\t ]*\n+/.test(normalized)) {
|
|
183
|
-
if (normalized.length <= limit) return [normalized];
|
|
184
|
-
if (!splitLongParagraphs) return [normalized];
|
|
185
|
-
return chunkText(normalized, limit);
|
|
186
|
-
}
|
|
187
|
-
const spans = parseFenceSpans(normalized);
|
|
188
|
-
const parts = [];
|
|
189
|
-
const re = /\n[\t ]*\n+/g;
|
|
190
|
-
let lastIndex = 0;
|
|
191
|
-
for (const match of normalized.matchAll(re)) {
|
|
192
|
-
const idx = match.index ?? 0;
|
|
193
|
-
if (!isSafeFenceBreak(spans, idx)) continue;
|
|
194
|
-
parts.push(normalized.slice(lastIndex, idx));
|
|
195
|
-
lastIndex = idx + match[0].length;
|
|
196
|
-
}
|
|
197
|
-
parts.push(normalized.slice(lastIndex));
|
|
198
|
-
const chunks = [];
|
|
199
|
-
for (const part of parts) {
|
|
200
|
-
const paragraph = part.replace(/\s+$/g, "");
|
|
201
|
-
if (!paragraph.trim()) continue;
|
|
202
|
-
if (paragraph.length <= limit) chunks.push(paragraph);
|
|
203
|
-
else if (!splitLongParagraphs) chunks.push(paragraph);
|
|
204
|
-
else chunks.push(...chunkText(paragraph, limit));
|
|
205
|
-
}
|
|
206
|
-
return chunks;
|
|
207
|
-
}
|
|
208
|
-
function chunkMarkdownTextWithMode(text, limit, mode) {
|
|
209
|
-
if (mode === "newline") {
|
|
210
|
-
const paragraphChunks = chunkByParagraph(text, limit, { splitLongParagraphs: false });
|
|
211
|
-
const out = [];
|
|
212
|
-
for (const chunk of paragraphChunks) {
|
|
213
|
-
const nested = chunkMarkdownText(chunk, limit);
|
|
214
|
-
if (!nested.length && chunk) out.push(chunk);
|
|
215
|
-
else out.push(...nested);
|
|
216
|
-
}
|
|
217
|
-
return out;
|
|
218
|
-
}
|
|
219
|
-
return chunkMarkdownText(text, limit);
|
|
220
|
-
}
|
|
221
|
-
function resolveChunkEarlyReturn(text, limit) {
|
|
222
|
-
if (!text) return [];
|
|
223
|
-
if (limit <= 0) return [text];
|
|
224
|
-
if (text.length <= limit) return [text];
|
|
225
|
-
}
|
|
226
|
-
function chunkText(text, limit) {
|
|
227
|
-
const early = resolveChunkEarlyReturn(text, limit);
|
|
228
|
-
if (early) return early;
|
|
229
|
-
return chunkTextByBreakResolver(text, limit, (window) => {
|
|
230
|
-
const { lastNewline, lastWhitespace } = scanParenAwareBreakpoints(window, 0, window.length);
|
|
231
|
-
return lastNewline > 0 ? lastNewline : lastWhitespace;
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
function chunkMarkdownText(text, limit) {
|
|
235
|
-
const early = resolveChunkEarlyReturn(text, limit);
|
|
236
|
-
if (early) return early;
|
|
237
|
-
const chunks = [];
|
|
238
|
-
const spans = parseFenceSpans(text);
|
|
239
|
-
let start = 0;
|
|
240
|
-
let reopenFence;
|
|
241
|
-
while (start < text.length) {
|
|
242
|
-
const reopenPrefix = reopenFence ? `${reopenFence.openLine}\n` : "";
|
|
243
|
-
const contentLimit = Math.max(1, limit - reopenPrefix.length);
|
|
244
|
-
if (text.length - start <= contentLimit) {
|
|
245
|
-
const finalChunk = `${reopenPrefix}${text.slice(start)}`;
|
|
246
|
-
if (finalChunk.length > 0) chunks.push(finalChunk);
|
|
247
|
-
break;
|
|
248
|
-
}
|
|
249
|
-
const windowEnd = Math.min(text.length, start + contentLimit);
|
|
250
|
-
const softBreak = pickSafeBreakIndex(text, start, windowEnd, spans);
|
|
251
|
-
let breakIdx = softBreak > start ? softBreak : windowEnd;
|
|
252
|
-
const initialFence = isSafeFenceBreak(spans, breakIdx) ? void 0 : findFenceSpanAt(spans, breakIdx);
|
|
253
|
-
let fenceToSplit = initialFence;
|
|
254
|
-
if (initialFence) {
|
|
255
|
-
const closeLine = `${initialFence.indent}${initialFence.marker}`;
|
|
256
|
-
const maxIdxIfNeedNewline = start + (contentLimit - (closeLine.length + 1));
|
|
257
|
-
if (maxIdxIfNeedNewline <= start) {
|
|
258
|
-
fenceToSplit = void 0;
|
|
259
|
-
breakIdx = windowEnd;
|
|
260
|
-
} else {
|
|
261
|
-
const minProgressIdx = Math.min(text.length, Math.max(start + 1, initialFence.start + initialFence.openLine.length + 2));
|
|
262
|
-
const maxIdxIfAlreadyNewline = start + (contentLimit - closeLine.length);
|
|
263
|
-
let pickedNewline = false;
|
|
264
|
-
let lastNewline = text.lastIndexOf("\n", Math.max(start, maxIdxIfAlreadyNewline - 1));
|
|
265
|
-
while (lastNewline >= start) {
|
|
266
|
-
const candidateBreak = lastNewline + 1;
|
|
267
|
-
if (candidateBreak < minProgressIdx) break;
|
|
268
|
-
const candidateFence = findFenceSpanAt(spans, candidateBreak);
|
|
269
|
-
if (candidateFence && candidateFence.start === initialFence.start) {
|
|
270
|
-
breakIdx = candidateBreak;
|
|
271
|
-
pickedNewline = true;
|
|
272
|
-
break;
|
|
273
|
-
}
|
|
274
|
-
lastNewline = text.lastIndexOf("\n", lastNewline - 1);
|
|
275
|
-
}
|
|
276
|
-
if (!pickedNewline) if (minProgressIdx > maxIdxIfAlreadyNewline) {
|
|
277
|
-
fenceToSplit = void 0;
|
|
278
|
-
breakIdx = windowEnd;
|
|
279
|
-
} else breakIdx = Math.max(minProgressIdx, maxIdxIfNeedNewline);
|
|
280
|
-
}
|
|
281
|
-
const fenceAtBreak = findFenceSpanAt(spans, breakIdx);
|
|
282
|
-
fenceToSplit = fenceAtBreak && fenceAtBreak.start === initialFence.start ? fenceAtBreak : void 0;
|
|
283
|
-
}
|
|
284
|
-
const rawContent = text.slice(start, breakIdx);
|
|
285
|
-
if (!rawContent) break;
|
|
286
|
-
let rawChunk = `${reopenPrefix}${rawContent}`;
|
|
287
|
-
const brokeOnSeparator = breakIdx < text.length && /\s/.test(text[breakIdx]);
|
|
288
|
-
let nextStart = Math.min(text.length, breakIdx + (brokeOnSeparator ? 1 : 0));
|
|
289
|
-
if (fenceToSplit) {
|
|
290
|
-
const closeLine = `${fenceToSplit.indent}${fenceToSplit.marker}`;
|
|
291
|
-
rawChunk = rawChunk.endsWith("\n") ? `${rawChunk}${closeLine}` : `${rawChunk}\n${closeLine}`;
|
|
292
|
-
reopenFence = fenceToSplit;
|
|
293
|
-
} else {
|
|
294
|
-
nextStart = skipLeadingNewlines(text, nextStart);
|
|
295
|
-
reopenFence = void 0;
|
|
296
|
-
}
|
|
297
|
-
chunks.push(rawChunk);
|
|
298
|
-
start = nextStart;
|
|
299
|
-
}
|
|
300
|
-
return chunks;
|
|
301
|
-
}
|
|
302
|
-
function skipLeadingNewlines(value, start = 0) {
|
|
303
|
-
let i = start;
|
|
304
|
-
while (i < value.length && value[i] === "\n") i++;
|
|
305
|
-
return i;
|
|
306
|
-
}
|
|
307
|
-
function pickSafeBreakIndex(text, start, end, spans) {
|
|
308
|
-
const { lastNewline, lastWhitespace } = scanParenAwareBreakpoints(text, start, end, (index) => isSafeFenceBreak(spans, index));
|
|
309
|
-
if (lastNewline > start) return lastNewline;
|
|
310
|
-
if (lastWhitespace > start) return lastWhitespace;
|
|
311
|
-
return -1;
|
|
312
|
-
}
|
|
313
|
-
function scanParenAwareBreakpoints(text, start, end, isAllowed = () => true) {
|
|
314
|
-
let lastNewline = -1;
|
|
315
|
-
let lastWhitespace = -1;
|
|
316
|
-
let depth = 0;
|
|
317
|
-
for (let i = start; i < end; i++) {
|
|
318
|
-
if (!isAllowed(i)) continue;
|
|
319
|
-
const char = text[i];
|
|
320
|
-
if (char === "(") {
|
|
321
|
-
depth += 1;
|
|
322
|
-
continue;
|
|
323
|
-
}
|
|
324
|
-
if (char === ")" && depth > 0) {
|
|
325
|
-
depth -= 1;
|
|
326
|
-
continue;
|
|
327
|
-
}
|
|
328
|
-
if (depth !== 0) continue;
|
|
329
|
-
if (char === "\n") lastNewline = i;
|
|
330
|
-
else if (/\s/.test(char)) lastWhitespace = i;
|
|
331
|
-
}
|
|
332
|
-
return {
|
|
333
|
-
lastNewline,
|
|
334
|
-
lastWhitespace
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
//#endregion
|
|
338
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/reply-payload-BeHzA2Kn.js
|
|
339
|
-
/** Prefer multi-attachment payloads, then fall back to the legacy single-media field. */
|
|
340
|
-
function resolveOutboundMediaUrls(payload) {
|
|
341
|
-
if (payload.mediaUrls?.length) return payload.mediaUrls;
|
|
342
|
-
if (payload.mediaUrl) return [payload.mediaUrl];
|
|
343
|
-
return [];
|
|
344
|
-
}
|
|
345
|
-
/** Normalize reply payload text/media into a trimmed, sendable shape for delivery paths. */
|
|
346
|
-
function resolveSendableOutboundReplyParts(payload, options) {
|
|
347
|
-
const text = options?.text ?? payload.text ?? "";
|
|
348
|
-
const trimmedText = text.trim();
|
|
349
|
-
const mediaUrls = resolveOutboundMediaUrls(payload).map((entry) => entry.trim()).filter(Boolean);
|
|
350
|
-
const mediaCount = mediaUrls.length;
|
|
351
|
-
const hasText = Boolean(trimmedText);
|
|
352
|
-
const hasMedia = mediaCount > 0;
|
|
353
|
-
return {
|
|
354
|
-
text,
|
|
355
|
-
trimmedText,
|
|
356
|
-
mediaUrls,
|
|
357
|
-
mediaCount,
|
|
358
|
-
hasText,
|
|
359
|
-
hasMedia,
|
|
360
|
-
hasContent: hasText || hasMedia
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
/** Send a caption with only the first media item, mirroring caption-limited channel transports. */
|
|
364
|
-
async function sendMediaWithLeadingCaption(params) {
|
|
365
|
-
if (params.mediaUrls.length === 0) return false;
|
|
366
|
-
for (const [index, mediaUrl] of params.mediaUrls.entries()) {
|
|
367
|
-
const isFirst = index === 0;
|
|
368
|
-
const caption = isFirst ? params.caption : void 0;
|
|
369
|
-
try {
|
|
370
|
-
await params.send({
|
|
371
|
-
mediaUrl,
|
|
372
|
-
caption
|
|
373
|
-
});
|
|
374
|
-
} catch (error) {
|
|
375
|
-
if (params.onError) {
|
|
376
|
-
await params.onError({
|
|
377
|
-
error,
|
|
378
|
-
mediaUrl,
|
|
379
|
-
caption,
|
|
380
|
-
index,
|
|
381
|
-
isFirst
|
|
382
|
-
});
|
|
383
|
-
continue;
|
|
384
|
-
}
|
|
385
|
-
throw error;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
return true;
|
|
389
|
-
}
|
|
390
|
-
//#endregion
|
|
391
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/message-hook-mappers-BvKyVtNo.js
|
|
392
|
-
function fireAndForgetHook(task, label, logger = logVerbose) {
|
|
393
|
-
task.catch((err) => {
|
|
394
|
-
logger(`${label}: ${String(err)}`);
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
function buildCanonicalSentMessageHookContext(params) {
|
|
398
|
-
return {
|
|
399
|
-
to: params.to,
|
|
400
|
-
content: params.content,
|
|
401
|
-
success: params.success,
|
|
402
|
-
error: params.error,
|
|
403
|
-
channelId: params.channelId,
|
|
404
|
-
accountId: params.accountId,
|
|
405
|
-
conversationId: params.conversationId ?? params.to,
|
|
406
|
-
messageId: params.messageId,
|
|
407
|
-
isGroup: params.isGroup,
|
|
408
|
-
groupId: params.groupId
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
function toPluginMessageContext(canonical) {
|
|
412
|
-
return {
|
|
413
|
-
channelId: canonical.channelId,
|
|
414
|
-
accountId: canonical.accountId,
|
|
415
|
-
conversationId: canonical.conversationId
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
function toPluginMessageSentEvent(canonical) {
|
|
419
|
-
return {
|
|
420
|
-
to: canonical.to,
|
|
421
|
-
content: canonical.content,
|
|
422
|
-
success: canonical.success,
|
|
423
|
-
...canonical.error ? { error: canonical.error } : {}
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
function toInternalMessageSentContext(canonical) {
|
|
427
|
-
return {
|
|
428
|
-
to: canonical.to,
|
|
429
|
-
content: canonical.content,
|
|
430
|
-
success: canonical.success,
|
|
431
|
-
...canonical.error ? { error: canonical.error } : {},
|
|
432
|
-
channelId: canonical.channelId,
|
|
433
|
-
accountId: canonical.accountId,
|
|
434
|
-
conversationId: canonical.conversationId,
|
|
435
|
-
messageId: canonical.messageId,
|
|
436
|
-
...canonical.isGroup != null ? { isGroup: canonical.isGroup } : {},
|
|
437
|
-
...canonical.groupId ? { groupId: canonical.groupId } : {}
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
//#endregion
|
|
441
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/secure-random-DblRPRKa.js
|
|
442
|
-
function generateSecureUuid() {
|
|
443
|
-
return randomUUID();
|
|
444
|
-
}
|
|
445
|
-
//#endregion
|
|
446
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/types.tools-BT2DX6OI.js
|
|
447
|
-
const TOOLS_BY_SENDER_KEY_TYPES = [
|
|
448
|
-
"id",
|
|
449
|
-
"e164",
|
|
450
|
-
"username",
|
|
451
|
-
"name"
|
|
452
|
-
];
|
|
453
|
-
function parseToolsBySenderTypedKey(rawKey) {
|
|
454
|
-
const trimmed = rawKey.trim();
|
|
455
|
-
if (!trimmed) return;
|
|
456
|
-
const lowered = normalizeLowercaseStringOrEmpty(trimmed);
|
|
457
|
-
for (const type of TOOLS_BY_SENDER_KEY_TYPES) {
|
|
458
|
-
const prefix = `${type}:`;
|
|
459
|
-
if (!lowered.startsWith(prefix)) continue;
|
|
460
|
-
return {
|
|
461
|
-
type,
|
|
462
|
-
value: trimmed.slice(prefix.length)
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
//#endregion
|
|
467
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/group-policy-M4aSFsZ5.js
|
|
468
|
-
function resolveChannelGroupConfig(groups, groupId, caseInsensitive = false) {
|
|
469
|
-
if (!groups) return;
|
|
470
|
-
const direct = groups[groupId];
|
|
471
|
-
if (direct) return direct;
|
|
472
|
-
if (!caseInsensitive) return;
|
|
473
|
-
const target = normalizeLowercaseStringOrEmpty(groupId);
|
|
474
|
-
const matchedKey = Object.keys(groups).find((key) => key !== "*" && normalizeLowercaseStringOrEmpty(key) === target);
|
|
475
|
-
if (!matchedKey) return;
|
|
476
|
-
return groups[matchedKey];
|
|
477
|
-
}
|
|
478
|
-
const warnedLegacyToolsBySenderKeys = /* @__PURE__ */ new Set();
|
|
479
|
-
const compiledToolsBySenderCache = /* @__PURE__ */ new WeakMap();
|
|
480
|
-
function normalizeSenderKey(value, options = {}) {
|
|
481
|
-
const trimmed = value.trim();
|
|
482
|
-
if (!trimmed) return "";
|
|
483
|
-
return normalizeLowercaseStringOrEmpty(options.stripLeadingAt && trimmed.startsWith("@") ? trimmed.slice(1) : trimmed);
|
|
484
|
-
}
|
|
485
|
-
function normalizeTypedSenderKey(value, type) {
|
|
486
|
-
return normalizeSenderKey(value, { stripLeadingAt: type === "username" });
|
|
487
|
-
}
|
|
488
|
-
function normalizeLegacySenderKey(value) {
|
|
489
|
-
return normalizeSenderKey(value, { stripLeadingAt: true });
|
|
490
|
-
}
|
|
491
|
-
function warnLegacyToolsBySenderKey(rawKey) {
|
|
492
|
-
const trimmed = rawKey.trim();
|
|
493
|
-
if (!trimmed || warnedLegacyToolsBySenderKeys.has(trimmed)) return;
|
|
494
|
-
warnedLegacyToolsBySenderKeys.add(trimmed);
|
|
495
|
-
process.emitWarning(`toolsBySender key "${trimmed}" is deprecated. Use explicit prefixes (id:, e164:, username:, name:). Legacy unprefixed keys are matched as id only.`, {
|
|
496
|
-
type: "DeprecationWarning",
|
|
497
|
-
code: "OPENCLAW_TOOLS_BY_SENDER_UNTYPED_KEY"
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
function parseSenderPolicyKey(rawKey) {
|
|
501
|
-
const trimmed = rawKey.trim();
|
|
502
|
-
if (!trimmed) return;
|
|
503
|
-
if (trimmed === "*") return { kind: "wildcard" };
|
|
504
|
-
const typed = parseToolsBySenderTypedKey(trimmed);
|
|
505
|
-
if (typed) {
|
|
506
|
-
const key = normalizeTypedSenderKey(typed.value, typed.type);
|
|
507
|
-
if (!key) return;
|
|
508
|
-
return {
|
|
509
|
-
kind: "typed",
|
|
510
|
-
type: typed.type,
|
|
511
|
-
key
|
|
512
|
-
};
|
|
513
|
-
}
|
|
514
|
-
warnLegacyToolsBySenderKey(trimmed);
|
|
515
|
-
const key = normalizeLegacySenderKey(trimmed);
|
|
516
|
-
if (!key) return;
|
|
517
|
-
return {
|
|
518
|
-
kind: "typed",
|
|
519
|
-
type: "id",
|
|
520
|
-
key
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
function createSenderPolicyBuckets() {
|
|
524
|
-
return {
|
|
525
|
-
id: /* @__PURE__ */ new Map(),
|
|
526
|
-
e164: /* @__PURE__ */ new Map(),
|
|
527
|
-
username: /* @__PURE__ */ new Map(),
|
|
528
|
-
name: /* @__PURE__ */ new Map()
|
|
529
|
-
};
|
|
530
|
-
}
|
|
531
|
-
function compileToolsBySenderPolicy(toolsBySender) {
|
|
532
|
-
const entries = Object.entries(toolsBySender);
|
|
533
|
-
if (entries.length === 0) return;
|
|
534
|
-
const buckets = createSenderPolicyBuckets();
|
|
535
|
-
let wildcard;
|
|
536
|
-
for (const [rawKey, policy] of entries) {
|
|
537
|
-
if (!policy) continue;
|
|
538
|
-
const parsed = parseSenderPolicyKey(rawKey);
|
|
539
|
-
if (!parsed) continue;
|
|
540
|
-
if (parsed.kind === "wildcard") {
|
|
541
|
-
wildcard = policy;
|
|
542
|
-
continue;
|
|
543
|
-
}
|
|
544
|
-
const bucket = buckets[parsed.type];
|
|
545
|
-
if (!bucket.has(parsed.key)) bucket.set(parsed.key, policy);
|
|
546
|
-
}
|
|
547
|
-
return {
|
|
548
|
-
buckets,
|
|
549
|
-
wildcard
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
|
-
function resolveCompiledToolsBySenderPolicy(toolsBySender) {
|
|
553
|
-
const cached = compiledToolsBySenderCache.get(toolsBySender);
|
|
554
|
-
if (cached) return cached;
|
|
555
|
-
const compiled = compileToolsBySenderPolicy(toolsBySender);
|
|
556
|
-
if (!compiled) return;
|
|
557
|
-
compiledToolsBySenderCache.set(toolsBySender, compiled);
|
|
558
|
-
return compiled;
|
|
559
|
-
}
|
|
560
|
-
function normalizeCandidate(value, type) {
|
|
561
|
-
const trimmed = normalizeOptionalString(value);
|
|
562
|
-
if (!trimmed) return "";
|
|
563
|
-
return normalizeTypedSenderKey(trimmed, type);
|
|
564
|
-
}
|
|
565
|
-
function normalizeSenderIdCandidates(value) {
|
|
566
|
-
const trimmed = normalizeOptionalString(value);
|
|
567
|
-
if (!trimmed) return [];
|
|
568
|
-
const typed = normalizeTypedSenderKey(trimmed, "id");
|
|
569
|
-
const legacy = normalizeLegacySenderKey(trimmed);
|
|
570
|
-
if (!typed) return legacy ? [legacy] : [];
|
|
571
|
-
if (!legacy || legacy === typed) return [typed];
|
|
572
|
-
return [typed, legacy];
|
|
573
|
-
}
|
|
574
|
-
function matchToolsBySenderPolicy(compiled, params) {
|
|
575
|
-
for (const senderIdCandidate of normalizeSenderIdCandidates(params.senderId)) {
|
|
576
|
-
const match = compiled.buckets.id.get(senderIdCandidate);
|
|
577
|
-
if (match) return match;
|
|
578
|
-
}
|
|
579
|
-
const senderE164 = normalizeCandidate(params.senderE164, "e164");
|
|
580
|
-
if (senderE164) {
|
|
581
|
-
const match = compiled.buckets.e164.get(senderE164);
|
|
582
|
-
if (match) return match;
|
|
583
|
-
}
|
|
584
|
-
const senderUsername = normalizeCandidate(params.senderUsername, "username");
|
|
585
|
-
if (senderUsername) {
|
|
586
|
-
const match = compiled.buckets.username.get(senderUsername);
|
|
587
|
-
if (match) return match;
|
|
588
|
-
}
|
|
589
|
-
const senderName = normalizeCandidate(params.senderName, "name");
|
|
590
|
-
if (senderName) {
|
|
591
|
-
const match = compiled.buckets.name.get(senderName);
|
|
592
|
-
if (match) return match;
|
|
593
|
-
}
|
|
594
|
-
return compiled.wildcard;
|
|
595
|
-
}
|
|
596
|
-
function resolveToolsBySender(params) {
|
|
597
|
-
const toolsBySender = params.toolsBySender;
|
|
598
|
-
if (!toolsBySender) return;
|
|
599
|
-
const compiled = resolveCompiledToolsBySenderPolicy(toolsBySender);
|
|
600
|
-
if (!compiled) return;
|
|
601
|
-
return matchToolsBySenderPolicy(compiled, params);
|
|
602
|
-
}
|
|
603
|
-
function resolveChannelGroups(cfg, channel, accountId) {
|
|
604
|
-
const normalizedAccountId = normalizeAccountId(accountId);
|
|
605
|
-
const channelConfig = cfg.channels?.[channel];
|
|
606
|
-
if (!channelConfig) return;
|
|
607
|
-
return resolveAccountEntry(channelConfig.accounts, normalizedAccountId)?.groups ?? channelConfig.groups;
|
|
608
|
-
}
|
|
609
|
-
function resolveChannelGroupToolsPolicy(params) {
|
|
610
|
-
const groups = resolveChannelGroups(params.cfg, params.channel, params.accountId);
|
|
611
|
-
const groupIds = [params.groupId, ...Array.isArray(params.groupIdCandidates) ? params.groupIdCandidates : []];
|
|
612
|
-
let groupConfig;
|
|
613
|
-
for (const rawGroupId of groupIds) {
|
|
614
|
-
const groupId = rawGroupId?.trim();
|
|
615
|
-
if (!groupId) continue;
|
|
616
|
-
groupConfig = resolveChannelGroupConfig(groups, groupId, params.groupIdCaseInsensitive);
|
|
617
|
-
if (groupConfig) break;
|
|
618
|
-
}
|
|
619
|
-
const defaultConfig = groups?.["*"];
|
|
620
|
-
const groupSenderPolicy = resolveToolsBySender({
|
|
621
|
-
toolsBySender: groupConfig?.toolsBySender,
|
|
622
|
-
senderId: params.senderId,
|
|
623
|
-
senderName: params.senderName,
|
|
624
|
-
senderUsername: params.senderUsername,
|
|
625
|
-
senderE164: params.senderE164
|
|
626
|
-
});
|
|
627
|
-
if (groupSenderPolicy) return groupSenderPolicy;
|
|
628
|
-
if (groupConfig?.tools) return groupConfig.tools;
|
|
629
|
-
const defaultSenderPolicy = resolveToolsBySender({
|
|
630
|
-
toolsBySender: defaultConfig?.toolsBySender,
|
|
631
|
-
senderId: params.senderId,
|
|
632
|
-
senderName: params.senderName,
|
|
633
|
-
senderUsername: params.senderUsername,
|
|
634
|
-
senderE164: params.senderE164
|
|
635
|
-
});
|
|
636
|
-
if (defaultSenderPolicy) return defaultSenderPolicy;
|
|
637
|
-
if (defaultConfig?.tools) return defaultConfig.tools;
|
|
638
|
-
}
|
|
639
|
-
//#endregion
|
|
640
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/parse-Bxp0CbaB.js
|
|
641
|
-
/**
|
|
642
|
-
* Extract audio mode tag from text.
|
|
643
|
-
* Supports [[audio_as_voice]] to send audio as voice message instead of file.
|
|
644
|
-
* Default is file (preserves backward compatibility).
|
|
645
|
-
*/
|
|
646
|
-
function parseAudioTag(text) {
|
|
647
|
-
const result = parseInlineDirectives(text, { stripReplyTags: false });
|
|
648
|
-
return {
|
|
649
|
-
text: result.text,
|
|
650
|
-
audioAsVoice: result.audioAsVoice,
|
|
651
|
-
hadTag: result.hasAudioTag
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
const MEDIA_TOKEN_RE = /\bMEDIA:\s*`?([^\n]+)`?/gi;
|
|
655
|
-
function normalizeMediaSource(src) {
|
|
656
|
-
return src.startsWith("file://") ? src.replace("file://", "") : src;
|
|
657
|
-
}
|
|
658
|
-
function cleanCandidate(raw) {
|
|
659
|
-
return raw.replace(/^[`"'[{(]+/, "").replace(/[`"'\\})\],]+$/, "");
|
|
660
|
-
}
|
|
661
|
-
const WINDOWS_DRIVE_RE$1 = /^[a-zA-Z]:[\\/]/;
|
|
662
|
-
const SCHEME_RE = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
|
|
663
|
-
const HAS_FILE_EXT = /\.\w{1,10}$/;
|
|
664
|
-
const TRAVERSAL_SEGMENT_RE = /(?:^|[/\\])\.\.(?:[/\\]|$)/;
|
|
665
|
-
function hasTraversalOrHomeDirPrefix(candidate) {
|
|
666
|
-
return candidate.startsWith("../") || candidate === ".." || candidate.startsWith("~") || TRAVERSAL_SEGMENT_RE.test(candidate);
|
|
667
|
-
}
|
|
668
|
-
function looksLikeLocalFilePath(candidate) {
|
|
669
|
-
return candidate.startsWith("/") || candidate.startsWith("./") || candidate.startsWith("../") || candidate.startsWith("~") || WINDOWS_DRIVE_RE$1.test(candidate) || candidate.startsWith("\\\\") || !SCHEME_RE.test(candidate) && (candidate.includes("/") || candidate.includes("\\"));
|
|
670
|
-
}
|
|
671
|
-
function isLikelyLocalPath(candidate) {
|
|
672
|
-
if (hasTraversalOrHomeDirPrefix(candidate)) return false;
|
|
673
|
-
return candidate.startsWith("/") || candidate.startsWith("./") || WINDOWS_DRIVE_RE$1.test(candidate) || candidate.startsWith("\\\\") || !SCHEME_RE.test(candidate) && (candidate.includes("/") || candidate.includes("\\"));
|
|
674
|
-
}
|
|
675
|
-
function isValidMedia(candidate, opts) {
|
|
676
|
-
if (!candidate) return false;
|
|
677
|
-
if (candidate.length > 4096) return false;
|
|
678
|
-
if (!opts?.allowSpaces && /\s/.test(candidate)) return false;
|
|
679
|
-
if (/^https?:\/\//i.test(candidate)) return true;
|
|
680
|
-
if (isLikelyLocalPath(candidate)) return true;
|
|
681
|
-
if (hasTraversalOrHomeDirPrefix(candidate)) return false;
|
|
682
|
-
if (opts?.allowBareFilename && !SCHEME_RE.test(candidate) && HAS_FILE_EXT.test(candidate)) return true;
|
|
683
|
-
return false;
|
|
684
|
-
}
|
|
685
|
-
function unwrapQuoted(value) {
|
|
686
|
-
const trimmed = value.trim();
|
|
687
|
-
if (trimmed.length < 2) return;
|
|
688
|
-
const first = trimmed[0];
|
|
689
|
-
if (first !== trimmed[trimmed.length - 1]) return;
|
|
690
|
-
if (first !== `"` && first !== "'" && first !== "`") return;
|
|
691
|
-
return trimmed.slice(1, -1).trim();
|
|
692
|
-
}
|
|
693
|
-
function mayContainFenceMarkers(input) {
|
|
694
|
-
return input.includes("```") || input.includes("~~~");
|
|
695
|
-
}
|
|
696
|
-
function isInsideFence(fenceSpans, offset) {
|
|
697
|
-
return fenceSpans.some((span) => offset >= span.start && offset < span.end);
|
|
698
|
-
}
|
|
699
|
-
function splitMediaFromOutput(raw) {
|
|
700
|
-
const trimmedRaw = raw.trimEnd();
|
|
701
|
-
if (!trimmedRaw.trim()) return { text: "" };
|
|
702
|
-
const mayContainMediaToken = /media:/i.test(trimmedRaw);
|
|
703
|
-
const mayContainAudioTag = trimmedRaw.includes("[[");
|
|
704
|
-
if (!mayContainMediaToken && !mayContainAudioTag) return { text: trimmedRaw };
|
|
705
|
-
const media = [];
|
|
706
|
-
let foundMediaToken = false;
|
|
707
|
-
const segments = [];
|
|
708
|
-
const pushTextSegment = (text) => {
|
|
709
|
-
if (!text) return;
|
|
710
|
-
const last = segments[segments.length - 1];
|
|
711
|
-
if (last?.type === "text") {
|
|
712
|
-
last.text = `${last.text}\n${text}`;
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
segments.push({
|
|
716
|
-
type: "text",
|
|
717
|
-
text
|
|
718
|
-
});
|
|
719
|
-
};
|
|
720
|
-
const hasFenceMarkers = mayContainFenceMarkers(trimmedRaw);
|
|
721
|
-
const fenceSpans = hasFenceMarkers ? parseFenceSpans(trimmedRaw) : [];
|
|
722
|
-
const lines = trimmedRaw.split("\n");
|
|
723
|
-
const keptLines = [];
|
|
724
|
-
let lineOffset = 0;
|
|
725
|
-
for (const line of lines) {
|
|
726
|
-
if (hasFenceMarkers && isInsideFence(fenceSpans, lineOffset)) {
|
|
727
|
-
keptLines.push(line);
|
|
728
|
-
pushTextSegment(line);
|
|
729
|
-
lineOffset += line.length + 1;
|
|
730
|
-
continue;
|
|
731
|
-
}
|
|
732
|
-
if (!line.trimStart().toUpperCase().startsWith("MEDIA:")) {
|
|
733
|
-
keptLines.push(line);
|
|
734
|
-
pushTextSegment(line);
|
|
735
|
-
lineOffset += line.length + 1;
|
|
736
|
-
continue;
|
|
737
|
-
}
|
|
738
|
-
const matches = Array.from(line.matchAll(MEDIA_TOKEN_RE));
|
|
739
|
-
if (matches.length === 0) {
|
|
740
|
-
keptLines.push(line);
|
|
741
|
-
pushTextSegment(line);
|
|
742
|
-
lineOffset += line.length + 1;
|
|
743
|
-
continue;
|
|
744
|
-
}
|
|
745
|
-
const pieces = [];
|
|
746
|
-
const lineSegments = [];
|
|
747
|
-
let cursor = 0;
|
|
748
|
-
for (const match of matches) {
|
|
749
|
-
const start = match.index ?? 0;
|
|
750
|
-
pieces.push(line.slice(cursor, start));
|
|
751
|
-
const payload = match[1];
|
|
752
|
-
const unwrapped = unwrapQuoted(payload);
|
|
753
|
-
const payloadValue = unwrapped ?? payload;
|
|
754
|
-
const parts = unwrapped ? [unwrapped] : payload.split(/\s+/).filter(Boolean);
|
|
755
|
-
const mediaStartIndex = media.length;
|
|
756
|
-
let validCount = 0;
|
|
757
|
-
const invalidParts = [];
|
|
758
|
-
let hasValidMedia = false;
|
|
759
|
-
for (const part of parts) {
|
|
760
|
-
const candidate = normalizeMediaSource(cleanCandidate(part));
|
|
761
|
-
if (isValidMedia(candidate, unwrapped ? { allowSpaces: true } : void 0)) {
|
|
762
|
-
media.push(candidate);
|
|
763
|
-
hasValidMedia = true;
|
|
764
|
-
foundMediaToken = true;
|
|
765
|
-
validCount += 1;
|
|
766
|
-
} else invalidParts.push(part);
|
|
767
|
-
}
|
|
768
|
-
const trimmedPayload = payloadValue.trim();
|
|
769
|
-
const looksLikeLocalPath = looksLikeLocalFilePath(trimmedPayload) || trimmedPayload.startsWith("file://");
|
|
770
|
-
if (!unwrapped && validCount === 1 && invalidParts.length > 0 && /\s/.test(payloadValue) && looksLikeLocalPath) {
|
|
771
|
-
const fallback = normalizeMediaSource(cleanCandidate(payloadValue));
|
|
772
|
-
if (isValidMedia(fallback, { allowSpaces: true })) {
|
|
773
|
-
media.splice(mediaStartIndex, media.length - mediaStartIndex, fallback);
|
|
774
|
-
hasValidMedia = true;
|
|
775
|
-
foundMediaToken = true;
|
|
776
|
-
validCount = 1;
|
|
777
|
-
invalidParts.length = 0;
|
|
778
|
-
}
|
|
779
|
-
}
|
|
780
|
-
if (!hasValidMedia && !unwrapped && /\s/.test(payloadValue)) {
|
|
781
|
-
const spacedFallback = normalizeMediaSource(cleanCandidate(payloadValue));
|
|
782
|
-
if (isValidMedia(spacedFallback, {
|
|
783
|
-
allowSpaces: true,
|
|
784
|
-
allowBareFilename: true
|
|
785
|
-
})) {
|
|
786
|
-
media.splice(mediaStartIndex, media.length - mediaStartIndex, spacedFallback);
|
|
787
|
-
hasValidMedia = true;
|
|
788
|
-
foundMediaToken = true;
|
|
789
|
-
validCount = 1;
|
|
790
|
-
invalidParts.length = 0;
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
if (!hasValidMedia) {
|
|
794
|
-
const fallback = normalizeMediaSource(cleanCandidate(payloadValue));
|
|
795
|
-
if (isValidMedia(fallback, {
|
|
796
|
-
allowSpaces: true,
|
|
797
|
-
allowBareFilename: true
|
|
798
|
-
})) {
|
|
799
|
-
media.push(fallback);
|
|
800
|
-
hasValidMedia = true;
|
|
801
|
-
foundMediaToken = true;
|
|
802
|
-
invalidParts.length = 0;
|
|
803
|
-
}
|
|
804
|
-
}
|
|
805
|
-
if (hasValidMedia) {
|
|
806
|
-
const beforeText = pieces.join("").replace(/[ \t]{2,}/g, " ").trim();
|
|
807
|
-
if (beforeText) lineSegments.push({
|
|
808
|
-
type: "text",
|
|
809
|
-
text: beforeText
|
|
810
|
-
});
|
|
811
|
-
pieces.length = 0;
|
|
812
|
-
for (const url of media.slice(mediaStartIndex, mediaStartIndex + validCount)) lineSegments.push({
|
|
813
|
-
type: "media",
|
|
814
|
-
url
|
|
815
|
-
});
|
|
816
|
-
if (invalidParts.length > 0) pieces.push(invalidParts.join(" "));
|
|
817
|
-
} else if (looksLikeLocalPath) foundMediaToken = true;
|
|
818
|
-
else pieces.push(match[0]);
|
|
819
|
-
cursor = start + match[0].length;
|
|
820
|
-
}
|
|
821
|
-
pieces.push(line.slice(cursor));
|
|
822
|
-
const cleanedLine = pieces.join("").replace(/[ \t]{2,}/g, " ").trim();
|
|
823
|
-
if (cleanedLine) {
|
|
824
|
-
keptLines.push(cleanedLine);
|
|
825
|
-
lineSegments.push({
|
|
826
|
-
type: "text",
|
|
827
|
-
text: cleanedLine
|
|
828
|
-
});
|
|
829
|
-
}
|
|
830
|
-
for (const segment of lineSegments) {
|
|
831
|
-
if (segment.type === "text") {
|
|
832
|
-
pushTextSegment(segment.text);
|
|
833
|
-
continue;
|
|
834
|
-
}
|
|
835
|
-
segments.push(segment);
|
|
836
|
-
}
|
|
837
|
-
lineOffset += line.length + 1;
|
|
838
|
-
}
|
|
839
|
-
let cleanedText = keptLines.join("\n").replace(/[ \t]+\n/g, "\n").replace(/[ \t]{2,}/g, " ").replace(/\n{2,}/g, "\n").trim();
|
|
840
|
-
const audioTagResult = parseAudioTag(cleanedText);
|
|
841
|
-
const hasAudioAsVoice = audioTagResult.audioAsVoice;
|
|
842
|
-
if (audioTagResult.hadTag) cleanedText = audioTagResult.text.replace(/\n{2,}/g, "\n").trim();
|
|
843
|
-
if (media.length === 0) {
|
|
844
|
-
const parsedText = foundMediaToken || hasAudioAsVoice ? cleanedText : trimmedRaw;
|
|
845
|
-
const result = {
|
|
846
|
-
text: parsedText,
|
|
847
|
-
segments: parsedText ? [{
|
|
848
|
-
type: "text",
|
|
849
|
-
text: parsedText
|
|
850
|
-
}] : []
|
|
851
|
-
};
|
|
852
|
-
if (hasAudioAsVoice) result.audioAsVoice = true;
|
|
853
|
-
return result;
|
|
854
|
-
}
|
|
855
|
-
return {
|
|
856
|
-
text: cleanedText,
|
|
857
|
-
mediaUrls: media,
|
|
858
|
-
mediaUrl: media[0],
|
|
859
|
-
segments: segments.length > 0 ? segments : [{
|
|
860
|
-
type: "text",
|
|
861
|
-
text: cleanedText
|
|
862
|
-
}],
|
|
863
|
-
...hasAudioAsVoice ? { audioAsVoice: true } : {}
|
|
864
|
-
};
|
|
865
|
-
}
|
|
866
|
-
//#endregion
|
|
867
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/pending-spawn-query-DuWwnOBt.js
|
|
868
|
-
const log$1 = createSubsystemLogger("outbound/pending-spawn");
|
|
869
|
-
const THROW_LOG_INTERVAL_MS = 6e4;
|
|
870
|
-
let lastThrowLogAt = 0;
|
|
871
|
-
let pendingSpawnedChildrenQuery;
|
|
872
|
-
function registerPendingSpawnedChildrenQuery(query) {
|
|
873
|
-
const previous = pendingSpawnedChildrenQuery;
|
|
874
|
-
pendingSpawnedChildrenQuery = query;
|
|
875
|
-
return previous;
|
|
876
|
-
}
|
|
877
|
-
function summarizeError(err) {
|
|
878
|
-
if (err instanceof Error) return {
|
|
879
|
-
name: err.name,
|
|
880
|
-
message: err.message
|
|
881
|
-
};
|
|
882
|
-
return {
|
|
883
|
-
name: "Unknown",
|
|
884
|
-
message: typeof err === "string" ? err : "non-error throw"
|
|
885
|
-
};
|
|
886
|
-
}
|
|
887
|
-
function hashSessionKey(key) {
|
|
888
|
-
const trimmed = key?.trim();
|
|
889
|
-
if (!trimmed) return;
|
|
890
|
-
return createHash("sha256").update(trimmed).digest("hex").slice(0, 12);
|
|
891
|
-
}
|
|
892
|
-
function resolvePendingSpawnedChildren(sessionKey) {
|
|
893
|
-
if (!pendingSpawnedChildrenQuery) return false;
|
|
894
|
-
try {
|
|
895
|
-
return pendingSpawnedChildrenQuery(sessionKey);
|
|
896
|
-
} catch (err) {
|
|
897
|
-
const now = Date.now();
|
|
898
|
-
if (now - lastThrowLogAt >= THROW_LOG_INTERVAL_MS) {
|
|
899
|
-
lastThrowLogAt = now;
|
|
900
|
-
log$1.warn("pending-spawn query threw; defaulting to false", {
|
|
901
|
-
err: summarizeError(err),
|
|
902
|
-
sessionKeyHash: hashSessionKey(sessionKey)
|
|
903
|
-
});
|
|
904
|
-
}
|
|
905
|
-
return false;
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
//#endregion
|
|
909
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/payloads-D1t_UbQs.js
|
|
910
|
-
function parseReplyDirectives(raw, options = {}) {
|
|
911
|
-
const split = splitMediaFromOutput(raw);
|
|
912
|
-
let text = split.text ?? "";
|
|
913
|
-
const replyParsed = parseInlineDirectives(text, {
|
|
914
|
-
currentMessageId: options.currentMessageId,
|
|
915
|
-
stripAudioTag: false,
|
|
916
|
-
stripReplyTags: true
|
|
917
|
-
});
|
|
918
|
-
if (replyParsed.hasReplyTag) text = replyParsed.text;
|
|
919
|
-
const silentToken = options.silentToken ?? "NO_REPLY";
|
|
920
|
-
const isSilent = isSilentReplyPayloadText(text, silentToken);
|
|
921
|
-
if (isSilent) text = "";
|
|
922
|
-
return {
|
|
923
|
-
text,
|
|
924
|
-
mediaUrls: split.mediaUrls,
|
|
925
|
-
mediaUrl: split.mediaUrl,
|
|
926
|
-
replyToId: replyParsed.replyToId,
|
|
927
|
-
replyToCurrent: replyParsed.replyToCurrent || void 0,
|
|
928
|
-
replyToTag: replyParsed.hasReplyTag,
|
|
929
|
-
audioAsVoice: split.audioAsVoice,
|
|
930
|
-
isSilent
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
function isSuppressedRelayStatusText(text) {
|
|
934
|
-
const normalized = text.trim();
|
|
935
|
-
if (!normalized) return false;
|
|
936
|
-
if (/^no channel reply\.?$/i.test(normalized)) return true;
|
|
937
|
-
if (/^replied in-thread\.?$/i.test(normalized)) return true;
|
|
938
|
-
if (/^replied in #[-\w]+\.?$/i.test(normalized)) return true;
|
|
939
|
-
if (/^updated\s+\[[^\]]*wiki\/[^\]]+\](?:\([^)]+\))?(?:\s+with\b[\s\S]*)?(?:\.\s*)?(?:no channel reply\.?)?$/i.test(normalized)) return true;
|
|
940
|
-
return false;
|
|
941
|
-
}
|
|
942
|
-
function mergeMediaUrls(...lists) {
|
|
943
|
-
const seen = /* @__PURE__ */ new Set();
|
|
944
|
-
const merged = [];
|
|
945
|
-
for (const list of lists) {
|
|
946
|
-
if (!list) continue;
|
|
947
|
-
for (const entry of list) {
|
|
948
|
-
const trimmed = entry?.trim();
|
|
949
|
-
if (!trimmed) continue;
|
|
950
|
-
if (seen.has(trimmed)) continue;
|
|
951
|
-
seen.add(trimmed);
|
|
952
|
-
merged.push(trimmed);
|
|
953
|
-
}
|
|
954
|
-
}
|
|
955
|
-
return merged;
|
|
956
|
-
}
|
|
957
|
-
function createOutboundPayloadPlanEntry(payload) {
|
|
958
|
-
if (shouldSuppressReasoningPayload(payload)) return null;
|
|
959
|
-
const parsed = parseReplyDirectives(payload.text ?? "");
|
|
960
|
-
const explicitMediaUrls = payload.mediaUrls ?? parsed.mediaUrls;
|
|
961
|
-
const explicitMediaUrl = payload.mediaUrl ?? parsed.mediaUrl;
|
|
962
|
-
const mergedMedia = mergeMediaUrls(explicitMediaUrls, explicitMediaUrl ? [explicitMediaUrl] : void 0);
|
|
963
|
-
const parsedText = parsed.text ?? "";
|
|
964
|
-
if (isSuppressedRelayStatusText(parsedText) && mergedMedia.length === 0) return null;
|
|
965
|
-
const isSilent = parsed.isSilent && mergedMedia.length === 0;
|
|
966
|
-
const resolvedMediaUrl = (explicitMediaUrls?.length ?? 0) > 1 ? void 0 : explicitMediaUrl;
|
|
967
|
-
const normalizedPayload = {
|
|
968
|
-
...payload,
|
|
969
|
-
text: formatBtwTextForExternalDelivery({
|
|
970
|
-
...payload,
|
|
971
|
-
text: parsedText
|
|
972
|
-
}) ?? "",
|
|
973
|
-
mediaUrls: mergedMedia.length ? mergedMedia : void 0,
|
|
974
|
-
mediaUrl: resolvedMediaUrl,
|
|
975
|
-
replyToId: payload.replyToId ?? parsed.replyToId,
|
|
976
|
-
replyToTag: payload.replyToTag || parsed.replyToTag,
|
|
977
|
-
replyToCurrent: payload.replyToCurrent || parsed.replyToCurrent,
|
|
978
|
-
audioAsVoice: Boolean(payload.audioAsVoice || parsed.audioAsVoice)
|
|
979
|
-
};
|
|
980
|
-
if (!isRenderablePayload(normalizedPayload) && !isSilent) return null;
|
|
981
|
-
const hasChannelData = hasReplyChannelData(normalizedPayload.channelData);
|
|
982
|
-
return {
|
|
983
|
-
payload: normalizedPayload,
|
|
984
|
-
hasPresentation: hasMessagePresentationBlocks(normalizedPayload.presentation),
|
|
985
|
-
hasInteractive: hasInteractiveReplyBlocks(normalizedPayload.interactive),
|
|
986
|
-
hasChannelData,
|
|
987
|
-
isSilent
|
|
988
|
-
};
|
|
989
|
-
}
|
|
990
|
-
function createOutboundPayloadPlan(payloads, context = {}) {
|
|
991
|
-
const resolvedSilentReplySettings = resolveSilentReplySettings({
|
|
992
|
-
cfg: context.cfg,
|
|
993
|
-
sessionKey: context.sessionKey,
|
|
994
|
-
surface: context.surface,
|
|
995
|
-
conversationType: context.conversationType
|
|
996
|
-
});
|
|
997
|
-
const hasPendingSpawnedChildren = context.hasPendingSpawnedChildren ?? resolvePendingSpawnedChildren(context.sessionKey);
|
|
998
|
-
const prepared = [];
|
|
999
|
-
for (const payload of payloads) {
|
|
1000
|
-
const entry = createOutboundPayloadPlanEntry(payload);
|
|
1001
|
-
if (!entry) continue;
|
|
1002
|
-
prepared.push(entry);
|
|
1003
|
-
}
|
|
1004
|
-
const hasVisibleNonSilentContent = prepared.some((entry) => {
|
|
1005
|
-
if (entry.isSilent) return false;
|
|
1006
|
-
const parts = resolveSendableOutboundReplyParts(entry.payload);
|
|
1007
|
-
return hasReplyPayloadContent({
|
|
1008
|
-
...entry.payload,
|
|
1009
|
-
text: parts.text,
|
|
1010
|
-
mediaUrls: parts.mediaUrls
|
|
1011
|
-
}, { hasChannelData: entry.hasChannelData });
|
|
1012
|
-
});
|
|
1013
|
-
const plan = [];
|
|
1014
|
-
for (const entry of prepared) {
|
|
1015
|
-
if (!entry.isSilent) {
|
|
1016
|
-
plan.push({
|
|
1017
|
-
payload: entry.payload,
|
|
1018
|
-
parts: resolveSendableOutboundReplyParts(entry.payload),
|
|
1019
|
-
hasPresentation: entry.hasPresentation,
|
|
1020
|
-
hasInteractive: entry.hasInteractive,
|
|
1021
|
-
hasChannelData: entry.hasChannelData
|
|
1022
|
-
});
|
|
1023
|
-
continue;
|
|
1024
|
-
}
|
|
1025
|
-
if (hasVisibleNonSilentContent || resolvedSilentReplySettings.policy === "allow" || hasPendingSpawnedChildren) continue;
|
|
1026
|
-
if (!resolvedSilentReplySettings.rewrite) {
|
|
1027
|
-
const visibleSilentPayload = {
|
|
1028
|
-
...entry.payload,
|
|
1029
|
-
text: entry.payload.text?.trim() || "NO_REPLY"
|
|
1030
|
-
};
|
|
1031
|
-
if (!isRenderablePayload(visibleSilentPayload)) continue;
|
|
1032
|
-
plan.push({
|
|
1033
|
-
payload: visibleSilentPayload,
|
|
1034
|
-
parts: resolveSendableOutboundReplyParts(visibleSilentPayload),
|
|
1035
|
-
hasPresentation: entry.hasPresentation,
|
|
1036
|
-
hasInteractive: entry.hasInteractive,
|
|
1037
|
-
hasChannelData: entry.hasChannelData
|
|
1038
|
-
});
|
|
1039
|
-
continue;
|
|
1040
|
-
}
|
|
1041
|
-
const rewrittenPayload = {
|
|
1042
|
-
...entry.payload,
|
|
1043
|
-
text: resolveSilentReplyRewriteText({ seed: `${context.sessionKey ?? context.surface ?? "silent-reply"}:${entry.payload.text ?? ""}` })
|
|
1044
|
-
};
|
|
1045
|
-
if (!isRenderablePayload(rewrittenPayload)) continue;
|
|
1046
|
-
plan.push({
|
|
1047
|
-
payload: rewrittenPayload,
|
|
1048
|
-
parts: resolveSendableOutboundReplyParts(rewrittenPayload),
|
|
1049
|
-
hasPresentation: entry.hasPresentation,
|
|
1050
|
-
hasInteractive: entry.hasInteractive,
|
|
1051
|
-
hasChannelData: entry.hasChannelData
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1054
|
-
return plan;
|
|
1055
|
-
}
|
|
1056
|
-
function projectOutboundPayloadPlanForDelivery(plan) {
|
|
1057
|
-
return plan.map((entry) => entry.payload);
|
|
1058
|
-
}
|
|
1059
|
-
function projectOutboundPayloadPlanForMirror(plan) {
|
|
1060
|
-
return {
|
|
1061
|
-
text: plan.map((entry) => entry.payload.text).filter((text) => Boolean(text)).join("\n"),
|
|
1062
|
-
mediaUrls: plan.flatMap((entry) => entry.parts.mediaUrls)
|
|
1063
|
-
};
|
|
1064
|
-
}
|
|
1065
|
-
function summarizeOutboundPayloadForTransport(payload) {
|
|
1066
|
-
const parts = resolveSendableOutboundReplyParts(payload);
|
|
1067
|
-
return {
|
|
1068
|
-
text: parts.text,
|
|
1069
|
-
mediaUrls: parts.mediaUrls,
|
|
1070
|
-
audioAsVoice: payload.audioAsVoice === true ? true : void 0,
|
|
1071
|
-
presentation: payload.presentation,
|
|
1072
|
-
delivery: payload.delivery,
|
|
1073
|
-
interactive: payload.interactive,
|
|
1074
|
-
channelData: payload.channelData
|
|
1075
|
-
};
|
|
1076
|
-
}
|
|
1077
|
-
[
|
|
1078
|
-
"import errno",
|
|
1079
|
-
"import os",
|
|
1080
|
-
"import stat",
|
|
1081
|
-
"import sys",
|
|
1082
|
-
"",
|
|
1083
|
-
"operation = sys.argv[1]",
|
|
1084
|
-
"root_path = sys.argv[2]",
|
|
1085
|
-
"relative_path = sys.argv[3]",
|
|
1086
|
-
"",
|
|
1087
|
-
"DIR_FLAGS = os.O_RDONLY",
|
|
1088
|
-
"if hasattr(os, 'O_DIRECTORY'):",
|
|
1089
|
-
" DIR_FLAGS |= os.O_DIRECTORY",
|
|
1090
|
-
"if hasattr(os, 'O_NOFOLLOW'):",
|
|
1091
|
-
" DIR_FLAGS |= os.O_NOFOLLOW",
|
|
1092
|
-
"",
|
|
1093
|
-
"def open_dir(path_value, dir_fd=None):",
|
|
1094
|
-
" return os.open(path_value, DIR_FLAGS, dir_fd=dir_fd)",
|
|
1095
|
-
"",
|
|
1096
|
-
"def split_segments(relative_path):",
|
|
1097
|
-
" return [part for part in relative_path.split('/') if part and part != '.']",
|
|
1098
|
-
"",
|
|
1099
|
-
"def validate_segment(segment):",
|
|
1100
|
-
" if segment == '..':",
|
|
1101
|
-
" raise OSError(errno.EPERM, 'path traversal is not allowed', segment)",
|
|
1102
|
-
"",
|
|
1103
|
-
"def walk_existing_path(root_fd, segments):",
|
|
1104
|
-
" current_fd = os.dup(root_fd)",
|
|
1105
|
-
" try:",
|
|
1106
|
-
" for segment in segments:",
|
|
1107
|
-
" validate_segment(segment)",
|
|
1108
|
-
" next_fd = open_dir(segment, dir_fd=current_fd)",
|
|
1109
|
-
" os.close(current_fd)",
|
|
1110
|
-
" current_fd = next_fd",
|
|
1111
|
-
" return current_fd",
|
|
1112
|
-
" except Exception:",
|
|
1113
|
-
" os.close(current_fd)",
|
|
1114
|
-
" raise",
|
|
1115
|
-
"",
|
|
1116
|
-
"def mkdirp_within_root(root_fd, segments):",
|
|
1117
|
-
" current_fd = os.dup(root_fd)",
|
|
1118
|
-
" try:",
|
|
1119
|
-
" for segment in segments:",
|
|
1120
|
-
" validate_segment(segment)",
|
|
1121
|
-
" try:",
|
|
1122
|
-
" next_fd = open_dir(segment, dir_fd=current_fd)",
|
|
1123
|
-
" except FileNotFoundError:",
|
|
1124
|
-
" os.mkdir(segment, 0o777, dir_fd=current_fd)",
|
|
1125
|
-
" next_fd = open_dir(segment, dir_fd=current_fd)",
|
|
1126
|
-
" os.close(current_fd)",
|
|
1127
|
-
" current_fd = next_fd",
|
|
1128
|
-
" finally:",
|
|
1129
|
-
" os.close(current_fd)",
|
|
1130
|
-
"",
|
|
1131
|
-
"def remove_within_root(root_fd, segments):",
|
|
1132
|
-
" if not segments:",
|
|
1133
|
-
" raise OSError(errno.EPERM, 'refusing to remove root path')",
|
|
1134
|
-
" parent_segments = segments[:-1]",
|
|
1135
|
-
" basename = segments[-1]",
|
|
1136
|
-
" validate_segment(basename)",
|
|
1137
|
-
" parent_fd = walk_existing_path(root_fd, parent_segments)",
|
|
1138
|
-
" try:",
|
|
1139
|
-
" target_stat = os.lstat(basename, dir_fd=parent_fd)",
|
|
1140
|
-
" if stat.S_ISDIR(target_stat.st_mode) and not stat.S_ISLNK(target_stat.st_mode):",
|
|
1141
|
-
" os.rmdir(basename, dir_fd=parent_fd)",
|
|
1142
|
-
" else:",
|
|
1143
|
-
" os.unlink(basename, dir_fd=parent_fd)",
|
|
1144
|
-
" finally:",
|
|
1145
|
-
" os.close(parent_fd)",
|
|
1146
|
-
"",
|
|
1147
|
-
"root_fd = open_dir(root_path)",
|
|
1148
|
-
"try:",
|
|
1149
|
-
" segments = split_segments(relative_path)",
|
|
1150
|
-
" if operation == 'mkdirp':",
|
|
1151
|
-
" mkdirp_within_root(root_fd, segments)",
|
|
1152
|
-
" elif operation == 'remove':",
|
|
1153
|
-
" remove_within_root(root_fd, segments)",
|
|
1154
|
-
" else:",
|
|
1155
|
-
" raise RuntimeError(f'unknown pinned path operation: {operation}')",
|
|
1156
|
-
"finally:",
|
|
1157
|
-
" os.close(root_fd)"
|
|
1158
|
-
].join("\n");
|
|
1159
|
-
[
|
|
1160
|
-
process.env.OPENCLAW_PINNED_PYTHON,
|
|
1161
|
-
process.env.OPENCLAW_PINNED_WRITE_PYTHON,
|
|
1162
|
-
"/usr/bin/python3",
|
|
1163
|
-
"/opt/homebrew/bin/python3",
|
|
1164
|
-
"/usr/local/bin/python3"
|
|
1165
|
-
].filter((value) => Boolean(value));
|
|
1166
|
-
[
|
|
1167
|
-
"import errno",
|
|
1168
|
-
"import os",
|
|
1169
|
-
"import secrets",
|
|
1170
|
-
"import stat",
|
|
1171
|
-
"import sys",
|
|
1172
|
-
"",
|
|
1173
|
-
"root_path = sys.argv[1]",
|
|
1174
|
-
"relative_parent = sys.argv[2]",
|
|
1175
|
-
"basename = sys.argv[3]",
|
|
1176
|
-
"mkdir_enabled = sys.argv[4] == \"1\"",
|
|
1177
|
-
"file_mode = int(sys.argv[5], 8)",
|
|
1178
|
-
"",
|
|
1179
|
-
"DIR_FLAGS = os.O_RDONLY",
|
|
1180
|
-
"if hasattr(os, 'O_DIRECTORY'):",
|
|
1181
|
-
" DIR_FLAGS |= os.O_DIRECTORY",
|
|
1182
|
-
"if hasattr(os, 'O_NOFOLLOW'):",
|
|
1183
|
-
" DIR_FLAGS |= os.O_NOFOLLOW",
|
|
1184
|
-
"",
|
|
1185
|
-
"WRITE_FLAGS = os.O_WRONLY | os.O_CREAT | os.O_EXCL",
|
|
1186
|
-
"if hasattr(os, 'O_NOFOLLOW'):",
|
|
1187
|
-
" WRITE_FLAGS |= os.O_NOFOLLOW",
|
|
1188
|
-
"",
|
|
1189
|
-
"def open_dir(path_value, dir_fd=None):",
|
|
1190
|
-
" return os.open(path_value, DIR_FLAGS, dir_fd=dir_fd)",
|
|
1191
|
-
"",
|
|
1192
|
-
"def walk_parent(root_fd, rel_parent, mkdir_enabled):",
|
|
1193
|
-
" current_fd = os.dup(root_fd)",
|
|
1194
|
-
" try:",
|
|
1195
|
-
" for segment in [part for part in rel_parent.split('/') if part and part != '.']:",
|
|
1196
|
-
" if segment == '..':",
|
|
1197
|
-
" raise OSError(errno.EPERM, 'path traversal is not allowed', segment)",
|
|
1198
|
-
" try:",
|
|
1199
|
-
" next_fd = open_dir(segment, dir_fd=current_fd)",
|
|
1200
|
-
" except FileNotFoundError:",
|
|
1201
|
-
" if not mkdir_enabled:",
|
|
1202
|
-
" raise",
|
|
1203
|
-
" os.mkdir(segment, 0o777, dir_fd=current_fd)",
|
|
1204
|
-
" next_fd = open_dir(segment, dir_fd=current_fd)",
|
|
1205
|
-
" os.close(current_fd)",
|
|
1206
|
-
" current_fd = next_fd",
|
|
1207
|
-
" return current_fd",
|
|
1208
|
-
" except Exception:",
|
|
1209
|
-
" os.close(current_fd)",
|
|
1210
|
-
" raise",
|
|
1211
|
-
"",
|
|
1212
|
-
"def create_temp_file(parent_fd, basename, mode):",
|
|
1213
|
-
" prefix = '.' + basename + '.'",
|
|
1214
|
-
" for _ in range(128):",
|
|
1215
|
-
" candidate = prefix + secrets.token_hex(6) + '.tmp'",
|
|
1216
|
-
" try:",
|
|
1217
|
-
" fd = os.open(candidate, WRITE_FLAGS, mode, dir_fd=parent_fd)",
|
|
1218
|
-
" return candidate, fd",
|
|
1219
|
-
" except FileExistsError:",
|
|
1220
|
-
" continue",
|
|
1221
|
-
" raise RuntimeError('failed to allocate pinned temp file')",
|
|
1222
|
-
"",
|
|
1223
|
-
"root_fd = open_dir(root_path)",
|
|
1224
|
-
"parent_fd = None",
|
|
1225
|
-
"temp_fd = None",
|
|
1226
|
-
"temp_name = None",
|
|
1227
|
-
"try:",
|
|
1228
|
-
" parent_fd = walk_parent(root_fd, relative_parent, mkdir_enabled)",
|
|
1229
|
-
" temp_name, temp_fd = create_temp_file(parent_fd, basename, file_mode)",
|
|
1230
|
-
" while True:",
|
|
1231
|
-
" chunk = sys.stdin.buffer.read(65536)",
|
|
1232
|
-
" if not chunk:",
|
|
1233
|
-
" break",
|
|
1234
|
-
" os.write(temp_fd, chunk)",
|
|
1235
|
-
" os.fsync(temp_fd)",
|
|
1236
|
-
" os.close(temp_fd)",
|
|
1237
|
-
" temp_fd = None",
|
|
1238
|
-
" os.replace(temp_name, basename, src_dir_fd=parent_fd, dst_dir_fd=parent_fd)",
|
|
1239
|
-
" temp_name = None",
|
|
1240
|
-
" os.fsync(parent_fd)",
|
|
1241
|
-
" result_stat = os.stat(basename, dir_fd=parent_fd, follow_symlinks=False)",
|
|
1242
|
-
" print(f'{result_stat.st_dev}|{result_stat.st_ino}')",
|
|
1243
|
-
"finally:",
|
|
1244
|
-
" if temp_fd is not None:",
|
|
1245
|
-
" os.close(temp_fd)",
|
|
1246
|
-
" if temp_name is not None and parent_fd is not None:",
|
|
1247
|
-
" try:",
|
|
1248
|
-
" os.unlink(temp_name, dir_fd=parent_fd)",
|
|
1249
|
-
" except FileNotFoundError:",
|
|
1250
|
-
" pass",
|
|
1251
|
-
" if parent_fd is not None:",
|
|
1252
|
-
" os.close(parent_fd)",
|
|
1253
|
-
" os.close(root_fd)"
|
|
1254
|
-
].join("\n");
|
|
1255
|
-
[
|
|
1256
|
-
process.env.OPENCLAW_PINNED_WRITE_PYTHON,
|
|
1257
|
-
"/usr/bin/python3",
|
|
1258
|
-
"/opt/homebrew/bin/python3",
|
|
1259
|
-
"/usr/local/bin/python3"
|
|
1260
|
-
].filter((value) => Boolean(value));
|
|
1261
|
-
var SafeOpenError = class extends Error {
|
|
1262
|
-
constructor(code, message, options) {
|
|
1263
|
-
super(message, options);
|
|
1264
|
-
this.code = code;
|
|
1265
|
-
this.name = "SafeOpenError";
|
|
1266
|
-
}
|
|
1267
|
-
};
|
|
1268
|
-
let fsSafeTestHooks;
|
|
1269
|
-
const SUPPORTS_NOFOLLOW = process.platform !== "win32" && "O_NOFOLLOW" in constants;
|
|
1270
|
-
const NONBLOCK_OPEN_FLAG = "O_NONBLOCK" in constants ? constants.O_NONBLOCK : 0;
|
|
1271
|
-
const OPEN_READ_FLAGS = constants.O_RDONLY | (SUPPORTS_NOFOLLOW ? constants.O_NOFOLLOW : 0);
|
|
1272
|
-
const OPEN_READ_NONBLOCK_FLAGS = OPEN_READ_FLAGS | NONBLOCK_OPEN_FLAG;
|
|
1273
|
-
const OPEN_READ_FOLLOW_FLAGS = constants.O_RDONLY;
|
|
1274
|
-
const OPEN_READ_FOLLOW_NONBLOCK_FLAGS = OPEN_READ_FOLLOW_FLAGS | NONBLOCK_OPEN_FLAG;
|
|
1275
|
-
constants.O_WRONLY | (SUPPORTS_NOFOLLOW ? constants.O_NOFOLLOW : 0);
|
|
1276
|
-
constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | (SUPPORTS_NOFOLLOW ? constants.O_NOFOLLOW : 0);
|
|
1277
|
-
constants.O_RDWR | constants.O_APPEND | (SUPPORTS_NOFOLLOW ? constants.O_NOFOLLOW : 0);
|
|
1278
|
-
constants.O_RDWR | constants.O_APPEND | constants.O_CREAT | constants.O_EXCL | (SUPPORTS_NOFOLLOW ? constants.O_NOFOLLOW : 0);
|
|
1279
|
-
async function openVerifiedLocalFile(filePath, options) {
|
|
1280
|
-
try {
|
|
1281
|
-
if ((await fs$1.lstat(filePath)).isDirectory()) throw new SafeOpenError("not-file", "not a file");
|
|
1282
|
-
await fsSafeTestHooks?.afterPreOpenLstat?.(filePath);
|
|
1283
|
-
} catch (err) {
|
|
1284
|
-
if (err instanceof SafeOpenError) throw err;
|
|
1285
|
-
}
|
|
1286
|
-
let handle;
|
|
1287
|
-
try {
|
|
1288
|
-
const openFlags = options?.allowSymlinkTargetWithinRoot ? options?.nonBlockingRead ? OPEN_READ_FOLLOW_NONBLOCK_FLAGS : OPEN_READ_FOLLOW_FLAGS : options?.nonBlockingRead ? OPEN_READ_NONBLOCK_FLAGS : OPEN_READ_FLAGS;
|
|
1289
|
-
await fsSafeTestHooks?.beforeOpen?.(filePath, openFlags);
|
|
1290
|
-
handle = await fs$1.open(filePath, openFlags);
|
|
1291
|
-
try {
|
|
1292
|
-
await fsSafeTestHooks?.afterOpen?.(filePath, handle);
|
|
1293
|
-
} catch (err) {
|
|
1294
|
-
await handle.close().catch(() => {});
|
|
1295
|
-
throw err;
|
|
1296
|
-
}
|
|
1297
|
-
} catch (err) {
|
|
1298
|
-
if (isNotFoundPathError(err)) throw new SafeOpenError("not-found", "file not found");
|
|
1299
|
-
if (isSymlinkOpenError(err)) throw new SafeOpenError("symlink", "symlink open blocked", { cause: err });
|
|
1300
|
-
if (hasNodeErrorCode(err, "EISDIR")) throw new SafeOpenError("not-file", "not a file");
|
|
1301
|
-
throw err;
|
|
1302
|
-
}
|
|
1303
|
-
try {
|
|
1304
|
-
const stat = await handle.stat();
|
|
1305
|
-
if (!stat.isFile()) throw new SafeOpenError("not-file", "not a file");
|
|
1306
|
-
if (options?.rejectHardlinks && stat.nlink > 1) throw new SafeOpenError("invalid-path", "hardlinked path not allowed");
|
|
1307
|
-
if (options?.allowSymlinkTargetWithinRoot) {
|
|
1308
|
-
if (!sameFileIdentity(stat, await fs$1.stat(filePath))) throw new SafeOpenError("path-mismatch", "path changed during read");
|
|
1309
|
-
} else {
|
|
1310
|
-
const pathStat = await fs$1.lstat(filePath);
|
|
1311
|
-
if (pathStat.isSymbolicLink()) throw new SafeOpenError("symlink", "symlink not allowed");
|
|
1312
|
-
if (!sameFileIdentity(stat, pathStat)) throw new SafeOpenError("path-mismatch", "path changed during read");
|
|
1313
|
-
}
|
|
1314
|
-
const realPath = await resolveOpenedFileRealPathForHandle(handle, filePath);
|
|
1315
|
-
const realStat = await fs$1.stat(realPath);
|
|
1316
|
-
if (options?.rejectHardlinks && realStat.nlink > 1) throw new SafeOpenError("invalid-path", "hardlinked path not allowed");
|
|
1317
|
-
if (!sameFileIdentity(stat, realStat)) throw new SafeOpenError("path-mismatch", "path mismatch");
|
|
1318
|
-
return {
|
|
1319
|
-
handle,
|
|
1320
|
-
realPath,
|
|
1321
|
-
stat
|
|
1322
|
-
};
|
|
1323
|
-
} catch (err) {
|
|
1324
|
-
await handle.close().catch(() => {});
|
|
1325
|
-
if (err instanceof SafeOpenError) throw err;
|
|
1326
|
-
if (isNotFoundPathError(err)) throw new SafeOpenError("not-found", "file not found");
|
|
1327
|
-
throw err;
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
async function readLocalFileSafely(params) {
|
|
1331
|
-
const opened = await openLocalFileSafely({ filePath: params.filePath });
|
|
1332
|
-
try {
|
|
1333
|
-
return await readOpenedFileSafely({
|
|
1334
|
-
opened,
|
|
1335
|
-
maxBytes: params.maxBytes
|
|
1336
|
-
});
|
|
1337
|
-
} finally {
|
|
1338
|
-
await opened.handle.close().catch(() => {});
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1341
|
-
async function openLocalFileSafely(params) {
|
|
1342
|
-
return await openVerifiedLocalFile(params.filePath);
|
|
1343
|
-
}
|
|
1344
|
-
async function readOpenedFileSafely(params) {
|
|
1345
|
-
if (params.maxBytes !== void 0 && params.opened.stat.size > params.maxBytes) throw new SafeOpenError("too-large", `file exceeds limit of ${params.maxBytes} bytes (got ${params.opened.stat.size})`);
|
|
1346
|
-
return {
|
|
1347
|
-
buffer: await params.opened.handle.readFile(),
|
|
1348
|
-
realPath: params.opened.realPath,
|
|
1349
|
-
stat: params.opened.stat
|
|
1350
|
-
};
|
|
1351
|
-
}
|
|
1352
|
-
async function resolveOpenedFileRealPathForHandle(handle, ioPath) {
|
|
1353
|
-
const handleStat = await handle.stat();
|
|
1354
|
-
const fdCandidates = process.platform === "linux" ? [`/proc/self/fd/${handle.fd}`, `/dev/fd/${handle.fd}`] : process.platform === "win32" ? [] : [`/dev/fd/${handle.fd}`];
|
|
1355
|
-
for (const fdPath of fdCandidates) try {
|
|
1356
|
-
const fdRealPath = await fs$1.realpath(fdPath);
|
|
1357
|
-
if (sameFileIdentity(handleStat, await fs$1.stat(fdRealPath))) return fdRealPath;
|
|
1358
|
-
} catch {}
|
|
1359
|
-
try {
|
|
1360
|
-
const ioRealPath = await fs$1.realpath(ioPath);
|
|
1361
|
-
if (sameFileIdentity(handleStat, await fs$1.stat(ioRealPath))) return ioRealPath;
|
|
1362
|
-
} catch (err) {
|
|
1363
|
-
if (!isNotFoundPathError(err)) throw err;
|
|
1364
|
-
}
|
|
1365
|
-
const parentResolved = await resolveOpenedFileRealPathFromParent(handleStat, ioPath);
|
|
1366
|
-
if (parentResolved) return parentResolved;
|
|
1367
|
-
throw new SafeOpenError("path-mismatch", "unable to resolve opened file path");
|
|
1368
|
-
}
|
|
1369
|
-
async function resolveOpenedFileRealPathFromParent(handleStat, ioPath) {
|
|
1370
|
-
let parentReal;
|
|
1371
|
-
try {
|
|
1372
|
-
parentReal = await fs$1.realpath(path.dirname(ioPath));
|
|
1373
|
-
} catch (err) {
|
|
1374
|
-
if (isNotFoundPathError(err)) return null;
|
|
1375
|
-
throw err;
|
|
1376
|
-
}
|
|
1377
|
-
let entries;
|
|
1378
|
-
try {
|
|
1379
|
-
entries = await fs$1.readdir(parentReal);
|
|
1380
|
-
} catch (err) {
|
|
1381
|
-
if (isNotFoundPathError(err)) return null;
|
|
1382
|
-
throw err;
|
|
1383
|
-
}
|
|
1384
|
-
for (const entry of entries.toSorted()) {
|
|
1385
|
-
const candidatePath = path.join(parentReal, entry);
|
|
1386
|
-
try {
|
|
1387
|
-
const candidateStat = await fs$1.lstat(candidatePath);
|
|
1388
|
-
if (candidateStat.isFile() && sameFileIdentity(handleStat, candidateStat)) return await fs$1.realpath(candidatePath);
|
|
1389
|
-
} catch (err) {
|
|
1390
|
-
if (!isNotFoundPathError(err)) throw err;
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
return null;
|
|
1394
|
-
}
|
|
1395
|
-
//#endregion
|
|
1396
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/archive-path-DQosmKv_.js
|
|
1397
|
-
function isWindowsDrivePath(value) {
|
|
1398
|
-
return /^[a-zA-Z]:[\\/]/.test(value);
|
|
1399
|
-
}
|
|
1400
|
-
//#endregion
|
|
1401
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/local-file-access-BpdUv1jJ.js
|
|
1402
|
-
const ENCODED_FILE_URL_SEPARATOR_RE = /%(?:2f|5c)/i;
|
|
1403
|
-
function isLocalFileUrlHost(hostname) {
|
|
1404
|
-
const normalized = normalizeLowercaseStringOrEmpty(hostname);
|
|
1405
|
-
return normalized === "" || normalized === "localhost";
|
|
1406
|
-
}
|
|
1407
|
-
function hasEncodedFileUrlSeparator(pathname) {
|
|
1408
|
-
return ENCODED_FILE_URL_SEPARATOR_RE.test(pathname);
|
|
1409
|
-
}
|
|
1410
|
-
function isWindowsNetworkPath(filePath) {
|
|
1411
|
-
if (process.platform !== "win32") return false;
|
|
1412
|
-
const normalized = filePath.replace(/\//g, "\\");
|
|
1413
|
-
return normalized.startsWith("\\\\?\\UNC\\") || normalized.startsWith("\\\\");
|
|
1414
|
-
}
|
|
1415
|
-
function assertNoWindowsNetworkPath(filePath, label = "Path") {
|
|
1416
|
-
if (isWindowsNetworkPath(filePath)) throw new Error(`${label} cannot use Windows network paths: ${filePath}`);
|
|
1417
|
-
}
|
|
1418
|
-
function safeFileURLToPath(fileUrl) {
|
|
1419
|
-
let parsed;
|
|
1420
|
-
try {
|
|
1421
|
-
parsed = new URL(fileUrl);
|
|
1422
|
-
} catch {
|
|
1423
|
-
throw new Error(`Invalid file:// URL: ${fileUrl}`);
|
|
1424
|
-
}
|
|
1425
|
-
if (parsed.protocol !== "file:") throw new Error(`Invalid file:// URL: ${fileUrl}`);
|
|
1426
|
-
if (!isLocalFileUrlHost(parsed.hostname)) throw new Error(`file:// URLs with remote hosts are not allowed: ${fileUrl}`);
|
|
1427
|
-
if (hasEncodedFileUrlSeparator(parsed.pathname)) throw new Error(`file:// URLs cannot encode path separators: ${fileUrl}`);
|
|
1428
|
-
const filePath = fileURLToPath(parsed);
|
|
1429
|
-
assertNoWindowsNetworkPath(filePath, "Local file URL");
|
|
1430
|
-
return filePath;
|
|
1431
|
-
}
|
|
1432
|
-
//#endregion
|
|
1433
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/media-source-url-DLCfXDgg.js
|
|
1434
|
-
const HTTP_URL_RE = /^https?:\/\//i;
|
|
1435
|
-
const MXC_URL_RE = /^mxc:\/\//i;
|
|
1436
|
-
function isPassThroughRemoteMediaSource(value) {
|
|
1437
|
-
const normalized = value?.trim() ?? "";
|
|
1438
|
-
return Boolean(normalized) && (HTTP_URL_RE.test(normalized) || MXC_URL_RE.test(normalized));
|
|
1439
|
-
}
|
|
1440
|
-
//#endregion
|
|
1441
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/sandbox-paths-OtvpaIO7.js
|
|
1442
|
-
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
1443
|
-
function normalizeUnicodeSpaces(str) {
|
|
1444
|
-
return str.replace(UNICODE_SPACES, " ");
|
|
1445
|
-
}
|
|
1446
|
-
function normalizeAtPrefix(filePath) {
|
|
1447
|
-
return filePath.startsWith("@") ? filePath.slice(1) : filePath;
|
|
1448
|
-
}
|
|
1449
|
-
function expandPath(filePath) {
|
|
1450
|
-
const normalized = normalizeUnicodeSpaces(normalizeAtPrefix(filePath));
|
|
1451
|
-
if (normalized === "~") return os.homedir();
|
|
1452
|
-
if (normalized.startsWith("~/")) return os.homedir() + normalized.slice(1);
|
|
1453
|
-
return normalized;
|
|
1454
|
-
}
|
|
1455
|
-
function resolveToCwd(filePath, cwd) {
|
|
1456
|
-
const expanded = expandPath(filePath);
|
|
1457
|
-
if (isWindowsDrivePath(expanded)) return path.win32.normalize(expanded);
|
|
1458
|
-
if (path.isAbsolute(expanded)) return expanded;
|
|
1459
|
-
return path.resolve(cwd, expanded);
|
|
1460
|
-
}
|
|
1461
|
-
function resolveSandboxInputPath(filePath, cwd) {
|
|
1462
|
-
return resolveToCwd(filePath, cwd);
|
|
1463
|
-
}
|
|
1464
|
-
//#endregion
|
|
1465
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/sandbox-tool-policy-CQSRiUbA.js
|
|
1466
|
-
function unionAllow(base, extra) {
|
|
1467
|
-
if (!Array.isArray(extra) || extra.length === 0) return base;
|
|
1468
|
-
if (!Array.isArray(base)) return Array.from(new Set(["*", ...extra]));
|
|
1469
|
-
if (base.length === 0) return Array.from(new Set(["*", ...extra]));
|
|
1470
|
-
return Array.from(new Set([...base, ...extra]));
|
|
1471
|
-
}
|
|
1472
|
-
function pickSandboxToolPolicy(config) {
|
|
1473
|
-
if (!config) return;
|
|
1474
|
-
const allow = Array.isArray(config.allow) ? unionAllow(config.allow, config.alsoAllow) : Array.isArray(config.alsoAllow) && config.alsoAllow.length > 0 ? unionAllow(void 0, config.alsoAllow) : void 0;
|
|
1475
|
-
const deny = Array.isArray(config.deny) ? config.deny : void 0;
|
|
1476
|
-
if (!allow && !deny) return;
|
|
1477
|
-
return {
|
|
1478
|
-
allow,
|
|
1479
|
-
deny
|
|
1480
|
-
};
|
|
1481
|
-
}
|
|
1482
|
-
//#endregion
|
|
1483
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/tool-policy-match-DCu-CJil.js
|
|
1484
|
-
function makeToolPolicyMatcher(policy) {
|
|
1485
|
-
const deny = compileGlobPatterns({
|
|
1486
|
-
raw: expandToolGroups(policy.deny ?? []),
|
|
1487
|
-
normalize: normalizeToolName
|
|
1488
|
-
});
|
|
1489
|
-
const allow = compileGlobPatterns({
|
|
1490
|
-
raw: expandToolGroups(policy.allow ?? []),
|
|
1491
|
-
normalize: normalizeToolName
|
|
1492
|
-
});
|
|
1493
|
-
return (name) => {
|
|
1494
|
-
const normalized = normalizeToolName(name);
|
|
1495
|
-
if (matchesAnyGlobPattern(normalized, deny)) return false;
|
|
1496
|
-
if (normalized === "apply_patch" && matchesAnyGlobPattern("write", deny)) return false;
|
|
1497
|
-
if (allow.length === 0) return true;
|
|
1498
|
-
if (matchesAnyGlobPattern(normalized, allow)) return true;
|
|
1499
|
-
if (normalized === "apply_patch" && matchesAnyGlobPattern("write", allow)) return true;
|
|
1500
|
-
return false;
|
|
1501
|
-
};
|
|
1502
|
-
}
|
|
1503
|
-
function isToolAllowedByPolicyName(name, policy) {
|
|
1504
|
-
if (!policy) return true;
|
|
1505
|
-
return makeToolPolicyMatcher(policy)(name);
|
|
1506
|
-
}
|
|
1507
|
-
function isToolAllowedByPolicies(name, policies) {
|
|
1508
|
-
return policies.every((policy) => isToolAllowedByPolicyName(name, policy));
|
|
1509
|
-
}
|
|
1510
|
-
//#endregion
|
|
1511
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/local-roots-B40QFFFV.js
|
|
1512
|
-
function resolveToolFsConfig(params) {
|
|
1513
|
-
const cfg = params.cfg;
|
|
1514
|
-
const globalFs = cfg?.tools?.fs;
|
|
1515
|
-
return { workspaceOnly: (cfg && params.agentId ? resolveAgentConfig(cfg, params.agentId)?.tools?.fs : void 0)?.workspaceOnly ?? globalFs?.workspaceOnly };
|
|
1516
|
-
}
|
|
1517
|
-
function resolveEffectiveToolFsWorkspaceOnly(params) {
|
|
1518
|
-
return resolveToolFsConfig(params).workspaceOnly === true;
|
|
1519
|
-
}
|
|
1520
|
-
function resolveEffectiveToolFsRootExpansionAllowed(params) {
|
|
1521
|
-
const cfg = params.cfg;
|
|
1522
|
-
if (!cfg) return true;
|
|
1523
|
-
const agentTools = params.agentId ? resolveAgentConfig(cfg, params.agentId)?.tools : void 0;
|
|
1524
|
-
const globalTools = cfg.tools;
|
|
1525
|
-
const profile = agentTools?.profile ?? globalTools?.profile;
|
|
1526
|
-
const profileAlsoAllow = new Set(agentTools?.alsoAllow ?? globalTools?.alsoAllow ?? []);
|
|
1527
|
-
const fsConfig = resolveToolFsConfig(params);
|
|
1528
|
-
const hasExplicitFsConfig = agentTools?.fs !== void 0 || globalTools?.fs !== void 0;
|
|
1529
|
-
if (fsConfig.workspaceOnly === true) return false;
|
|
1530
|
-
if (hasExplicitFsConfig) {
|
|
1531
|
-
profileAlsoAllow.add("read");
|
|
1532
|
-
profileAlsoAllow.add("write");
|
|
1533
|
-
profileAlsoAllow.add("edit");
|
|
1534
|
-
}
|
|
1535
|
-
return isToolAllowedByPolicies("read", [
|
|
1536
|
-
mergeAlsoAllowPolicy(resolveToolProfilePolicy(profile), profileAlsoAllow.size > 0 ? Array.from(profileAlsoAllow) : void 0),
|
|
1537
|
-
pickSandboxToolPolicy(globalTools),
|
|
1538
|
-
pickSandboxToolPolicy(agentTools)
|
|
1539
|
-
]);
|
|
1540
|
-
}
|
|
1541
|
-
let cachedPreferredTmpDir;
|
|
1542
|
-
const DATA_URL_RE = /^data:/i;
|
|
1543
|
-
const WINDOWS_DRIVE_RE = /^[A-Za-z]:[\\/]/;
|
|
1544
|
-
function resolveCachedPreferredTmpDir() {
|
|
1545
|
-
if (!cachedPreferredTmpDir) cachedPreferredTmpDir = resolvePreferredOpenClawTmpDir();
|
|
1546
|
-
return cachedPreferredTmpDir;
|
|
1547
|
-
}
|
|
1548
|
-
function buildMediaLocalRoots(stateDir, configDir, options = {}) {
|
|
1549
|
-
const resolvedStateDir = path.resolve(stateDir);
|
|
1550
|
-
const resolvedConfigDir = path.resolve(configDir);
|
|
1551
|
-
const preferredTmpDir = options.preferredTmpDir ?? resolveCachedPreferredTmpDir();
|
|
1552
|
-
return Array.from(new Set([
|
|
1553
|
-
preferredTmpDir,
|
|
1554
|
-
path.join(resolvedConfigDir, "media"),
|
|
1555
|
-
path.join(resolvedStateDir, "media"),
|
|
1556
|
-
path.join(resolvedStateDir, "canvas"),
|
|
1557
|
-
path.join(resolvedStateDir, "workspace"),
|
|
1558
|
-
path.join(resolvedStateDir, "sandboxes")
|
|
1559
|
-
]));
|
|
1560
|
-
}
|
|
1561
|
-
function getAgentScopedMediaLocalRoots(cfg, agentId) {
|
|
1562
|
-
const roots = buildMediaLocalRoots(resolveStateDir(), resolveConfigDir());
|
|
1563
|
-
const normalizedAgentId = normalizeOptionalString(agentId);
|
|
1564
|
-
if (!normalizedAgentId) return roots;
|
|
1565
|
-
const workspaceDir = resolveAgentWorkspaceDir(cfg, normalizedAgentId);
|
|
1566
|
-
if (!workspaceDir) return roots;
|
|
1567
|
-
const normalizedWorkspaceDir = path.resolve(workspaceDir);
|
|
1568
|
-
if (!roots.includes(normalizedWorkspaceDir)) roots.push(normalizedWorkspaceDir);
|
|
1569
|
-
return roots;
|
|
1570
|
-
}
|
|
1571
|
-
function resolveLocalMediaPath(source) {
|
|
1572
|
-
const trimmed = source.trim();
|
|
1573
|
-
if (!trimmed || isPassThroughRemoteMediaSource(trimmed) || DATA_URL_RE.test(trimmed)) return;
|
|
1574
|
-
if (trimmed.startsWith("file://")) try {
|
|
1575
|
-
return safeFileURLToPath(trimmed);
|
|
1576
|
-
} catch {
|
|
1577
|
-
return;
|
|
1578
|
-
}
|
|
1579
|
-
if (trimmed.startsWith("~")) return resolveUserPath(trimmed);
|
|
1580
|
-
if (path.isAbsolute(trimmed) || WINDOWS_DRIVE_RE.test(trimmed)) return path.resolve(trimmed);
|
|
1581
|
-
}
|
|
1582
|
-
function appendLocalMediaParentRoots(roots, mediaSources) {
|
|
1583
|
-
const appended = Array.from(new Set(roots.map((root) => path.resolve(root))));
|
|
1584
|
-
for (const source of mediaSources ?? []) {
|
|
1585
|
-
const localPath = resolveLocalMediaPath(source);
|
|
1586
|
-
if (!localPath) continue;
|
|
1587
|
-
const parentDir = path.dirname(localPath);
|
|
1588
|
-
if (parentDir === path.parse(parentDir).root) continue;
|
|
1589
|
-
const normalizedParent = path.resolve(parentDir);
|
|
1590
|
-
if (!appended.includes(normalizedParent)) appended.push(normalizedParent);
|
|
1591
|
-
}
|
|
1592
|
-
return appended;
|
|
1593
|
-
}
|
|
1594
|
-
function getAgentScopedMediaLocalRootsForSources(params) {
|
|
1595
|
-
const roots = getAgentScopedMediaLocalRoots(params.cfg, params.agentId);
|
|
1596
|
-
if (resolveEffectiveToolFsWorkspaceOnly({
|
|
1597
|
-
cfg: params.cfg,
|
|
1598
|
-
agentId: params.agentId
|
|
1599
|
-
})) return roots;
|
|
1600
|
-
if (!resolveEffectiveToolFsRootExpansionAllowed({
|
|
1601
|
-
cfg: params.cfg,
|
|
1602
|
-
agentId: params.agentId
|
|
1603
|
-
})) return roots;
|
|
1604
|
-
return appendLocalMediaParentRoots(roots, params.mediaSources);
|
|
1605
|
-
}
|
|
1606
|
-
//#endregion
|
|
1607
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/read-capability-B_d5F-j4.js
|
|
1608
|
-
function resolvePathFromInput(filePath, cwd) {
|
|
1609
|
-
return path.normalize(resolveSandboxInputPath(filePath, cwd));
|
|
1610
|
-
}
|
|
1611
|
-
function normalizeWorkspaceDir(workspaceDir) {
|
|
1612
|
-
const trimmed = workspaceDir?.trim();
|
|
1613
|
-
if (!trimmed) return null;
|
|
1614
|
-
const expanded = trimmed.startsWith("~") ? resolveUserPath(trimmed) : trimmed;
|
|
1615
|
-
const resolved = path.resolve(expanded);
|
|
1616
|
-
if (resolved === path.parse(resolved).root) return null;
|
|
1617
|
-
return resolved;
|
|
1618
|
-
}
|
|
1619
|
-
function resolveWorkspaceRoot(workspaceDir) {
|
|
1620
|
-
return normalizeWorkspaceDir(workspaceDir) ?? process.cwd();
|
|
1621
|
-
}
|
|
1622
|
-
function collectUniqueStrings(values) {
|
|
1623
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1624
|
-
const resolved = [];
|
|
1625
|
-
for (const value of values) {
|
|
1626
|
-
const trimmed = value?.trim();
|
|
1627
|
-
if (!trimmed || seen.has(trimmed)) continue;
|
|
1628
|
-
seen.add(trimmed);
|
|
1629
|
-
resolved.push(trimmed);
|
|
1630
|
-
}
|
|
1631
|
-
return resolved;
|
|
1632
|
-
}
|
|
1633
|
-
function buildScopedGroupIdCandidates(groupId) {
|
|
1634
|
-
const raw = groupId?.trim();
|
|
1635
|
-
if (!raw) return [];
|
|
1636
|
-
const topicSenderMatch = raw.match(/^(.+):topic:([^:]+):sender:([^:]+)$/i);
|
|
1637
|
-
if (topicSenderMatch) {
|
|
1638
|
-
const [, chatId, topicId] = topicSenderMatch;
|
|
1639
|
-
return collectUniqueStrings([
|
|
1640
|
-
raw,
|
|
1641
|
-
`${chatId}:topic:${topicId}`,
|
|
1642
|
-
chatId
|
|
1643
|
-
]);
|
|
1644
|
-
}
|
|
1645
|
-
const topicMatch = raw.match(/^(.+):topic:([^:]+)$/i);
|
|
1646
|
-
if (topicMatch) {
|
|
1647
|
-
const [, chatId, topicId] = topicMatch;
|
|
1648
|
-
return collectUniqueStrings([`${chatId}:topic:${topicId}`, chatId]);
|
|
1649
|
-
}
|
|
1650
|
-
const senderMatch = raw.match(/^(.+):sender:([^:]+)$/i);
|
|
1651
|
-
if (senderMatch) {
|
|
1652
|
-
const [, chatId] = senderMatch;
|
|
1653
|
-
return collectUniqueStrings([raw, chatId]);
|
|
1654
|
-
}
|
|
1655
|
-
return [raw];
|
|
1656
|
-
}
|
|
1657
|
-
function resolveGroupContextFromSessionKey(sessionKey) {
|
|
1658
|
-
const raw = (sessionKey ?? "").trim();
|
|
1659
|
-
if (!raw) return {};
|
|
1660
|
-
const { baseSessionKey, threadId } = parseThreadSessionSuffix(raw);
|
|
1661
|
-
const conversationKey = threadId ? baseSessionKey : raw;
|
|
1662
|
-
const conversation = parseRawSessionConversationRef(conversationKey);
|
|
1663
|
-
if (conversation) {
|
|
1664
|
-
const resolvedConversation = /:(?:sender|thread|topic):/iu.test(conversation.rawId) ? resolveSessionConversation({
|
|
1665
|
-
channel: conversation.channel,
|
|
1666
|
-
kind: conversation.kind,
|
|
1667
|
-
rawId: conversation.rawId
|
|
1668
|
-
}) : null;
|
|
1669
|
-
return {
|
|
1670
|
-
channel: conversation.channel,
|
|
1671
|
-
groupIds: collectUniqueStrings([
|
|
1672
|
-
...buildScopedGroupIdCandidates(conversation.rawId),
|
|
1673
|
-
resolvedConversation?.id,
|
|
1674
|
-
resolvedConversation?.baseConversationId,
|
|
1675
|
-
...resolvedConversation?.parentConversationCandidates ?? []
|
|
1676
|
-
])
|
|
1677
|
-
};
|
|
1678
|
-
}
|
|
1679
|
-
const parts = (conversationKey ?? raw).split(":").filter(Boolean);
|
|
1680
|
-
let body = parts[0] === "agent" ? parts.slice(2) : parts;
|
|
1681
|
-
if (body[0] === "subagent") body = body.slice(1);
|
|
1682
|
-
if (body.length < 3) return {};
|
|
1683
|
-
const [channel, kind, ...rest] = body;
|
|
1684
|
-
if (kind !== "group" && kind !== "channel") return {};
|
|
1685
|
-
const groupId = rest.join(":").trim();
|
|
1686
|
-
if (!groupId) return {};
|
|
1687
|
-
return {
|
|
1688
|
-
channel: normalizeLowercaseStringOrEmpty(channel),
|
|
1689
|
-
groupIds: buildScopedGroupIdCandidates(groupId)
|
|
1690
|
-
};
|
|
1691
|
-
}
|
|
1692
|
-
function resolveGroupToolPolicy(params) {
|
|
1693
|
-
if (!params.config) return;
|
|
1694
|
-
const sessionContext = resolveGroupContextFromSessionKey(params.sessionKey);
|
|
1695
|
-
const spawnedContext = resolveGroupContextFromSessionKey(params.spawnedBy);
|
|
1696
|
-
const groupIds = collectUniqueStrings([
|
|
1697
|
-
...buildScopedGroupIdCandidates(params.groupId),
|
|
1698
|
-
...sessionContext.groupIds ?? [],
|
|
1699
|
-
...spawnedContext.groupIds ?? []
|
|
1700
|
-
]);
|
|
1701
|
-
if (groupIds.length === 0) return;
|
|
1702
|
-
const channel = normalizeMessageChannel(params.messageProvider ?? sessionContext.channel ?? spawnedContext.channel);
|
|
1703
|
-
if (!channel) return;
|
|
1704
|
-
let plugin;
|
|
1705
|
-
try {
|
|
1706
|
-
plugin = getLoadedChannelPlugin(channel);
|
|
1707
|
-
} catch {
|
|
1708
|
-
plugin = void 0;
|
|
1709
|
-
}
|
|
1710
|
-
for (const groupId of groupIds) {
|
|
1711
|
-
const toolsConfig = plugin?.groups?.resolveToolPolicy?.({
|
|
1712
|
-
cfg: params.config,
|
|
1713
|
-
groupId,
|
|
1714
|
-
groupChannel: params.groupChannel,
|
|
1715
|
-
groupSpace: params.groupSpace,
|
|
1716
|
-
accountId: params.accountId,
|
|
1717
|
-
senderId: params.senderId,
|
|
1718
|
-
senderName: params.senderName,
|
|
1719
|
-
senderUsername: params.senderUsername,
|
|
1720
|
-
senderE164: params.senderE164
|
|
1721
|
-
});
|
|
1722
|
-
const policy = pickSandboxToolPolicy(toolsConfig);
|
|
1723
|
-
if (policy) return policy;
|
|
1724
|
-
}
|
|
1725
|
-
return pickSandboxToolPolicy(resolveChannelGroupToolsPolicy({
|
|
1726
|
-
cfg: params.config,
|
|
1727
|
-
channel,
|
|
1728
|
-
groupId: groupIds[0],
|
|
1729
|
-
groupIdCandidates: groupIds.slice(1),
|
|
1730
|
-
accountId: params.accountId,
|
|
1731
|
-
senderId: params.senderId,
|
|
1732
|
-
senderName: params.senderName,
|
|
1733
|
-
senderUsername: params.senderUsername,
|
|
1734
|
-
senderE164: params.senderE164
|
|
1735
|
-
}));
|
|
1736
|
-
}
|
|
1737
|
-
function isAgentScopedHostMediaReadAllowed(params) {
|
|
1738
|
-
if (!resolveEffectiveToolFsRootExpansionAllowed({
|
|
1739
|
-
cfg: params.cfg,
|
|
1740
|
-
agentId: params.agentId
|
|
1741
|
-
})) return false;
|
|
1742
|
-
const groupPolicy = resolveGroupToolPolicy({
|
|
1743
|
-
config: params.cfg,
|
|
1744
|
-
sessionKey: params.sessionKey,
|
|
1745
|
-
messageProvider: params.messageProvider,
|
|
1746
|
-
groupId: params.groupId,
|
|
1747
|
-
groupChannel: params.groupChannel,
|
|
1748
|
-
groupSpace: params.groupSpace,
|
|
1749
|
-
accountId: params.accountId,
|
|
1750
|
-
senderId: normalizeOptionalString(params.requesterSenderId),
|
|
1751
|
-
senderName: normalizeOptionalString(params.requesterSenderName),
|
|
1752
|
-
senderUsername: normalizeOptionalString(params.requesterSenderUsername),
|
|
1753
|
-
senderE164: normalizeOptionalString(params.requesterSenderE164)
|
|
1754
|
-
});
|
|
1755
|
-
if (groupPolicy && !isToolAllowedByPolicies("read", [groupPolicy])) return false;
|
|
1756
|
-
return true;
|
|
1757
|
-
}
|
|
1758
|
-
function createAgentScopedHostMediaReadFile(params) {
|
|
1759
|
-
if (!isAgentScopedHostMediaReadAllowed(params)) return;
|
|
1760
|
-
const workspaceRoot = resolveWorkspaceRoot(params.workspaceDir ?? (params.agentId ? resolveAgentWorkspaceDir(params.cfg, params.agentId) : void 0));
|
|
1761
|
-
return async (filePath) => {
|
|
1762
|
-
return (await readLocalFileSafely({ filePath: resolvePathFromInput(filePath, workspaceRoot) })).buffer;
|
|
1763
|
-
};
|
|
1764
|
-
}
|
|
1765
|
-
function resolveAgentScopedOutboundMediaAccess(params) {
|
|
1766
|
-
const hostMediaReadAllowed = isAgentScopedHostMediaReadAllowed(params);
|
|
1767
|
-
const localRoots = params.mediaAccess?.localRoots ?? (hostMediaReadAllowed ? getAgentScopedMediaLocalRootsForSources({
|
|
1768
|
-
cfg: params.cfg,
|
|
1769
|
-
agentId: params.agentId,
|
|
1770
|
-
mediaSources: params.mediaSources
|
|
1771
|
-
}) : getAgentScopedMediaLocalRoots(params.cfg, params.agentId));
|
|
1772
|
-
const resolvedWorkspaceDir = params.workspaceDir ?? params.mediaAccess?.workspaceDir ?? (params.agentId ? resolveAgentWorkspaceDir(params.cfg, params.agentId) : void 0);
|
|
1773
|
-
const readFile = params.mediaAccess?.readFile ?? params.mediaReadFile ?? (hostMediaReadAllowed ? createAgentScopedHostMediaReadFile({
|
|
1774
|
-
cfg: params.cfg,
|
|
1775
|
-
agentId: params.agentId,
|
|
1776
|
-
workspaceDir: resolvedWorkspaceDir,
|
|
1777
|
-
sessionKey: params.sessionKey,
|
|
1778
|
-
messageProvider: params.messageProvider,
|
|
1779
|
-
groupId: params.groupId,
|
|
1780
|
-
groupChannel: params.groupChannel,
|
|
1781
|
-
groupSpace: params.groupSpace,
|
|
1782
|
-
accountId: params.accountId,
|
|
1783
|
-
requesterSenderId: params.requesterSenderId,
|
|
1784
|
-
requesterSenderName: params.requesterSenderName,
|
|
1785
|
-
requesterSenderUsername: params.requesterSenderUsername,
|
|
1786
|
-
requesterSenderE164: params.requesterSenderE164
|
|
1787
|
-
}) : void 0);
|
|
1788
|
-
return {
|
|
1789
|
-
...localRoots?.length ? { localRoots } : {},
|
|
1790
|
-
...readFile ? { readFile } : {},
|
|
1791
|
-
...resolvedWorkspaceDir ? { workspaceDir: resolvedWorkspaceDir } : {}
|
|
1792
|
-
};
|
|
1793
|
-
}
|
|
1794
|
-
//#endregion
|
|
1795
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/load-UwglZn5K.js
|
|
1796
|
-
function createChannelRegistryLoader(resolveValue) {
|
|
1797
|
-
const cache = /* @__PURE__ */ new Map();
|
|
1798
|
-
let lastRegistry = null;
|
|
1799
|
-
return async (id) => {
|
|
1800
|
-
const registry = getActivePluginChannelRegistry();
|
|
1801
|
-
if (registry !== lastRegistry) {
|
|
1802
|
-
cache.clear();
|
|
1803
|
-
lastRegistry = registry;
|
|
1804
|
-
}
|
|
1805
|
-
const cached = cache.get(id);
|
|
1806
|
-
if (cached) return cached;
|
|
1807
|
-
const pluginEntry = registry?.channels.find((entry) => entry.plugin.id === id);
|
|
1808
|
-
if (!pluginEntry) return;
|
|
1809
|
-
const resolved = resolveValue(pluginEntry);
|
|
1810
|
-
if (resolved) cache.set(id, resolved);
|
|
1811
|
-
return resolved;
|
|
1812
|
-
};
|
|
1813
|
-
}
|
|
1814
|
-
const loadOutboundAdapterFromRegistry = createChannelRegistryLoader((entry) => entry.plugin.outbound);
|
|
1815
|
-
async function loadChannelOutboundAdapter(id) {
|
|
1816
|
-
return loadOutboundAdapterFromRegistry(id);
|
|
1817
|
-
}
|
|
1818
|
-
//#endregion
|
|
1819
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/delivery-queue-Ds-NSzJi.js
|
|
1820
|
-
const QUEUE_DIRNAME = "delivery-queue";
|
|
1821
|
-
const FAILED_DIRNAME = "failed";
|
|
1822
|
-
function resolveQueueDir(stateDir) {
|
|
1823
|
-
const base = stateDir ?? resolveStateDir();
|
|
1824
|
-
return path.join(base, QUEUE_DIRNAME);
|
|
1825
|
-
}
|
|
1826
|
-
function resolveFailedDir(stateDir) {
|
|
1827
|
-
return path.join(resolveQueueDir(stateDir), FAILED_DIRNAME);
|
|
1828
|
-
}
|
|
1829
|
-
function resolveQueueEntryPaths(id, stateDir) {
|
|
1830
|
-
const queueDir = resolveQueueDir(stateDir);
|
|
1831
|
-
return {
|
|
1832
|
-
jsonPath: path.join(queueDir, `${id}.json`),
|
|
1833
|
-
deliveredPath: path.join(queueDir, `${id}.delivered`)
|
|
1834
|
-
};
|
|
1835
|
-
}
|
|
1836
|
-
function getErrnoCode$1(err) {
|
|
1837
|
-
return err && typeof err === "object" && "code" in err ? String(err.code) : null;
|
|
1838
|
-
}
|
|
1839
|
-
async function unlinkBestEffort(filePath) {
|
|
1840
|
-
try {
|
|
1841
|
-
await fs.promises.unlink(filePath);
|
|
1842
|
-
} catch {}
|
|
1843
|
-
}
|
|
1844
|
-
async function writeQueueEntry(filePath, entry) {
|
|
1845
|
-
const tmp = `${filePath}.${process.pid}.tmp`;
|
|
1846
|
-
await fs.promises.writeFile(tmp, JSON.stringify(entry, null, 2), {
|
|
1847
|
-
encoding: "utf-8",
|
|
1848
|
-
mode: 384
|
|
1849
|
-
});
|
|
1850
|
-
await fs.promises.rename(tmp, filePath);
|
|
1851
|
-
}
|
|
1852
|
-
async function readQueueEntry(filePath) {
|
|
1853
|
-
return JSON.parse(await fs.promises.readFile(filePath, "utf-8"));
|
|
1854
|
-
}
|
|
1855
|
-
/** Ensure the queue directory (and failed/ subdirectory) exist. */
|
|
1856
|
-
async function ensureQueueDir(stateDir) {
|
|
1857
|
-
const queueDir = resolveQueueDir(stateDir);
|
|
1858
|
-
await fs.promises.mkdir(queueDir, {
|
|
1859
|
-
recursive: true,
|
|
1860
|
-
mode: 448
|
|
1861
|
-
});
|
|
1862
|
-
await fs.promises.mkdir(resolveFailedDir(stateDir), {
|
|
1863
|
-
recursive: true,
|
|
1864
|
-
mode: 448
|
|
1865
|
-
});
|
|
1866
|
-
return queueDir;
|
|
1867
|
-
}
|
|
1868
|
-
/** Persist a delivery entry to disk before attempting send. Returns the entry ID. */
|
|
1869
|
-
async function enqueueDelivery(params, stateDir) {
|
|
1870
|
-
const queueDir = await ensureQueueDir(stateDir);
|
|
1871
|
-
const id = generateSecureUuid();
|
|
1872
|
-
await writeQueueEntry(path.join(queueDir, `${id}.json`), {
|
|
1873
|
-
id,
|
|
1874
|
-
enqueuedAt: Date.now(),
|
|
1875
|
-
channel: params.channel,
|
|
1876
|
-
to: params.to,
|
|
1877
|
-
accountId: params.accountId,
|
|
1878
|
-
payloads: params.payloads,
|
|
1879
|
-
threadId: params.threadId,
|
|
1880
|
-
replyToId: params.replyToId,
|
|
1881
|
-
bestEffort: params.bestEffort,
|
|
1882
|
-
gifPlayback: params.gifPlayback,
|
|
1883
|
-
forceDocument: params.forceDocument,
|
|
1884
|
-
silent: params.silent,
|
|
1885
|
-
mirror: params.mirror,
|
|
1886
|
-
session: params.session,
|
|
1887
|
-
gatewayClientScopes: params.gatewayClientScopes,
|
|
1888
|
-
retryCount: 0
|
|
1889
|
-
});
|
|
1890
|
-
return id;
|
|
1891
|
-
}
|
|
1892
|
-
/** Remove a successfully delivered entry from the queue.
|
|
1893
|
-
*
|
|
1894
|
-
* Uses a two-phase approach so that a crash between delivery and cleanup
|
|
1895
|
-
* does not cause the message to be replayed on the next recovery scan:
|
|
1896
|
-
* Phase 1: atomic rename {id}.json → {id}.delivered
|
|
1897
|
-
* Phase 2: unlink the .delivered marker
|
|
1898
|
-
* If the process dies between phase 1 and phase 2 the marker is cleaned up
|
|
1899
|
-
* by {@link loadPendingDeliveries} on the next startup without re-sending.
|
|
1900
|
-
*/
|
|
1901
|
-
async function ackDelivery(id, stateDir) {
|
|
1902
|
-
const { jsonPath, deliveredPath } = resolveQueueEntryPaths(id, stateDir);
|
|
1903
|
-
try {
|
|
1904
|
-
await fs.promises.rename(jsonPath, deliveredPath);
|
|
1905
|
-
} catch (err) {
|
|
1906
|
-
if (getErrnoCode$1(err) === "ENOENT") {
|
|
1907
|
-
await unlinkBestEffort(deliveredPath);
|
|
1908
|
-
return;
|
|
1909
|
-
}
|
|
1910
|
-
throw err;
|
|
1911
|
-
}
|
|
1912
|
-
await unlinkBestEffort(deliveredPath);
|
|
1913
|
-
}
|
|
1914
|
-
/** Update a queue entry after a failed delivery attempt. */
|
|
1915
|
-
async function failDelivery(id, error, stateDir) {
|
|
1916
|
-
const filePath = path.join(resolveQueueDir(stateDir), `${id}.json`);
|
|
1917
|
-
const entry = await readQueueEntry(filePath);
|
|
1918
|
-
entry.retryCount += 1;
|
|
1919
|
-
entry.lastAttemptAt = Date.now();
|
|
1920
|
-
entry.lastError = error;
|
|
1921
|
-
await writeQueueEntry(filePath, entry);
|
|
1922
|
-
}
|
|
1923
|
-
const entriesInProgress = /* @__PURE__ */ new Set();
|
|
1924
|
-
function claimRecoveryEntry(entryId) {
|
|
1925
|
-
if (entriesInProgress.has(entryId)) return false;
|
|
1926
|
-
entriesInProgress.add(entryId);
|
|
1927
|
-
return true;
|
|
1928
|
-
}
|
|
1929
|
-
function releaseRecoveryEntry(entryId) {
|
|
1930
|
-
entriesInProgress.delete(entryId);
|
|
1931
|
-
}
|
|
1932
|
-
async function withActiveDeliveryClaim(entryId, fn) {
|
|
1933
|
-
if (!claimRecoveryEntry(entryId)) return { status: "claimed-by-other-owner" };
|
|
1934
|
-
try {
|
|
1935
|
-
return {
|
|
1936
|
-
status: "claimed",
|
|
1937
|
-
value: await fn()
|
|
1938
|
-
};
|
|
1939
|
-
} finally {
|
|
1940
|
-
releaseRecoveryEntry(entryId);
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1943
|
-
//#endregion
|
|
1944
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/deliver-C6YJ_kD0.js
|
|
1945
|
-
/**
|
|
1946
|
-
* Utility for checking AbortSignal state and throwing a standard AbortError.
|
|
1947
|
-
*/
|
|
1948
|
-
/**
|
|
1949
|
-
* Throws an AbortError if the given signal has been aborted.
|
|
1950
|
-
* Use at async checkpoints to support cancellation.
|
|
1951
|
-
*/
|
|
1952
|
-
function throwIfAborted(abortSignal) {
|
|
1953
|
-
if (abortSignal?.aborted) {
|
|
1954
|
-
const err = /* @__PURE__ */ new Error("Operation aborted");
|
|
1955
|
-
err.name = "AbortError";
|
|
1956
|
-
throw err;
|
|
1957
|
-
}
|
|
1958
|
-
}
|
|
1959
|
-
const log = createSubsystemLogger("outbound/deliver");
|
|
1960
|
-
let transcriptRuntimePromise;
|
|
1961
|
-
async function loadTranscriptRuntime() {
|
|
1962
|
-
transcriptRuntimePromise ??= import("./transcript.runtime-BqhvZZdl-BPy42vBP.mjs");
|
|
1963
|
-
return await transcriptRuntimePromise;
|
|
1964
|
-
}
|
|
1965
|
-
let channelBootstrapRuntimePromise;
|
|
1966
|
-
async function loadChannelBootstrapRuntime() {
|
|
1967
|
-
channelBootstrapRuntimePromise ??= import("./channel-bootstrap.runtime-BVclcGv1-DJv_Z-Kr.mjs");
|
|
1968
|
-
return await channelBootstrapRuntimePromise;
|
|
1969
|
-
}
|
|
1970
|
-
async function createChannelHandler(params) {
|
|
1971
|
-
let outbound = await loadChannelOutboundAdapter(params.channel);
|
|
1972
|
-
if (!outbound) {
|
|
1973
|
-
const { bootstrapOutboundChannelPlugin } = await loadChannelBootstrapRuntime();
|
|
1974
|
-
bootstrapOutboundChannelPlugin({
|
|
1975
|
-
channel: params.channel,
|
|
1976
|
-
cfg: params.cfg
|
|
1977
|
-
});
|
|
1978
|
-
outbound = await loadChannelOutboundAdapter(params.channel);
|
|
1979
|
-
}
|
|
1980
|
-
const handler = createPluginHandler({
|
|
1981
|
-
...params,
|
|
1982
|
-
outbound
|
|
1983
|
-
});
|
|
1984
|
-
if (!handler) throw new Error(`Outbound not configured for channel: ${params.channel}`);
|
|
1985
|
-
return handler;
|
|
1986
|
-
}
|
|
1987
|
-
function createPluginHandler(params) {
|
|
1988
|
-
const outbound = params.outbound;
|
|
1989
|
-
if (!outbound?.sendText) return null;
|
|
1990
|
-
const baseCtx = createChannelOutboundContextBase(params);
|
|
1991
|
-
const sendText = outbound.sendText;
|
|
1992
|
-
const sendMedia = outbound.sendMedia;
|
|
1993
|
-
const chunker = outbound.chunker ?? null;
|
|
1994
|
-
const chunkerMode = outbound.chunkerMode;
|
|
1995
|
-
const resolveCtx = (overrides) => ({
|
|
1996
|
-
...baseCtx,
|
|
1997
|
-
replyToId: overrides?.replyToId ?? baseCtx.replyToId,
|
|
1998
|
-
threadId: overrides?.threadId ?? baseCtx.threadId,
|
|
1999
|
-
audioAsVoice: overrides?.audioAsVoice
|
|
2000
|
-
});
|
|
2001
|
-
const buildTargetRef = (overrides) => ({
|
|
2002
|
-
channel: params.channel,
|
|
2003
|
-
to: params.to,
|
|
2004
|
-
accountId: params.accountId ?? void 0,
|
|
2005
|
-
threadId: overrides?.threadId ?? baseCtx.threadId
|
|
2006
|
-
});
|
|
2007
|
-
return {
|
|
2008
|
-
chunker,
|
|
2009
|
-
chunkerMode,
|
|
2010
|
-
textChunkLimit: outbound.textChunkLimit,
|
|
2011
|
-
supportsMedia: Boolean(sendMedia),
|
|
2012
|
-
sanitizeText: outbound.sanitizeText ? (payload) => outbound.sanitizeText({
|
|
2013
|
-
text: payload.text ?? "",
|
|
2014
|
-
payload
|
|
2015
|
-
}) : void 0,
|
|
2016
|
-
normalizePayload: outbound.normalizePayload ? (payload) => outbound.normalizePayload({ payload }) : void 0,
|
|
2017
|
-
renderPresentation: outbound.renderPresentation ? async (payload) => {
|
|
2018
|
-
const presentation = normalizeMessagePresentation(payload.presentation);
|
|
2019
|
-
if (!presentation) return payload;
|
|
2020
|
-
const ctx = {
|
|
2021
|
-
...resolveCtx({
|
|
2022
|
-
replyToId: payload.replyToId ?? baseCtx.replyToId,
|
|
2023
|
-
threadId: baseCtx.threadId,
|
|
2024
|
-
audioAsVoice: payload.audioAsVoice
|
|
2025
|
-
}),
|
|
2026
|
-
text: payload.text ?? "",
|
|
2027
|
-
mediaUrl: payload.mediaUrl,
|
|
2028
|
-
payload
|
|
2029
|
-
};
|
|
2030
|
-
return await outbound.renderPresentation({
|
|
2031
|
-
payload,
|
|
2032
|
-
presentation,
|
|
2033
|
-
ctx
|
|
2034
|
-
});
|
|
2035
|
-
} : void 0,
|
|
2036
|
-
pinDeliveredMessage: outbound.pinDeliveredMessage ? async ({ target, messageId, pin }) => outbound.pinDeliveredMessage({
|
|
2037
|
-
cfg: params.cfg,
|
|
2038
|
-
target,
|
|
2039
|
-
messageId,
|
|
2040
|
-
pin
|
|
2041
|
-
}) : void 0,
|
|
2042
|
-
shouldSkipPlainTextSanitization: outbound.shouldSkipPlainTextSanitization ? (payload) => outbound.shouldSkipPlainTextSanitization({ payload }) : void 0,
|
|
2043
|
-
resolveEffectiveTextChunkLimit: outbound.resolveEffectiveTextChunkLimit ? (fallbackLimit) => outbound.resolveEffectiveTextChunkLimit({
|
|
2044
|
-
cfg: params.cfg,
|
|
2045
|
-
accountId: params.accountId ?? void 0,
|
|
2046
|
-
fallbackLimit
|
|
2047
|
-
}) : void 0,
|
|
2048
|
-
sendPayload: outbound.sendPayload ? async (payload, overrides) => outbound.sendPayload({
|
|
2049
|
-
...resolveCtx(overrides),
|
|
2050
|
-
text: payload.text ?? "",
|
|
2051
|
-
mediaUrl: payload.mediaUrl,
|
|
2052
|
-
payload
|
|
2053
|
-
}) : void 0,
|
|
2054
|
-
sendFormattedText: outbound.sendFormattedText ? async (text, overrides) => outbound.sendFormattedText({
|
|
2055
|
-
...resolveCtx(overrides),
|
|
2056
|
-
text
|
|
2057
|
-
}) : void 0,
|
|
2058
|
-
sendFormattedMedia: outbound.sendFormattedMedia ? async (caption, mediaUrl, overrides) => outbound.sendFormattedMedia({
|
|
2059
|
-
...resolveCtx(overrides),
|
|
2060
|
-
text: caption,
|
|
2061
|
-
mediaUrl
|
|
2062
|
-
}) : void 0,
|
|
2063
|
-
sendText: async (text, overrides) => sendText({
|
|
2064
|
-
...resolveCtx(overrides),
|
|
2065
|
-
text
|
|
2066
|
-
}),
|
|
2067
|
-
buildTargetRef,
|
|
2068
|
-
sendMedia: async (caption, mediaUrl, overrides) => {
|
|
2069
|
-
if (sendMedia) return sendMedia({
|
|
2070
|
-
...resolveCtx(overrides),
|
|
2071
|
-
text: caption,
|
|
2072
|
-
mediaUrl
|
|
2073
|
-
});
|
|
2074
|
-
return sendText({
|
|
2075
|
-
...resolveCtx(overrides),
|
|
2076
|
-
text: caption
|
|
2077
|
-
});
|
|
2078
|
-
}
|
|
2079
|
-
};
|
|
2080
|
-
}
|
|
2081
|
-
function createChannelOutboundContextBase(params) {
|
|
2082
|
-
return {
|
|
2083
|
-
cfg: params.cfg,
|
|
2084
|
-
to: params.to,
|
|
2085
|
-
accountId: params.accountId,
|
|
2086
|
-
replyToId: params.replyToId,
|
|
2087
|
-
threadId: params.threadId,
|
|
2088
|
-
identity: params.identity,
|
|
2089
|
-
gifPlayback: params.gifPlayback,
|
|
2090
|
-
forceDocument: params.forceDocument,
|
|
2091
|
-
deps: params.deps,
|
|
2092
|
-
silent: params.silent,
|
|
2093
|
-
mediaAccess: params.mediaAccess,
|
|
2094
|
-
mediaLocalRoots: params.mediaAccess?.localRoots,
|
|
2095
|
-
mediaReadFile: params.mediaAccess?.readFile,
|
|
2096
|
-
gatewayClientScopes: params.gatewayClientScopes
|
|
2097
|
-
};
|
|
2098
|
-
}
|
|
2099
|
-
const isAbortError = (err) => err instanceof Error && err.name === "AbortError";
|
|
2100
|
-
function collectPayloadMediaSources(plan) {
|
|
2101
|
-
return plan.flatMap((entry) => entry.parts.mediaUrls);
|
|
2102
|
-
}
|
|
2103
|
-
function normalizeEmptyPayloadForDelivery(payload) {
|
|
2104
|
-
const text = typeof payload.text === "string" ? payload.text : "";
|
|
2105
|
-
if (!text.trim()) {
|
|
2106
|
-
if (!hasReplyPayloadContent({
|
|
2107
|
-
...payload,
|
|
2108
|
-
text
|
|
2109
|
-
})) return null;
|
|
2110
|
-
if (text) return {
|
|
2111
|
-
...payload,
|
|
2112
|
-
text: ""
|
|
2113
|
-
};
|
|
2114
|
-
}
|
|
2115
|
-
return payload;
|
|
2116
|
-
}
|
|
2117
|
-
function normalizePayloadsForChannelDelivery(plan, handler) {
|
|
2118
|
-
const normalizedPayloads = [];
|
|
2119
|
-
for (const payload of projectOutboundPayloadPlanForDelivery(plan)) {
|
|
2120
|
-
let sanitizedPayload = payload;
|
|
2121
|
-
if (handler.sanitizeText && sanitizedPayload.text) {
|
|
2122
|
-
if (!handler.shouldSkipPlainTextSanitization?.(sanitizedPayload)) sanitizedPayload = {
|
|
2123
|
-
...sanitizedPayload,
|
|
2124
|
-
text: handler.sanitizeText(sanitizedPayload)
|
|
2125
|
-
};
|
|
2126
|
-
}
|
|
2127
|
-
const normalizedPayload = handler.normalizePayload ? handler.normalizePayload(sanitizedPayload) : sanitizedPayload;
|
|
2128
|
-
const normalized = normalizedPayload ? normalizeEmptyPayloadForDelivery(normalizedPayload) : null;
|
|
2129
|
-
if (normalized) normalizedPayloads.push(normalized);
|
|
2130
|
-
}
|
|
2131
|
-
return normalizedPayloads;
|
|
2132
|
-
}
|
|
2133
|
-
function buildPayloadSummary(payload) {
|
|
2134
|
-
return summarizeOutboundPayloadForTransport(payload);
|
|
2135
|
-
}
|
|
2136
|
-
function normalizeDeliveryPin(payload) {
|
|
2137
|
-
const pin = payload.delivery?.pin;
|
|
2138
|
-
if (pin === true) return { enabled: true };
|
|
2139
|
-
if (!pin || typeof pin !== "object" || Array.isArray(pin)) return;
|
|
2140
|
-
if (!pin.enabled) return;
|
|
2141
|
-
const normalized = { enabled: true };
|
|
2142
|
-
if (pin.notify === true) normalized.notify = true;
|
|
2143
|
-
if (pin.required === true) normalized.required = true;
|
|
2144
|
-
return normalized;
|
|
2145
|
-
}
|
|
2146
|
-
async function maybePinDeliveredMessage(params) {
|
|
2147
|
-
const pin = normalizeDeliveryPin(params.payload);
|
|
2148
|
-
if (!pin) return;
|
|
2149
|
-
if (!params.messageId) {
|
|
2150
|
-
if (pin.required) throw new Error("Delivery pin requested, but no delivered message id was returned.");
|
|
2151
|
-
log.warn("Delivery pin requested, but no delivered message id was returned.", {
|
|
2152
|
-
channel: params.target.channel,
|
|
2153
|
-
to: params.target.to
|
|
2154
|
-
});
|
|
2155
|
-
return;
|
|
2156
|
-
}
|
|
2157
|
-
if (!params.handler.pinDeliveredMessage) {
|
|
2158
|
-
if (pin.required) throw new Error(`Delivery pin is not supported by channel: ${params.target.channel}`);
|
|
2159
|
-
log.warn("Delivery pin requested, but channel does not support pinning delivered messages.", {
|
|
2160
|
-
channel: params.target.channel,
|
|
2161
|
-
to: params.target.to
|
|
2162
|
-
});
|
|
2163
|
-
return;
|
|
2164
|
-
}
|
|
2165
|
-
try {
|
|
2166
|
-
await params.handler.pinDeliveredMessage({
|
|
2167
|
-
target: params.target,
|
|
2168
|
-
messageId: params.messageId,
|
|
2169
|
-
pin
|
|
2170
|
-
});
|
|
2171
|
-
} catch (err) {
|
|
2172
|
-
if (pin.required) throw err;
|
|
2173
|
-
log.warn("Delivery pin requested, but channel failed to pin delivered message.", {
|
|
2174
|
-
channel: params.target.channel,
|
|
2175
|
-
to: params.target.to,
|
|
2176
|
-
messageId: params.messageId,
|
|
2177
|
-
error: formatErrorMessage(err)
|
|
2178
|
-
});
|
|
2179
|
-
}
|
|
2180
|
-
}
|
|
2181
|
-
async function renderPresentationForDelivery(handler, payload) {
|
|
2182
|
-
const presentation = normalizeMessagePresentation(payload.presentation);
|
|
2183
|
-
if (!presentation) return payload;
|
|
2184
|
-
const rendered = handler.renderPresentation ? await handler.renderPresentation(payload) : null;
|
|
2185
|
-
if (rendered) {
|
|
2186
|
-
const { presentation: _presentation, ...withoutPresentation } = rendered;
|
|
2187
|
-
return withoutPresentation;
|
|
2188
|
-
}
|
|
2189
|
-
const { presentation: _presentation, ...withoutPresentation } = payload;
|
|
2190
|
-
return {
|
|
2191
|
-
...withoutPresentation,
|
|
2192
|
-
text: renderMessagePresentationFallbackText({
|
|
2193
|
-
text: payload.text,
|
|
2194
|
-
presentation
|
|
2195
|
-
})
|
|
2196
|
-
};
|
|
2197
|
-
}
|
|
2198
|
-
function createMessageSentEmitter(params) {
|
|
2199
|
-
const hasMessageSentHooks = params.hookRunner?.hasHooks("message_sent") ?? false;
|
|
2200
|
-
const canEmitInternalHook = Boolean(params.sessionKeyForInternalHooks);
|
|
2201
|
-
const emitMessageSent = (event) => {
|
|
2202
|
-
if (!hasMessageSentHooks && !canEmitInternalHook) return;
|
|
2203
|
-
const canonical = buildCanonicalSentMessageHookContext({
|
|
2204
|
-
to: params.to,
|
|
2205
|
-
content: event.content,
|
|
2206
|
-
success: event.success,
|
|
2207
|
-
error: event.error,
|
|
2208
|
-
channelId: params.channel,
|
|
2209
|
-
accountId: params.accountId ?? void 0,
|
|
2210
|
-
conversationId: params.to,
|
|
2211
|
-
messageId: event.messageId,
|
|
2212
|
-
isGroup: params.mirrorIsGroup,
|
|
2213
|
-
groupId: params.mirrorGroupId
|
|
2214
|
-
});
|
|
2215
|
-
if (hasMessageSentHooks) fireAndForgetHook(params.hookRunner.runMessageSent(toPluginMessageSentEvent(canonical), toPluginMessageContext(canonical)), "deliverOutboundPayloads: message_sent plugin hook failed", (message) => {
|
|
2216
|
-
log.warn(message);
|
|
2217
|
-
});
|
|
2218
|
-
if (!canEmitInternalHook) return;
|
|
2219
|
-
fireAndForgetHook(triggerInternalHook(createInternalHookEvent("message", "sent", params.sessionKeyForInternalHooks, toInternalMessageSentContext(canonical))), "deliverOutboundPayloads: message:sent internal hook failed", (message) => {
|
|
2220
|
-
log.warn(message);
|
|
2221
|
-
});
|
|
2222
|
-
};
|
|
2223
|
-
return {
|
|
2224
|
-
emitMessageSent,
|
|
2225
|
-
hasMessageSentHooks
|
|
2226
|
-
};
|
|
2227
|
-
}
|
|
2228
|
-
async function applyMessageSendingHook(params) {
|
|
2229
|
-
if (!params.enabled) return {
|
|
2230
|
-
cancelled: false,
|
|
2231
|
-
payload: params.payload,
|
|
2232
|
-
payloadSummary: params.payloadSummary
|
|
2233
|
-
};
|
|
2234
|
-
try {
|
|
2235
|
-
const sendingResult = await params.hookRunner.runMessageSending({
|
|
2236
|
-
to: params.to,
|
|
2237
|
-
content: params.payloadSummary.text,
|
|
2238
|
-
replyToId: params.payload.replyToId ?? params.replyToId ?? void 0,
|
|
2239
|
-
threadId: params.threadId ?? void 0,
|
|
2240
|
-
metadata: {
|
|
2241
|
-
channel: params.channel,
|
|
2242
|
-
accountId: params.accountId,
|
|
2243
|
-
mediaUrls: params.payloadSummary.mediaUrls
|
|
2244
|
-
}
|
|
2245
|
-
}, {
|
|
2246
|
-
channelId: params.channel,
|
|
2247
|
-
accountId: params.accountId ?? void 0,
|
|
2248
|
-
conversationId: params.to
|
|
2249
|
-
});
|
|
2250
|
-
if (sendingResult?.cancel) return {
|
|
2251
|
-
cancelled: true,
|
|
2252
|
-
payload: params.payload,
|
|
2253
|
-
payloadSummary: params.payloadSummary
|
|
2254
|
-
};
|
|
2255
|
-
if (sendingResult?.content == null) return {
|
|
2256
|
-
cancelled: false,
|
|
2257
|
-
payload: params.payload,
|
|
2258
|
-
payloadSummary: params.payloadSummary
|
|
2259
|
-
};
|
|
2260
|
-
return {
|
|
2261
|
-
cancelled: false,
|
|
2262
|
-
payload: {
|
|
2263
|
-
...params.payload,
|
|
2264
|
-
text: sendingResult.content
|
|
2265
|
-
},
|
|
2266
|
-
payloadSummary: {
|
|
2267
|
-
...params.payloadSummary,
|
|
2268
|
-
text: sendingResult.content
|
|
2269
|
-
}
|
|
2270
|
-
};
|
|
2271
|
-
} catch {
|
|
2272
|
-
return {
|
|
2273
|
-
cancelled: false,
|
|
2274
|
-
payload: params.payload,
|
|
2275
|
-
payloadSummary: params.payloadSummary
|
|
2276
|
-
};
|
|
2277
|
-
}
|
|
2278
|
-
}
|
|
2279
|
-
async function deliverOutboundPayloads(params) {
|
|
2280
|
-
const { channel, to, payloads } = params;
|
|
2281
|
-
const queueId = params.skipQueue ? null : await enqueueDelivery({
|
|
2282
|
-
channel,
|
|
2283
|
-
to,
|
|
2284
|
-
accountId: params.accountId,
|
|
2285
|
-
payloads,
|
|
2286
|
-
threadId: params.threadId,
|
|
2287
|
-
replyToId: params.replyToId,
|
|
2288
|
-
bestEffort: params.bestEffort,
|
|
2289
|
-
gifPlayback: params.gifPlayback,
|
|
2290
|
-
forceDocument: params.forceDocument,
|
|
2291
|
-
silent: params.silent,
|
|
2292
|
-
mirror: params.mirror,
|
|
2293
|
-
session: params.session,
|
|
2294
|
-
gatewayClientScopes: params.gatewayClientScopes
|
|
2295
|
-
}).catch(() => null);
|
|
2296
|
-
if (!queueId) return await deliverOutboundPayloadsWithQueueCleanup(params, null);
|
|
2297
|
-
const claimResult = await withActiveDeliveryClaim(queueId, () => deliverOutboundPayloadsWithQueueCleanup(params, queueId));
|
|
2298
|
-
if (claimResult.status === "claimed-by-other-owner") return [];
|
|
2299
|
-
return claimResult.value;
|
|
2300
|
-
}
|
|
2301
|
-
async function deliverOutboundPayloadsWithQueueCleanup(params, queueId) {
|
|
2302
|
-
let hadPartialFailure = false;
|
|
2303
|
-
const wrappedParams = params.onError ? {
|
|
2304
|
-
...params,
|
|
2305
|
-
onError: (err, payload) => {
|
|
2306
|
-
hadPartialFailure = true;
|
|
2307
|
-
params.onError(err, payload);
|
|
2308
|
-
}
|
|
2309
|
-
} : params;
|
|
2310
|
-
try {
|
|
2311
|
-
const results = await deliverOutboundPayloadsCore(wrappedParams);
|
|
2312
|
-
if (queueId) if (hadPartialFailure) await failDelivery(queueId, "partial delivery failure (bestEffort)").catch(() => {});
|
|
2313
|
-
else await ackDelivery(queueId).catch(() => {});
|
|
2314
|
-
return results;
|
|
2315
|
-
} catch (err) {
|
|
2316
|
-
if (queueId) if (isAbortError(err)) await ackDelivery(queueId).catch(() => {});
|
|
2317
|
-
else await failDelivery(queueId, formatErrorMessage(err)).catch(() => {});
|
|
2318
|
-
throw err;
|
|
2319
|
-
}
|
|
2320
|
-
}
|
|
2321
|
-
/** Core delivery logic (extracted for queue wrapper). */
|
|
2322
|
-
async function deliverOutboundPayloadsCore(params) {
|
|
2323
|
-
const { cfg, channel, to, payloads } = params;
|
|
2324
|
-
const outboundPayloadPlan = createOutboundPayloadPlan(payloads, {
|
|
2325
|
-
cfg,
|
|
2326
|
-
sessionKey: params.session?.policyKey ?? params.session?.key,
|
|
2327
|
-
surface: channel
|
|
2328
|
-
});
|
|
2329
|
-
const accountId = params.accountId;
|
|
2330
|
-
const deps = params.deps;
|
|
2331
|
-
const abortSignal = params.abortSignal;
|
|
2332
|
-
const mediaSources = collectPayloadMediaSources(outboundPayloadPlan);
|
|
2333
|
-
const mediaAccess = mediaSources.length > 0 ? resolveAgentScopedOutboundMediaAccess({
|
|
2334
|
-
cfg,
|
|
2335
|
-
agentId: params.session?.agentId ?? params.mirror?.agentId,
|
|
2336
|
-
mediaSources,
|
|
2337
|
-
sessionKey: params.session?.key,
|
|
2338
|
-
messageProvider: params.session?.key ? void 0 : channel,
|
|
2339
|
-
accountId: params.session?.requesterAccountId ?? accountId,
|
|
2340
|
-
requesterSenderId: params.session?.requesterSenderId,
|
|
2341
|
-
requesterSenderName: params.session?.requesterSenderName,
|
|
2342
|
-
requesterSenderUsername: params.session?.requesterSenderUsername,
|
|
2343
|
-
requesterSenderE164: params.session?.requesterSenderE164
|
|
2344
|
-
}) : {};
|
|
2345
|
-
const results = [];
|
|
2346
|
-
const handler = await createChannelHandler({
|
|
2347
|
-
cfg,
|
|
2348
|
-
channel,
|
|
2349
|
-
to,
|
|
2350
|
-
deps,
|
|
2351
|
-
accountId,
|
|
2352
|
-
replyToId: params.replyToId,
|
|
2353
|
-
threadId: params.threadId,
|
|
2354
|
-
identity: params.identity,
|
|
2355
|
-
gifPlayback: params.gifPlayback,
|
|
2356
|
-
forceDocument: params.forceDocument,
|
|
2357
|
-
silent: params.silent,
|
|
2358
|
-
mediaAccess,
|
|
2359
|
-
gatewayClientScopes: params.gatewayClientScopes
|
|
2360
|
-
});
|
|
2361
|
-
const configuredTextLimit = handler.chunker ? resolveTextChunkLimit(cfg, channel, accountId, { fallbackLimit: handler.textChunkLimit }) : void 0;
|
|
2362
|
-
const textLimit = handler.resolveEffectiveTextChunkLimit ? handler.resolveEffectiveTextChunkLimit(configuredTextLimit) : configuredTextLimit;
|
|
2363
|
-
const chunkMode = handler.chunker ? resolveChunkMode(cfg, channel, accountId) : "length";
|
|
2364
|
-
const sendTextChunks = async (text, overrides) => {
|
|
2365
|
-
throwIfAborted(abortSignal);
|
|
2366
|
-
if (!handler.chunker || textLimit === void 0) {
|
|
2367
|
-
results.push(await handler.sendText(text, overrides));
|
|
2368
|
-
return;
|
|
2369
|
-
}
|
|
2370
|
-
if (chunkMode === "newline") {
|
|
2371
|
-
const blockChunks = (handler.chunkerMode ?? "text") === "markdown" ? chunkMarkdownTextWithMode(text, textLimit, "newline") : chunkByParagraph(text, textLimit);
|
|
2372
|
-
if (!blockChunks.length && text) blockChunks.push(text);
|
|
2373
|
-
for (const blockChunk of blockChunks) {
|
|
2374
|
-
const chunks = handler.chunker(blockChunk, textLimit);
|
|
2375
|
-
if (!chunks.length && blockChunk) chunks.push(blockChunk);
|
|
2376
|
-
for (const chunk of chunks) {
|
|
2377
|
-
throwIfAborted(abortSignal);
|
|
2378
|
-
results.push(await handler.sendText(chunk, overrides));
|
|
2379
|
-
}
|
|
2380
|
-
}
|
|
2381
|
-
return;
|
|
2382
|
-
}
|
|
2383
|
-
const chunks = handler.chunker(text, textLimit);
|
|
2384
|
-
for (const chunk of chunks) {
|
|
2385
|
-
throwIfAborted(abortSignal);
|
|
2386
|
-
results.push(await handler.sendText(chunk, overrides));
|
|
2387
|
-
}
|
|
2388
|
-
};
|
|
2389
|
-
const normalizedPayloads = normalizePayloadsForChannelDelivery(outboundPayloadPlan, handler);
|
|
2390
|
-
const hookRunner = getGlobalHookRunner();
|
|
2391
|
-
const sessionKeyForInternalHooks = params.mirror?.sessionKey ?? params.session?.key;
|
|
2392
|
-
const mirrorIsGroup = params.mirror?.isGroup;
|
|
2393
|
-
const mirrorGroupId = params.mirror?.groupId;
|
|
2394
|
-
const { emitMessageSent, hasMessageSentHooks } = createMessageSentEmitter({
|
|
2395
|
-
hookRunner,
|
|
2396
|
-
channel,
|
|
2397
|
-
to,
|
|
2398
|
-
accountId,
|
|
2399
|
-
sessionKeyForInternalHooks,
|
|
2400
|
-
mirrorIsGroup,
|
|
2401
|
-
mirrorGroupId
|
|
2402
|
-
});
|
|
2403
|
-
const hasMessageSendingHooks = hookRunner?.hasHooks("message_sending") ?? false;
|
|
2404
|
-
if (hasMessageSentHooks && params.session?.agentId && !sessionKeyForInternalHooks) log.warn("deliverOutboundPayloads: session.agentId present without session key; internal message:sent hook will be skipped", {
|
|
2405
|
-
channel,
|
|
2406
|
-
to,
|
|
2407
|
-
agentId: params.session.agentId
|
|
2408
|
-
});
|
|
2409
|
-
for (const payload of normalizedPayloads) {
|
|
2410
|
-
let payloadSummary = buildPayloadSummary(payload);
|
|
2411
|
-
try {
|
|
2412
|
-
throwIfAborted(abortSignal);
|
|
2413
|
-
const hookResult = await applyMessageSendingHook({
|
|
2414
|
-
hookRunner,
|
|
2415
|
-
enabled: hasMessageSendingHooks,
|
|
2416
|
-
payload,
|
|
2417
|
-
payloadSummary,
|
|
2418
|
-
to,
|
|
2419
|
-
channel,
|
|
2420
|
-
accountId,
|
|
2421
|
-
replyToId: params.replyToId,
|
|
2422
|
-
threadId: params.threadId
|
|
2423
|
-
});
|
|
2424
|
-
if (hookResult.cancelled) continue;
|
|
2425
|
-
const effectivePayload = await renderPresentationForDelivery(handler, hookResult.payload);
|
|
2426
|
-
payloadSummary = buildPayloadSummary(effectivePayload);
|
|
2427
|
-
params.onPayload?.(payloadSummary);
|
|
2428
|
-
const sendOverrides = {
|
|
2429
|
-
replyToId: effectivePayload.replyToId ?? params.replyToId ?? void 0,
|
|
2430
|
-
threadId: params.threadId ?? void 0,
|
|
2431
|
-
audioAsVoice: effectivePayload.audioAsVoice === true ? true : void 0,
|
|
2432
|
-
forceDocument: params.forceDocument
|
|
2433
|
-
};
|
|
2434
|
-
const deliveryTarget = handler.buildTargetRef({ threadId: sendOverrides.threadId });
|
|
2435
|
-
if (handler.sendPayload && hasReplyPayloadContent({
|
|
2436
|
-
presentation: effectivePayload.presentation,
|
|
2437
|
-
interactive: effectivePayload.interactive,
|
|
2438
|
-
channelData: effectivePayload.channelData
|
|
2439
|
-
})) {
|
|
2440
|
-
const delivery = await handler.sendPayload(effectivePayload, sendOverrides);
|
|
2441
|
-
results.push(delivery);
|
|
2442
|
-
await maybePinDeliveredMessage({
|
|
2443
|
-
handler,
|
|
2444
|
-
payload: effectivePayload,
|
|
2445
|
-
target: deliveryTarget,
|
|
2446
|
-
messageId: delivery.messageId
|
|
2447
|
-
});
|
|
2448
|
-
emitMessageSent({
|
|
2449
|
-
success: true,
|
|
2450
|
-
content: payloadSummary.text,
|
|
2451
|
-
messageId: delivery.messageId
|
|
2452
|
-
});
|
|
2453
|
-
continue;
|
|
2454
|
-
}
|
|
2455
|
-
if (payloadSummary.mediaUrls.length === 0) {
|
|
2456
|
-
const beforeCount = results.length;
|
|
2457
|
-
if (handler.sendFormattedText) results.push(...await handler.sendFormattedText(payloadSummary.text, sendOverrides));
|
|
2458
|
-
else await sendTextChunks(payloadSummary.text, sendOverrides);
|
|
2459
|
-
const deliveredResults = results.slice(beforeCount);
|
|
2460
|
-
const messageId = results.at(-1)?.messageId;
|
|
2461
|
-
const pinMessageId = deliveredResults.find((entry) => entry.messageId)?.messageId;
|
|
2462
|
-
await maybePinDeliveredMessage({
|
|
2463
|
-
handler,
|
|
2464
|
-
payload: effectivePayload,
|
|
2465
|
-
target: deliveryTarget,
|
|
2466
|
-
messageId: pinMessageId
|
|
2467
|
-
});
|
|
2468
|
-
emitMessageSent({
|
|
2469
|
-
success: results.length > beforeCount,
|
|
2470
|
-
content: payloadSummary.text,
|
|
2471
|
-
messageId
|
|
2472
|
-
});
|
|
2473
|
-
continue;
|
|
2474
|
-
}
|
|
2475
|
-
if (!handler.supportsMedia) {
|
|
2476
|
-
log.warn("Plugin outbound adapter does not implement sendMedia; media URLs will be dropped and text fallback will be used", {
|
|
2477
|
-
channel,
|
|
2478
|
-
to,
|
|
2479
|
-
mediaCount: payloadSummary.mediaUrls.length
|
|
2480
|
-
});
|
|
2481
|
-
const fallbackText = payloadSummary.text.trim();
|
|
2482
|
-
if (!fallbackText) throw new Error("Plugin outbound adapter does not implement sendMedia and no text fallback is available for media payload");
|
|
2483
|
-
const beforeCount = results.length;
|
|
2484
|
-
await sendTextChunks(fallbackText, sendOverrides);
|
|
2485
|
-
const deliveredResults = results.slice(beforeCount);
|
|
2486
|
-
const messageId = results.at(-1)?.messageId;
|
|
2487
|
-
const pinMessageId = deliveredResults.find((entry) => entry.messageId)?.messageId;
|
|
2488
|
-
await maybePinDeliveredMessage({
|
|
2489
|
-
handler,
|
|
2490
|
-
payload: effectivePayload,
|
|
2491
|
-
target: deliveryTarget,
|
|
2492
|
-
messageId: pinMessageId
|
|
2493
|
-
});
|
|
2494
|
-
emitMessageSent({
|
|
2495
|
-
success: results.length > beforeCount,
|
|
2496
|
-
content: payloadSummary.text,
|
|
2497
|
-
messageId
|
|
2498
|
-
});
|
|
2499
|
-
continue;
|
|
2500
|
-
}
|
|
2501
|
-
let firstMessageId;
|
|
2502
|
-
let lastMessageId;
|
|
2503
|
-
await sendMediaWithLeadingCaption({
|
|
2504
|
-
mediaUrls: payloadSummary.mediaUrls,
|
|
2505
|
-
caption: payloadSummary.text,
|
|
2506
|
-
send: async ({ mediaUrl, caption }) => {
|
|
2507
|
-
throwIfAborted(abortSignal);
|
|
2508
|
-
if (handler.sendFormattedMedia) {
|
|
2509
|
-
const delivery = await handler.sendFormattedMedia(caption ?? "", mediaUrl, sendOverrides);
|
|
2510
|
-
results.push(delivery);
|
|
2511
|
-
firstMessageId ??= delivery.messageId;
|
|
2512
|
-
lastMessageId = delivery.messageId;
|
|
2513
|
-
return;
|
|
2514
|
-
}
|
|
2515
|
-
const delivery = await handler.sendMedia(caption ?? "", mediaUrl, sendOverrides);
|
|
2516
|
-
results.push(delivery);
|
|
2517
|
-
firstMessageId ??= delivery.messageId;
|
|
2518
|
-
lastMessageId = delivery.messageId;
|
|
2519
|
-
}
|
|
2520
|
-
});
|
|
2521
|
-
await maybePinDeliveredMessage({
|
|
2522
|
-
handler,
|
|
2523
|
-
payload: effectivePayload,
|
|
2524
|
-
target: deliveryTarget,
|
|
2525
|
-
messageId: firstMessageId
|
|
2526
|
-
});
|
|
2527
|
-
emitMessageSent({
|
|
2528
|
-
success: true,
|
|
2529
|
-
content: payloadSummary.text,
|
|
2530
|
-
messageId: lastMessageId
|
|
2531
|
-
});
|
|
2532
|
-
} catch (err) {
|
|
2533
|
-
emitMessageSent({
|
|
2534
|
-
success: false,
|
|
2535
|
-
content: payloadSummary.text,
|
|
2536
|
-
error: formatErrorMessage(err)
|
|
2537
|
-
});
|
|
2538
|
-
if (!params.bestEffort) throw err;
|
|
2539
|
-
params.onError?.(err, payloadSummary);
|
|
2540
|
-
}
|
|
2541
|
-
}
|
|
2542
|
-
if (params.mirror && results.length > 0) {
|
|
2543
|
-
const mirrorText = resolveMirroredTranscriptText({
|
|
2544
|
-
text: params.mirror.text,
|
|
2545
|
-
mediaUrls: params.mirror.mediaUrls
|
|
2546
|
-
});
|
|
2547
|
-
if (mirrorText) {
|
|
2548
|
-
const { appendAssistantMessageToSessionTranscript } = await loadTranscriptRuntime();
|
|
2549
|
-
await appendAssistantMessageToSessionTranscript({
|
|
2550
|
-
agentId: params.mirror.agentId,
|
|
2551
|
-
sessionKey: params.mirror.sessionKey,
|
|
2552
|
-
text: mirrorText,
|
|
2553
|
-
idempotencyKey: params.mirror.idempotencyKey
|
|
2554
|
-
});
|
|
2555
|
-
}
|
|
2556
|
-
}
|
|
2557
|
-
return results;
|
|
2558
|
-
}
|
|
2559
|
-
//#endregion
|
|
2560
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/channel-resolution-Bpi0M4FM.js
|
|
2561
|
-
function normalizeDeliverableOutboundChannel(raw) {
|
|
2562
|
-
const normalized = normalizeMessageChannel(raw);
|
|
2563
|
-
if (!normalized || !isDeliverableMessageChannel(normalized)) return;
|
|
2564
|
-
return normalized;
|
|
2565
|
-
}
|
|
2566
|
-
function maybeBootstrapChannelPlugin(params) {
|
|
2567
|
-
bootstrapOutboundChannelPlugin(params);
|
|
2568
|
-
}
|
|
2569
|
-
function resolveDirectFromActiveRegistry(channel) {
|
|
2570
|
-
const activeRegistry = getActivePluginRegistry();
|
|
2571
|
-
if (!activeRegistry) return;
|
|
2572
|
-
for (const entry of activeRegistry.channels) {
|
|
2573
|
-
const plugin = entry?.plugin;
|
|
2574
|
-
if (plugin?.id === channel) return plugin;
|
|
2575
|
-
}
|
|
2576
|
-
}
|
|
2577
|
-
function resolveOutboundChannelPlugin(params) {
|
|
2578
|
-
const normalized = normalizeDeliverableOutboundChannel(params.channel);
|
|
2579
|
-
if (!normalized) return;
|
|
2580
|
-
const resolveLoaded = () => getLoadedChannelPlugin(normalized);
|
|
2581
|
-
const resolve = () => getChannelPlugin(normalized);
|
|
2582
|
-
const current = resolveLoaded();
|
|
2583
|
-
if (current) return current;
|
|
2584
|
-
const directCurrent = resolveDirectFromActiveRegistry(normalized);
|
|
2585
|
-
if (directCurrent) return directCurrent;
|
|
2586
|
-
maybeBootstrapChannelPlugin({
|
|
2587
|
-
channel: normalized,
|
|
2588
|
-
cfg: params.cfg
|
|
2589
|
-
});
|
|
2590
|
-
return resolveLoaded() ?? resolveDirectFromActiveRegistry(normalized) ?? resolve();
|
|
2591
|
-
}
|
|
2592
|
-
//#endregion
|
|
2593
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/channel-selection-uZ6StxpE.js
|
|
2594
|
-
const getMessageChannels = () => listDeliverableMessageChannels();
|
|
2595
|
-
function isKnownChannel(value) {
|
|
2596
|
-
return getMessageChannels().includes(value);
|
|
2597
|
-
}
|
|
2598
|
-
function resolveKnownChannel(value) {
|
|
2599
|
-
const normalized = normalizeMessageChannel(value);
|
|
2600
|
-
if (!normalized) return;
|
|
2601
|
-
if (!isDeliverableMessageChannel(normalized)) return;
|
|
2602
|
-
if (!isKnownChannel(normalized)) return;
|
|
2603
|
-
return normalized;
|
|
2604
|
-
}
|
|
2605
|
-
function resolveAvailableKnownChannel(params) {
|
|
2606
|
-
const normalized = resolveKnownChannel(params.value);
|
|
2607
|
-
if (!normalized) return;
|
|
2608
|
-
return resolveOutboundChannelPlugin({
|
|
2609
|
-
channel: normalized,
|
|
2610
|
-
cfg: params.cfg
|
|
2611
|
-
}) ? normalized : void 0;
|
|
2612
|
-
}
|
|
2613
|
-
function isAccountEnabled(account) {
|
|
2614
|
-
if (!account || typeof account !== "object") return true;
|
|
2615
|
-
return account.enabled !== false;
|
|
2616
|
-
}
|
|
2617
|
-
const loggedChannelSelectionErrors = /* @__PURE__ */ new Set();
|
|
2618
|
-
function logChannelSelectionError(params) {
|
|
2619
|
-
const message = formatErrorMessage(params.error);
|
|
2620
|
-
const key = `${params.pluginId}:${params.accountId}:${params.operation}:${message}`;
|
|
2621
|
-
if (loggedChannelSelectionErrors.has(key)) return;
|
|
2622
|
-
loggedChannelSelectionErrors.add(key);
|
|
2623
|
-
defaultRuntime.error?.(`[channel-selection] ${params.pluginId}(${params.accountId}) ${params.operation} failed: ${message}`);
|
|
2624
|
-
}
|
|
2625
|
-
async function isPluginConfigured(plugin, cfg) {
|
|
2626
|
-
const accountIds = plugin.config.listAccountIds(cfg);
|
|
2627
|
-
if (accountIds.length === 0) return false;
|
|
2628
|
-
for (const accountId of accountIds) {
|
|
2629
|
-
let account;
|
|
2630
|
-
try {
|
|
2631
|
-
account = plugin.config.resolveAccount(cfg, accountId);
|
|
2632
|
-
} catch (error) {
|
|
2633
|
-
logChannelSelectionError({
|
|
2634
|
-
pluginId: plugin.id,
|
|
2635
|
-
accountId,
|
|
2636
|
-
operation: "resolveAccount",
|
|
2637
|
-
error
|
|
2638
|
-
});
|
|
2639
|
-
continue;
|
|
2640
|
-
}
|
|
2641
|
-
if (!(plugin.config.isEnabled ? plugin.config.isEnabled(account, cfg) : isAccountEnabled(account))) continue;
|
|
2642
|
-
if (!plugin.config.isConfigured) return true;
|
|
2643
|
-
let configured = false;
|
|
2644
|
-
try {
|
|
2645
|
-
configured = await plugin.config.isConfigured(account, cfg);
|
|
2646
|
-
} catch (error) {
|
|
2647
|
-
logChannelSelectionError({
|
|
2648
|
-
pluginId: plugin.id,
|
|
2649
|
-
accountId,
|
|
2650
|
-
operation: "isConfigured",
|
|
2651
|
-
error
|
|
2652
|
-
});
|
|
2653
|
-
continue;
|
|
2654
|
-
}
|
|
2655
|
-
if (configured) return true;
|
|
2656
|
-
}
|
|
2657
|
-
return false;
|
|
2658
|
-
}
|
|
2659
|
-
async function listConfiguredMessageChannels(cfg) {
|
|
2660
|
-
const channels = [];
|
|
2661
|
-
for (const plugin of listChannelPlugins()) {
|
|
2662
|
-
if (!isKnownChannel(plugin.id)) continue;
|
|
2663
|
-
if (await isPluginConfigured(plugin, cfg)) channels.push(plugin.id);
|
|
2664
|
-
}
|
|
2665
|
-
return channels;
|
|
2666
|
-
}
|
|
2667
|
-
async function resolveMessageChannelSelection(params) {
|
|
2668
|
-
const normalized = normalizeMessageChannel(params.channel);
|
|
2669
|
-
if (normalized) {
|
|
2670
|
-
const availableExplicit = resolveAvailableKnownChannel({
|
|
2671
|
-
cfg: params.cfg,
|
|
2672
|
-
value: normalized
|
|
2673
|
-
});
|
|
2674
|
-
if (!availableExplicit) {
|
|
2675
|
-
const fallback = resolveAvailableKnownChannel({
|
|
2676
|
-
cfg: params.cfg,
|
|
2677
|
-
value: params.fallbackChannel
|
|
2678
|
-
});
|
|
2679
|
-
if (fallback) return {
|
|
2680
|
-
channel: fallback,
|
|
2681
|
-
configured: [],
|
|
2682
|
-
source: "tool-context-fallback"
|
|
2683
|
-
};
|
|
2684
|
-
if (!isKnownChannel(normalized)) throw new Error(`Unknown channel: ${normalized}`);
|
|
2685
|
-
throw new Error(`Channel is unavailable: ${normalized}`);
|
|
2686
|
-
}
|
|
2687
|
-
return {
|
|
2688
|
-
channel: availableExplicit,
|
|
2689
|
-
configured: [],
|
|
2690
|
-
source: "explicit"
|
|
2691
|
-
};
|
|
2692
|
-
}
|
|
2693
|
-
const fallback = resolveAvailableKnownChannel({
|
|
2694
|
-
cfg: params.cfg,
|
|
2695
|
-
value: params.fallbackChannel
|
|
2696
|
-
});
|
|
2697
|
-
if (fallback) return {
|
|
2698
|
-
channel: fallback,
|
|
2699
|
-
configured: [],
|
|
2700
|
-
source: "tool-context-fallback"
|
|
2701
|
-
};
|
|
2702
|
-
const configured = await listConfiguredMessageChannels(params.cfg);
|
|
2703
|
-
if (configured.length === 1) return {
|
|
2704
|
-
channel: configured[0],
|
|
2705
|
-
configured,
|
|
2706
|
-
source: "single-configured"
|
|
2707
|
-
};
|
|
2708
|
-
if (configured.length === 0) throw new Error("Channel is required (no configured channels detected).");
|
|
2709
|
-
throw new Error(`Channel is required when multiple channels are configured: ${configured.join(", ")}`);
|
|
2710
|
-
}
|
|
2711
|
-
//#endregion
|
|
2712
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/target-errors-DWCwFi1f.js
|
|
2713
|
-
function missingTargetMessage(provider, hint) {
|
|
2714
|
-
return `Delivering to ${provider} requires target${formatTargetHint(hint)}`;
|
|
2715
|
-
}
|
|
2716
|
-
function missingTargetError(provider, hint) {
|
|
2717
|
-
return new Error(missingTargetMessage(provider, hint));
|
|
2718
|
-
}
|
|
2719
|
-
function formatTargetHint(hint, withLabel = false) {
|
|
2720
|
-
const normalized = hint?.trim();
|
|
2721
|
-
if (!normalized) return "";
|
|
2722
|
-
return withLabel ? ` Hint: ${normalized}` : ` ${normalized}`;
|
|
2723
|
-
}
|
|
2724
|
-
//#endregion
|
|
2725
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/channel-config-helpers-DprVFCfq.js
|
|
2726
|
-
/** Coerce mixed allowlist config values into plain strings without trimming or deduping. */
|
|
2727
|
-
function mapAllowFromEntries(allowFrom) {
|
|
2728
|
-
return (allowFrom ?? []).map((entry) => String(entry));
|
|
2729
|
-
}
|
|
2730
|
-
//#endregion
|
|
2731
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/targets-session-CrpEdT9S.js
|
|
2732
|
-
function buildWebChatDeliveryError() {
|
|
2733
|
-
return /* @__PURE__ */ new Error(`Delivering to WebChat is not supported via \`${formatCliCommand("openclaw agent")}\`; use WhatsApp/Telegram or run with --deliver=false.`);
|
|
2734
|
-
}
|
|
2735
|
-
function resolveOutboundTargetWithPlugin(params) {
|
|
2736
|
-
if (params.target.channel === "webchat") return {
|
|
2737
|
-
ok: false,
|
|
2738
|
-
error: buildWebChatDeliveryError()
|
|
2739
|
-
};
|
|
2740
|
-
const plugin = params.plugin;
|
|
2741
|
-
if (!plugin) return params.onMissingPlugin?.();
|
|
2742
|
-
const allowFromRaw = params.target.allowFrom ?? (params.target.cfg && plugin.config.resolveAllowFrom ? plugin.config.resolveAllowFrom({
|
|
2743
|
-
cfg: params.target.cfg,
|
|
2744
|
-
accountId: params.target.accountId ?? void 0
|
|
2745
|
-
}) : void 0);
|
|
2746
|
-
const allowFrom = allowFromRaw ? mapAllowFromEntries(allowFromRaw) : void 0;
|
|
2747
|
-
const effectiveTo = params.target.to?.trim() || (params.target.cfg && plugin.config.resolveDefaultTo ? plugin.config.resolveDefaultTo({
|
|
2748
|
-
cfg: params.target.cfg,
|
|
2749
|
-
accountId: params.target.accountId ?? void 0
|
|
2750
|
-
}) : void 0);
|
|
2751
|
-
const resolveTarget = plugin.outbound?.resolveTarget;
|
|
2752
|
-
if (resolveTarget) return resolveTarget({
|
|
2753
|
-
cfg: params.target.cfg,
|
|
2754
|
-
to: effectiveTo,
|
|
2755
|
-
allowFrom,
|
|
2756
|
-
accountId: params.target.accountId ?? void 0,
|
|
2757
|
-
mode: params.target.mode ?? "explicit"
|
|
2758
|
-
});
|
|
2759
|
-
if (effectiveTo) return {
|
|
2760
|
-
ok: true,
|
|
2761
|
-
to: effectiveTo
|
|
2762
|
-
};
|
|
2763
|
-
const hint = plugin.messaging?.targetResolver?.hint;
|
|
2764
|
-
return {
|
|
2765
|
-
ok: false,
|
|
2766
|
-
error: missingTargetError(plugin.meta.label ?? params.target.channel, hint)
|
|
2767
|
-
};
|
|
2768
|
-
}
|
|
2769
|
-
//#endregion
|
|
2770
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/targets-DMtF6TU_.js
|
|
2771
|
-
function resolveOutboundTarget(params) {
|
|
2772
|
-
return resolveOutboundTargetWithPlugin({
|
|
2773
|
-
plugin: resolveOutboundChannelPlugin({
|
|
2774
|
-
channel: params.channel,
|
|
2775
|
-
cfg: params.cfg
|
|
2776
|
-
}),
|
|
2777
|
-
target: params,
|
|
2778
|
-
onMissingPlugin: () => params.channel === "webchat" ? void 0 : {
|
|
2779
|
-
ok: false,
|
|
2780
|
-
error: /* @__PURE__ */ new Error(`Unsupported channel: ${params.channel}`)
|
|
2781
|
-
}
|
|
2782
|
-
}) ?? {
|
|
2783
|
-
ok: false,
|
|
2784
|
-
error: /* @__PURE__ */ new Error(`Unsupported channel: ${params.channel}`)
|
|
2785
|
-
};
|
|
2786
|
-
}
|
|
2787
|
-
//#endregion
|
|
2788
|
-
//#region node_modules/.pnpm/openclaw@2026.4.22_@napi-rs+canvas@0.1.99/node_modules/openclaw/dist/message-ClDCyV3_.js
|
|
2789
|
-
let messageConfigRuntimePromise = null;
|
|
2790
|
-
let messageGatewayRuntimePromise = null;
|
|
2791
|
-
function loadMessageConfigRuntime() {
|
|
2792
|
-
messageConfigRuntimePromise ??= import("./message.config.runtime-K-k4XOyq-DZTmXomP.mjs");
|
|
2793
|
-
return messageConfigRuntimePromise;
|
|
2794
|
-
}
|
|
2795
|
-
function loadMessageGatewayRuntime() {
|
|
2796
|
-
messageGatewayRuntimePromise ??= import("./message.gateway.runtime-DqHOHRTQ-DH4ml0YF.mjs");
|
|
2797
|
-
return messageGatewayRuntimePromise;
|
|
2798
|
-
}
|
|
2799
|
-
async function resolveRequiredChannel(params) {
|
|
2800
|
-
return (await resolveMessageChannelSelection({
|
|
2801
|
-
cfg: params.cfg,
|
|
2802
|
-
channel: params.channel
|
|
2803
|
-
})).channel;
|
|
2804
|
-
}
|
|
2805
|
-
function resolveRequiredPlugin(channel, cfg) {
|
|
2806
|
-
const plugin = resolveOutboundChannelPlugin({
|
|
2807
|
-
channel,
|
|
2808
|
-
cfg
|
|
2809
|
-
});
|
|
2810
|
-
if (!plugin) throw new Error(`Unknown channel: ${channel}`);
|
|
2811
|
-
return plugin;
|
|
2812
|
-
}
|
|
2813
|
-
function resolveGatewayOptions(opts) {
|
|
2814
|
-
return {
|
|
2815
|
-
url: opts?.mode === GATEWAY_CLIENT_MODES.BACKEND || opts?.clientName === GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT ? void 0 : opts?.url,
|
|
2816
|
-
token: opts?.token,
|
|
2817
|
-
timeoutMs: typeof opts?.timeoutMs === "number" && Number.isFinite(opts.timeoutMs) ? Math.max(1, Math.floor(opts.timeoutMs)) : 1e4,
|
|
2818
|
-
clientName: opts?.clientName ?? GATEWAY_CLIENT_NAMES.CLI,
|
|
2819
|
-
clientDisplayName: opts?.clientDisplayName,
|
|
2820
|
-
mode: opts?.mode ?? GATEWAY_CLIENT_MODES.CLI
|
|
2821
|
-
};
|
|
2822
|
-
}
|
|
2823
|
-
async function callMessageGateway(params) {
|
|
2824
|
-
const { callGatewayLeastPrivilege } = await loadMessageGatewayRuntime();
|
|
2825
|
-
const gateway = resolveGatewayOptions(params.gateway);
|
|
2826
|
-
return await callGatewayLeastPrivilege({
|
|
2827
|
-
url: gateway.url,
|
|
2828
|
-
token: gateway.token,
|
|
2829
|
-
method: params.method,
|
|
2830
|
-
params: params.params,
|
|
2831
|
-
timeoutMs: gateway.timeoutMs,
|
|
2832
|
-
clientName: gateway.clientName,
|
|
2833
|
-
clientDisplayName: gateway.clientDisplayName,
|
|
2834
|
-
mode: gateway.mode
|
|
2835
|
-
});
|
|
2836
|
-
}
|
|
2837
|
-
async function resolveMessageConfig(cfg) {
|
|
2838
|
-
if (cfg) return cfg;
|
|
2839
|
-
const { loadConfig } = await loadMessageConfigRuntime();
|
|
2840
|
-
return loadConfig();
|
|
2841
|
-
}
|
|
2842
|
-
async function resolveGatewayIdempotencyKey(idempotencyKey) {
|
|
2843
|
-
if (idempotencyKey) return idempotencyKey;
|
|
2844
|
-
const { randomIdempotencyKey } = await loadMessageGatewayRuntime();
|
|
2845
|
-
return randomIdempotencyKey();
|
|
2846
|
-
}
|
|
2847
|
-
async function sendMessage(params) {
|
|
2848
|
-
const cfg = await resolveMessageConfig(params.cfg);
|
|
2849
|
-
const channel = await resolveRequiredChannel({
|
|
2850
|
-
cfg,
|
|
2851
|
-
channel: params.channel
|
|
2852
|
-
});
|
|
2853
|
-
const deliveryMode = resolveRequiredPlugin(channel, cfg).outbound?.deliveryMode ?? "direct";
|
|
2854
|
-
const outboundPlan = createOutboundPayloadPlan([{
|
|
2855
|
-
text: params.content,
|
|
2856
|
-
mediaUrl: params.mediaUrl,
|
|
2857
|
-
mediaUrls: params.mediaUrls
|
|
2858
|
-
}]);
|
|
2859
|
-
const normalizedPayloads = projectOutboundPayloadPlanForDelivery(outboundPlan);
|
|
2860
|
-
const mirrorProjection = projectOutboundPayloadPlanForMirror(outboundPlan);
|
|
2861
|
-
const mirrorText = mirrorProjection.text;
|
|
2862
|
-
const mirrorMediaUrls = mirrorProjection.mediaUrls;
|
|
2863
|
-
const primaryMediaUrl = mirrorMediaUrls[0] ?? params.mediaUrl ?? null;
|
|
2864
|
-
if (params.dryRun) return {
|
|
2865
|
-
channel,
|
|
2866
|
-
to: params.to,
|
|
2867
|
-
via: deliveryMode === "gateway" ? "gateway" : "direct",
|
|
2868
|
-
mediaUrl: primaryMediaUrl,
|
|
2869
|
-
mediaUrls: mirrorMediaUrls.length ? mirrorMediaUrls : void 0,
|
|
2870
|
-
dryRun: true
|
|
2871
|
-
};
|
|
2872
|
-
if (deliveryMode !== "gateway") {
|
|
2873
|
-
const outboundChannel = channel;
|
|
2874
|
-
const resolvedTarget = resolveOutboundTarget({
|
|
2875
|
-
channel: outboundChannel,
|
|
2876
|
-
to: params.to,
|
|
2877
|
-
cfg,
|
|
2878
|
-
accountId: params.accountId,
|
|
2879
|
-
mode: "explicit"
|
|
2880
|
-
});
|
|
2881
|
-
if (!resolvedTarget.ok) throw resolvedTarget.error;
|
|
2882
|
-
const outboundSession = buildOutboundSessionContext({
|
|
2883
|
-
cfg,
|
|
2884
|
-
agentId: params.agentId,
|
|
2885
|
-
sessionKey: params.requesterSessionKey ?? params.mirror?.sessionKey,
|
|
2886
|
-
requesterAccountId: params.requesterAccountId ?? params.accountId,
|
|
2887
|
-
requesterSenderId: params.requesterSenderId,
|
|
2888
|
-
requesterSenderName: params.requesterSenderName,
|
|
2889
|
-
requesterSenderUsername: params.requesterSenderUsername,
|
|
2890
|
-
requesterSenderE164: params.requesterSenderE164
|
|
2891
|
-
});
|
|
2892
|
-
const results = await deliverOutboundPayloads({
|
|
2893
|
-
cfg,
|
|
2894
|
-
channel: outboundChannel,
|
|
2895
|
-
to: resolvedTarget.to,
|
|
2896
|
-
session: outboundSession,
|
|
2897
|
-
accountId: params.accountId,
|
|
2898
|
-
payloads: normalizedPayloads,
|
|
2899
|
-
replyToId: params.replyToId,
|
|
2900
|
-
threadId: params.threadId,
|
|
2901
|
-
gifPlayback: params.gifPlayback,
|
|
2902
|
-
forceDocument: params.forceDocument,
|
|
2903
|
-
deps: params.deps,
|
|
2904
|
-
bestEffort: params.bestEffort,
|
|
2905
|
-
abortSignal: params.abortSignal,
|
|
2906
|
-
silent: params.silent,
|
|
2907
|
-
mirror: params.mirror ? {
|
|
2908
|
-
...params.mirror,
|
|
2909
|
-
text: mirrorText || params.content,
|
|
2910
|
-
mediaUrls: mirrorMediaUrls.length ? mirrorMediaUrls : void 0,
|
|
2911
|
-
idempotencyKey: params.mirror.idempotencyKey ?? params.idempotencyKey
|
|
2912
|
-
} : void 0
|
|
2913
|
-
});
|
|
2914
|
-
return {
|
|
2915
|
-
channel,
|
|
2916
|
-
to: params.to,
|
|
2917
|
-
via: "direct",
|
|
2918
|
-
mediaUrl: primaryMediaUrl,
|
|
2919
|
-
mediaUrls: mirrorMediaUrls.length ? mirrorMediaUrls : void 0,
|
|
2920
|
-
result: results.at(-1)
|
|
2921
|
-
};
|
|
2922
|
-
}
|
|
2923
|
-
const result = await callMessageGateway({
|
|
2924
|
-
gateway: params.gateway,
|
|
2925
|
-
method: "send",
|
|
2926
|
-
params: {
|
|
2927
|
-
to: params.to,
|
|
2928
|
-
message: params.content,
|
|
2929
|
-
mediaUrl: params.mediaUrl,
|
|
2930
|
-
mediaUrls: mirrorMediaUrls.length ? mirrorMediaUrls : params.mediaUrls,
|
|
2931
|
-
gifPlayback: params.gifPlayback,
|
|
2932
|
-
accountId: params.accountId,
|
|
2933
|
-
agentId: params.agentId,
|
|
2934
|
-
channel,
|
|
2935
|
-
replyToId: params.replyToId,
|
|
2936
|
-
sessionKey: params.mirror?.sessionKey,
|
|
2937
|
-
idempotencyKey: await resolveGatewayIdempotencyKey(params.idempotencyKey)
|
|
2938
|
-
}
|
|
2939
|
-
});
|
|
2940
|
-
return {
|
|
2941
|
-
channel,
|
|
2942
|
-
to: params.to,
|
|
2943
|
-
via: "gateway",
|
|
2944
|
-
mediaUrl: primaryMediaUrl,
|
|
2945
|
-
mediaUrls: mirrorMediaUrls.length ? mirrorMediaUrls : void 0,
|
|
2946
|
-
result
|
|
2947
|
-
};
|
|
2948
|
-
}
|
|
2949
|
-
//#endregion
|
|
2950
|
-
export { parseReplyDirectives as n, registerPendingSpawnedChildrenQuery as r, sendMessage as t };
|