@workclaw/openclaw-workchat 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +720 -233
- package/package.json +1 -1
- package/src/api/api.ts +74 -7
- package/src/api/session-guard.ts +84 -0
- package/src/api/types.ts +18 -3
- package/src/channel.ts +71 -7
- package/src/messaging/inbound.ts +56 -2
- package/src/messaging/process-message.ts +120 -3
- package/src/messaging/send-media.ts +201 -0
- package/src/messaging/send.ts +5 -0
- package/src/storage/seen-msgids.ts +79 -0
package/index.js
CHANGED
|
@@ -46,7 +46,8 @@ var init_types = __esm({
|
|
|
46
46
|
DEFAULT_WS_URL = "wss://workbrain.cn/backend-api/open-apis/connect";
|
|
47
47
|
WorkChatMsgType = {
|
|
48
48
|
Text: "1",
|
|
49
|
-
|
|
49
|
+
Image: "2",
|
|
50
|
+
Audio: "110"
|
|
50
51
|
};
|
|
51
52
|
RequestDefaults = {
|
|
52
53
|
TimeoutMs: 3e4
|
|
@@ -1605,14 +1606,14 @@ var require_util = __commonJS({
|
|
|
1605
1606
|
}
|
|
1606
1607
|
const port = url2.port != null ? url2.port : url2.protocol === "https:" ? 443 : 80;
|
|
1607
1608
|
let origin = url2.origin != null ? url2.origin : `${url2.protocol || ""}//${url2.hostname || ""}:${port}`;
|
|
1608
|
-
let
|
|
1609
|
+
let path8 = url2.path != null ? url2.path : `${url2.pathname || ""}${url2.search || ""}`;
|
|
1609
1610
|
if (origin[origin.length - 1] === "/") {
|
|
1610
1611
|
origin = origin.slice(0, origin.length - 1);
|
|
1611
1612
|
}
|
|
1612
|
-
if (
|
|
1613
|
-
|
|
1613
|
+
if (path8 && path8[0] !== "/") {
|
|
1614
|
+
path8 = `/${path8}`;
|
|
1614
1615
|
}
|
|
1615
|
-
return new URL(`${origin}${
|
|
1616
|
+
return new URL(`${origin}${path8}`);
|
|
1616
1617
|
}
|
|
1617
1618
|
if (!isHttpOrHttpsPrefixed(url2.origin || url2.protocol)) {
|
|
1618
1619
|
throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`.");
|
|
@@ -2433,9 +2434,9 @@ var require_diagnostics = __commonJS({
|
|
|
2433
2434
|
"undici:client:sendHeaders",
|
|
2434
2435
|
(evt) => {
|
|
2435
2436
|
const {
|
|
2436
|
-
request: { method, path:
|
|
2437
|
+
request: { method, path: path8, origin }
|
|
2437
2438
|
} = evt;
|
|
2438
|
-
debugLog("sending request to %s %s%s", method, origin,
|
|
2439
|
+
debugLog("sending request to %s %s%s", method, origin, path8);
|
|
2439
2440
|
}
|
|
2440
2441
|
);
|
|
2441
2442
|
}
|
|
@@ -2453,14 +2454,14 @@ var require_diagnostics = __commonJS({
|
|
|
2453
2454
|
"undici:request:headers",
|
|
2454
2455
|
(evt) => {
|
|
2455
2456
|
const {
|
|
2456
|
-
request: { method, path:
|
|
2457
|
+
request: { method, path: path8, origin },
|
|
2457
2458
|
response: { statusCode }
|
|
2458
2459
|
} = evt;
|
|
2459
2460
|
debugLog(
|
|
2460
2461
|
"received response to %s %s%s - HTTP %d",
|
|
2461
2462
|
method,
|
|
2462
2463
|
origin,
|
|
2463
|
-
|
|
2464
|
+
path8,
|
|
2464
2465
|
statusCode
|
|
2465
2466
|
);
|
|
2466
2467
|
}
|
|
@@ -2469,23 +2470,23 @@ var require_diagnostics = __commonJS({
|
|
|
2469
2470
|
"undici:request:trailers",
|
|
2470
2471
|
(evt) => {
|
|
2471
2472
|
const {
|
|
2472
|
-
request: { method, path:
|
|
2473
|
+
request: { method, path: path8, origin }
|
|
2473
2474
|
} = evt;
|
|
2474
|
-
debugLog("trailers received from %s %s%s", method, origin,
|
|
2475
|
+
debugLog("trailers received from %s %s%s", method, origin, path8);
|
|
2475
2476
|
}
|
|
2476
2477
|
);
|
|
2477
2478
|
diagnosticsChannel.subscribe(
|
|
2478
2479
|
"undici:request:error",
|
|
2479
2480
|
(evt) => {
|
|
2480
2481
|
const {
|
|
2481
|
-
request: { method, path:
|
|
2482
|
+
request: { method, path: path8, origin },
|
|
2482
2483
|
error: error62
|
|
2483
2484
|
} = evt;
|
|
2484
2485
|
debugLog(
|
|
2485
2486
|
"request to %s %s%s errored - %s",
|
|
2486
2487
|
method,
|
|
2487
2488
|
origin,
|
|
2488
|
-
|
|
2489
|
+
path8,
|
|
2489
2490
|
error62.message
|
|
2490
2491
|
);
|
|
2491
2492
|
}
|
|
@@ -2600,7 +2601,7 @@ var require_request = __commonJS({
|
|
|
2600
2601
|
var kHandler = Symbol("handler");
|
|
2601
2602
|
var Request = class {
|
|
2602
2603
|
constructor(origin, {
|
|
2603
|
-
path:
|
|
2604
|
+
path: path8,
|
|
2604
2605
|
method,
|
|
2605
2606
|
body,
|
|
2606
2607
|
headers,
|
|
@@ -2617,11 +2618,11 @@ var require_request = __commonJS({
|
|
|
2617
2618
|
maxRedirections,
|
|
2618
2619
|
typeOfService
|
|
2619
2620
|
}, handler) {
|
|
2620
|
-
if (typeof
|
|
2621
|
+
if (typeof path8 !== "string") {
|
|
2621
2622
|
throw new InvalidArgumentError("path must be a string");
|
|
2622
|
-
} else if (
|
|
2623
|
+
} else if (path8[0] !== "/" && !(path8.startsWith("http://") || path8.startsWith("https://")) && method !== "CONNECT") {
|
|
2623
2624
|
throw new InvalidArgumentError("path must be an absolute URL or start with a slash");
|
|
2624
|
-
} else if (invalidPathRegex.test(
|
|
2625
|
+
} else if (invalidPathRegex.test(path8)) {
|
|
2625
2626
|
throw new InvalidArgumentError("invalid request path");
|
|
2626
2627
|
}
|
|
2627
2628
|
if (typeof method !== "string") {
|
|
@@ -2696,7 +2697,7 @@ var require_request = __commonJS({
|
|
|
2696
2697
|
this.completed = false;
|
|
2697
2698
|
this.aborted = false;
|
|
2698
2699
|
this.upgrade = upgrade || null;
|
|
2699
|
-
this.path = query ? serializePathWithQuery(
|
|
2700
|
+
this.path = query ? serializePathWithQuery(path8, query) : path8;
|
|
2700
2701
|
this.origin = origin;
|
|
2701
2702
|
this.protocol = getProtocolFromUrlString(origin);
|
|
2702
2703
|
this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent;
|
|
@@ -6265,7 +6266,7 @@ var require_formdata = __commonJS({
|
|
|
6265
6266
|
var { kEnumerableProperty } = require_util();
|
|
6266
6267
|
var { webidl } = require_webidl();
|
|
6267
6268
|
var nodeUtil = __require("util");
|
|
6268
|
-
var
|
|
6269
|
+
var FormData2 = class _FormData {
|
|
6269
6270
|
#state = [];
|
|
6270
6271
|
constructor(form = void 0) {
|
|
6271
6272
|
webidl.util.markAsUncloneable(this);
|
|
@@ -6382,11 +6383,11 @@ var require_formdata = __commonJS({
|
|
|
6382
6383
|
formData.#state = newState;
|
|
6383
6384
|
}
|
|
6384
6385
|
};
|
|
6385
|
-
var { getFormDataState, setFormDataState } =
|
|
6386
|
-
Reflect.deleteProperty(
|
|
6387
|
-
Reflect.deleteProperty(
|
|
6388
|
-
iteratorMixin("FormData",
|
|
6389
|
-
Object.defineProperties(
|
|
6386
|
+
var { getFormDataState, setFormDataState } = FormData2;
|
|
6387
|
+
Reflect.deleteProperty(FormData2, "getFormDataState");
|
|
6388
|
+
Reflect.deleteProperty(FormData2, "setFormDataState");
|
|
6389
|
+
iteratorMixin("FormData", FormData2, getFormDataState, "name", "value");
|
|
6390
|
+
Object.defineProperties(FormData2.prototype, {
|
|
6390
6391
|
append: kEnumerableProperty,
|
|
6391
6392
|
delete: kEnumerableProperty,
|
|
6392
6393
|
get: kEnumerableProperty,
|
|
@@ -6414,8 +6415,8 @@ var require_formdata = __commonJS({
|
|
|
6414
6415
|
}
|
|
6415
6416
|
return { name, value };
|
|
6416
6417
|
}
|
|
6417
|
-
webidl.is.FormData = webidl.util.MakeTypeAssertion(
|
|
6418
|
-
module.exports = { FormData, makeEntry, setFormDataState };
|
|
6418
|
+
webidl.is.FormData = webidl.util.MakeTypeAssertion(FormData2);
|
|
6419
|
+
module.exports = { FormData: FormData2, makeEntry, setFormDataState };
|
|
6419
6420
|
}
|
|
6420
6421
|
});
|
|
6421
6422
|
|
|
@@ -6779,7 +6780,7 @@ var require_body = __commonJS({
|
|
|
6779
6780
|
fullyReadBody,
|
|
6780
6781
|
extractMimeType
|
|
6781
6782
|
} = require_util2();
|
|
6782
|
-
var { FormData, setFormDataState } = require_formdata();
|
|
6783
|
+
var { FormData: FormData2, setFormDataState } = require_formdata();
|
|
6783
6784
|
var { webidl } = require_webidl();
|
|
6784
6785
|
var assert2 = __require("assert");
|
|
6785
6786
|
var { isErrored, isDisturbed } = __require("stream");
|
|
@@ -6972,13 +6973,13 @@ Content-Type: ${value.type || "application/octet-stream"}\r
|
|
|
6972
6973
|
switch (mimeType.essence) {
|
|
6973
6974
|
case "multipart/form-data": {
|
|
6974
6975
|
const parsed = multipartFormDataParser(value, mimeType);
|
|
6975
|
-
const fd = new
|
|
6976
|
+
const fd = new FormData2();
|
|
6976
6977
|
setFormDataState(fd, parsed);
|
|
6977
6978
|
return fd;
|
|
6978
6979
|
}
|
|
6979
6980
|
case "application/x-www-form-urlencoded": {
|
|
6980
6981
|
const entries = new URLSearchParams(value.toString());
|
|
6981
|
-
const fd = new
|
|
6982
|
+
const fd = new FormData2();
|
|
6982
6983
|
for (const [name, value2] of entries) {
|
|
6983
6984
|
fd.append(name, value2);
|
|
6984
6985
|
}
|
|
@@ -7902,7 +7903,7 @@ var require_client_h1 = __commonJS({
|
|
|
7902
7903
|
return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT";
|
|
7903
7904
|
}
|
|
7904
7905
|
function writeH1(client, request) {
|
|
7905
|
-
const { method, path:
|
|
7906
|
+
const { method, path: path8, host, upgrade, blocking, reset } = request;
|
|
7906
7907
|
let { body, headers, contentLength } = request;
|
|
7907
7908
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH";
|
|
7908
7909
|
if (util.isFormDataLike(body)) {
|
|
@@ -7980,7 +7981,7 @@ var require_client_h1 = __commonJS({
|
|
|
7980
7981
|
if (socket.setTypeOfService) {
|
|
7981
7982
|
socket.setTypeOfService(request.typeOfService);
|
|
7982
7983
|
}
|
|
7983
|
-
let header = `${method} ${
|
|
7984
|
+
let header = `${method} ${path8} HTTP/1.1\r
|
|
7984
7985
|
`;
|
|
7985
7986
|
if (typeof host === "string") {
|
|
7986
7987
|
header += `host: ${host}\r
|
|
@@ -8659,7 +8660,7 @@ var require_client_h2 = __commonJS({
|
|
|
8659
8660
|
const headersTimeout = request.headersTimeout ?? client[kHeadersTimeout];
|
|
8660
8661
|
const bodyTimeout = request.bodyTimeout ?? client[kBodyTimeout];
|
|
8661
8662
|
const session = client[kHTTP2Session];
|
|
8662
|
-
const { method, path:
|
|
8663
|
+
const { method, path: path8, host, upgrade, expectContinue, signal, protocol, headers: reqHeaders } = request;
|
|
8663
8664
|
let { body } = request;
|
|
8664
8665
|
if (upgrade != null && upgrade !== "websocket") {
|
|
8665
8666
|
util.errorRequest(client, request, new InvalidArgumentError(`Custom upgrade "${upgrade}" not supported over HTTP/2`));
|
|
@@ -8728,7 +8729,7 @@ var require_client_h2 = __commonJS({
|
|
|
8728
8729
|
}
|
|
8729
8730
|
headers[HTTP2_HEADER_METHOD] = "CONNECT";
|
|
8730
8731
|
headers[HTTP2_HEADER_PROTOCOL] = "websocket";
|
|
8731
|
-
headers[HTTP2_HEADER_PATH] =
|
|
8732
|
+
headers[HTTP2_HEADER_PATH] = path8;
|
|
8732
8733
|
if (protocol === "ws:" || protocol === "wss:") {
|
|
8733
8734
|
headers[HTTP2_HEADER_SCHEME] = protocol === "ws:" ? "http" : "https";
|
|
8734
8735
|
} else {
|
|
@@ -8780,7 +8781,7 @@ var require_client_h2 = __commonJS({
|
|
|
8780
8781
|
stream.setTimeout(headersTimeout);
|
|
8781
8782
|
return true;
|
|
8782
8783
|
}
|
|
8783
|
-
headers[HTTP2_HEADER_PATH] =
|
|
8784
|
+
headers[HTTP2_HEADER_PATH] = path8;
|
|
8784
8785
|
headers[HTTP2_HEADER_SCHEME] = protocol === "http:" ? "http" : "https";
|
|
8785
8786
|
const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH";
|
|
8786
8787
|
if (body && typeof body.read === "function") {
|
|
@@ -10261,7 +10262,7 @@ var require_agent = __commonJS({
|
|
|
10261
10262
|
function defaultFactory(origin, opts) {
|
|
10262
10263
|
return opts && opts.connections === 1 ? new Client(origin, opts) : new Pool(origin, opts);
|
|
10263
10264
|
}
|
|
10264
|
-
var
|
|
10265
|
+
var Agent3 = class extends DispatcherBase {
|
|
10265
10266
|
constructor({ factory = defaultFactory, maxOrigins = Infinity, connect, ...options } = {}) {
|
|
10266
10267
|
if (typeof factory !== "function") {
|
|
10267
10268
|
throw new InvalidArgumentError("factory must be a function.");
|
|
@@ -10370,7 +10371,7 @@ var require_agent = __commonJS({
|
|
|
10370
10371
|
return allClientStats;
|
|
10371
10372
|
}
|
|
10372
10373
|
};
|
|
10373
|
-
module.exports =
|
|
10374
|
+
module.exports = Agent3;
|
|
10374
10375
|
}
|
|
10375
10376
|
});
|
|
10376
10377
|
|
|
@@ -11076,7 +11077,7 @@ var require_proxy_agent = __commonJS({
|
|
|
11076
11077
|
"node_modules/undici/lib/dispatcher/proxy-agent.js"(exports, module) {
|
|
11077
11078
|
"use strict";
|
|
11078
11079
|
var { kProxy, kClose, kDestroy, kDispatch } = require_symbols();
|
|
11079
|
-
var
|
|
11080
|
+
var Agent3 = require_agent();
|
|
11080
11081
|
var Pool = require_pool();
|
|
11081
11082
|
var DispatcherBase = require_dispatcher_base();
|
|
11082
11083
|
var { InvalidArgumentError, RequestAbortedError, SecureProxyConnectionError } = require_errors();
|
|
@@ -11132,10 +11133,10 @@ var require_proxy_agent = __commonJS({
|
|
|
11132
11133
|
};
|
|
11133
11134
|
const {
|
|
11134
11135
|
origin,
|
|
11135
|
-
path:
|
|
11136
|
+
path: path8 = "/",
|
|
11136
11137
|
headers = {}
|
|
11137
11138
|
} = opts;
|
|
11138
|
-
opts.path = origin +
|
|
11139
|
+
opts.path = origin + path8;
|
|
11139
11140
|
if (!("host" in headers) && !("Host" in headers)) {
|
|
11140
11141
|
const { host } = new URL(origin);
|
|
11141
11142
|
headers.host = host;
|
|
@@ -11207,7 +11208,7 @@ var require_proxy_agent = __commonJS({
|
|
|
11207
11208
|
} else {
|
|
11208
11209
|
this[kClient] = clientFactory(url2, { connect });
|
|
11209
11210
|
}
|
|
11210
|
-
this[kAgent] = new
|
|
11211
|
+
this[kAgent] = new Agent3({
|
|
11211
11212
|
...opts,
|
|
11212
11213
|
factory,
|
|
11213
11214
|
connect: async (opts2, callback) => {
|
|
@@ -11335,7 +11336,7 @@ var require_env_http_proxy_agent = __commonJS({
|
|
|
11335
11336
|
var DispatcherBase = require_dispatcher_base();
|
|
11336
11337
|
var { kClose, kDestroy, kClosed, kDestroyed, kDispatch, kNoProxyAgent, kHttpProxyAgent, kHttpsProxyAgent } = require_symbols();
|
|
11337
11338
|
var ProxyAgent = require_proxy_agent();
|
|
11338
|
-
var
|
|
11339
|
+
var Agent3 = require_agent();
|
|
11339
11340
|
var DEFAULT_PORTS = {
|
|
11340
11341
|
"http:": 80,
|
|
11341
11342
|
"https:": 443
|
|
@@ -11348,7 +11349,7 @@ var require_env_http_proxy_agent = __commonJS({
|
|
|
11348
11349
|
super();
|
|
11349
11350
|
this.#opts = opts;
|
|
11350
11351
|
const { httpProxy, httpsProxy, noProxy, ...agentOpts } = opts;
|
|
11351
|
-
this[kNoProxyAgent] = new
|
|
11352
|
+
this[kNoProxyAgent] = new Agent3(agentOpts);
|
|
11352
11353
|
const HTTP_PROXY = httpProxy ?? process.env.http_proxy ?? process.env.HTTP_PROXY;
|
|
11353
11354
|
if (HTTP_PROXY) {
|
|
11354
11355
|
this[kHttpProxyAgent] = new ProxyAgent({ ...agentOpts, uri: HTTP_PROXY });
|
|
@@ -13295,20 +13296,20 @@ var require_mock_utils = __commonJS({
|
|
|
13295
13296
|
}
|
|
13296
13297
|
return normalizedQp;
|
|
13297
13298
|
}
|
|
13298
|
-
function safeUrl(
|
|
13299
|
-
if (typeof
|
|
13300
|
-
return
|
|
13299
|
+
function safeUrl(path8) {
|
|
13300
|
+
if (typeof path8 !== "string") {
|
|
13301
|
+
return path8;
|
|
13301
13302
|
}
|
|
13302
|
-
const pathSegments =
|
|
13303
|
+
const pathSegments = path8.split("?", 3);
|
|
13303
13304
|
if (pathSegments.length !== 2) {
|
|
13304
|
-
return
|
|
13305
|
+
return path8;
|
|
13305
13306
|
}
|
|
13306
13307
|
const qp = new URLSearchParams(pathSegments.pop());
|
|
13307
13308
|
qp.sort();
|
|
13308
13309
|
return [...pathSegments, qp.toString()].join("?");
|
|
13309
13310
|
}
|
|
13310
|
-
function matchKey(mockDispatch2, { path:
|
|
13311
|
-
const pathMatch = matchValue(mockDispatch2.path,
|
|
13311
|
+
function matchKey(mockDispatch2, { path: path8, method, body, headers }) {
|
|
13312
|
+
const pathMatch = matchValue(mockDispatch2.path, path8);
|
|
13312
13313
|
const methodMatch = matchValue(mockDispatch2.method, method);
|
|
13313
13314
|
const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true;
|
|
13314
13315
|
const headersMatch = matchHeaders(mockDispatch2, headers);
|
|
@@ -13333,8 +13334,8 @@ var require_mock_utils = __commonJS({
|
|
|
13333
13334
|
const basePath = key.query ? serializePathWithQuery(key.path, key.query) : key.path;
|
|
13334
13335
|
const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath;
|
|
13335
13336
|
const resolvedPathWithoutTrailingSlash = removeTrailingSlash(resolvedPath);
|
|
13336
|
-
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path:
|
|
13337
|
-
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(
|
|
13337
|
+
let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path8, ignoreTrailingSlash }) => {
|
|
13338
|
+
return ignoreTrailingSlash ? matchValue(removeTrailingSlash(safeUrl(path8)), resolvedPathWithoutTrailingSlash) : matchValue(safeUrl(path8), resolvedPath);
|
|
13338
13339
|
});
|
|
13339
13340
|
if (matchedMockDispatches.length === 0) {
|
|
13340
13341
|
throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`);
|
|
@@ -13373,19 +13374,19 @@ var require_mock_utils = __commonJS({
|
|
|
13373
13374
|
mockDispatches.splice(index, 1);
|
|
13374
13375
|
}
|
|
13375
13376
|
}
|
|
13376
|
-
function removeTrailingSlash(
|
|
13377
|
-
while (
|
|
13378
|
-
|
|
13377
|
+
function removeTrailingSlash(path8) {
|
|
13378
|
+
while (path8.endsWith("/")) {
|
|
13379
|
+
path8 = path8.slice(0, -1);
|
|
13379
13380
|
}
|
|
13380
|
-
if (
|
|
13381
|
-
|
|
13381
|
+
if (path8.length === 0) {
|
|
13382
|
+
path8 = "/";
|
|
13382
13383
|
}
|
|
13383
|
-
return
|
|
13384
|
+
return path8;
|
|
13384
13385
|
}
|
|
13385
13386
|
function buildKey(opts) {
|
|
13386
|
-
const { path:
|
|
13387
|
+
const { path: path8, method, body, headers, query } = opts;
|
|
13387
13388
|
return {
|
|
13388
|
-
path:
|
|
13389
|
+
path: path8,
|
|
13389
13390
|
method,
|
|
13390
13391
|
body,
|
|
13391
13392
|
headers,
|
|
@@ -14075,10 +14076,10 @@ var require_pending_interceptors_formatter = __commonJS({
|
|
|
14075
14076
|
}
|
|
14076
14077
|
format(pendingInterceptors) {
|
|
14077
14078
|
const withPrettyHeaders = pendingInterceptors.map(
|
|
14078
|
-
({ method, path:
|
|
14079
|
+
({ method, path: path8, data: { statusCode }, persist, times, timesInvoked, origin }) => ({
|
|
14079
14080
|
Method: method,
|
|
14080
14081
|
Origin: origin,
|
|
14081
|
-
Path:
|
|
14082
|
+
Path: path8,
|
|
14082
14083
|
"Status code": statusCode,
|
|
14083
14084
|
Persistent: persist ? PERSISTENT : NOT_PERSISTENT,
|
|
14084
14085
|
Invocations: timesInvoked,
|
|
@@ -14097,7 +14098,7 @@ var require_mock_agent = __commonJS({
|
|
|
14097
14098
|
"node_modules/undici/lib/mock/mock-agent.js"(exports, module) {
|
|
14098
14099
|
"use strict";
|
|
14099
14100
|
var { kClients } = require_symbols();
|
|
14100
|
-
var
|
|
14101
|
+
var Agent3 = require_agent();
|
|
14101
14102
|
var {
|
|
14102
14103
|
kAgent,
|
|
14103
14104
|
kMockAgentSet,
|
|
@@ -14135,7 +14136,7 @@ var require_mock_agent = __commonJS({
|
|
|
14135
14136
|
if (opts?.agent && typeof opts.agent.dispatch !== "function") {
|
|
14136
14137
|
throw new InvalidArgumentError("Argument opts.agent must implement Agent");
|
|
14137
14138
|
}
|
|
14138
|
-
const agent = opts?.agent ? opts.agent : new
|
|
14139
|
+
const agent = opts?.agent ? opts.agent : new Agent3(opts);
|
|
14139
14140
|
this[kAgent] = agent;
|
|
14140
14141
|
this[kClients] = agent[kClients];
|
|
14141
14142
|
this[kOptions] = mockOptions;
|
|
@@ -14160,9 +14161,9 @@ var require_mock_agent = __commonJS({
|
|
|
14160
14161
|
const acceptNonStandardSearchParameters = this[kMockAgentAcceptsNonStandardSearchParameters];
|
|
14161
14162
|
const dispatchOpts = { ...opts };
|
|
14162
14163
|
if (acceptNonStandardSearchParameters && dispatchOpts.path) {
|
|
14163
|
-
const [
|
|
14164
|
+
const [path8, searchParams] = dispatchOpts.path.split("?");
|
|
14164
14165
|
const normalizedSearchParams = normalizeSearchParams(searchParams, acceptNonStandardSearchParameters);
|
|
14165
|
-
dispatchOpts.path = `${
|
|
14166
|
+
dispatchOpts.path = `${path8}?${normalizedSearchParams}`;
|
|
14166
14167
|
}
|
|
14167
14168
|
return this[kAgent].dispatch(dispatchOpts, handler);
|
|
14168
14169
|
}
|
|
@@ -14366,7 +14367,7 @@ var require_snapshot_utils = __commonJS({
|
|
|
14366
14367
|
var require_snapshot_recorder = __commonJS({
|
|
14367
14368
|
"node_modules/undici/lib/mock/snapshot-recorder.js"(exports, module) {
|
|
14368
14369
|
"use strict";
|
|
14369
|
-
var { writeFile, readFile, mkdir } = __require("fs/promises");
|
|
14370
|
+
var { writeFile: writeFile2, readFile, mkdir: mkdir2 } = __require("fs/promises");
|
|
14370
14371
|
var { dirname, resolve } = __require("path");
|
|
14371
14372
|
var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("timers");
|
|
14372
14373
|
var { InvalidArgumentError, UndiciError } = require_errors();
|
|
@@ -14563,12 +14564,12 @@ var require_snapshot_recorder = __commonJS({
|
|
|
14563
14564
|
* @return {Promise<void>} - Resolves when snapshots are loaded
|
|
14564
14565
|
*/
|
|
14565
14566
|
async loadSnapshots(filePath) {
|
|
14566
|
-
const
|
|
14567
|
-
if (!
|
|
14567
|
+
const path8 = filePath || this.#snapshotPath;
|
|
14568
|
+
if (!path8) {
|
|
14568
14569
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
14569
14570
|
}
|
|
14570
14571
|
try {
|
|
14571
|
-
const data = await readFile(resolve(
|
|
14572
|
+
const data = await readFile(resolve(path8), "utf8");
|
|
14572
14573
|
const parsed = JSON.parse(data);
|
|
14573
14574
|
if (Array.isArray(parsed)) {
|
|
14574
14575
|
this.#snapshots.clear();
|
|
@@ -14582,7 +14583,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
14582
14583
|
if (error62.code === "ENOENT") {
|
|
14583
14584
|
this.#snapshots.clear();
|
|
14584
14585
|
} else {
|
|
14585
|
-
throw new UndiciError(`Failed to load snapshots from ${
|
|
14586
|
+
throw new UndiciError(`Failed to load snapshots from ${path8}`, { cause: error62 });
|
|
14586
14587
|
}
|
|
14587
14588
|
}
|
|
14588
14589
|
}
|
|
@@ -14593,17 +14594,17 @@ var require_snapshot_recorder = __commonJS({
|
|
|
14593
14594
|
* @returns {Promise<void>} - Resolves when snapshots are saved
|
|
14594
14595
|
*/
|
|
14595
14596
|
async saveSnapshots(filePath) {
|
|
14596
|
-
const
|
|
14597
|
-
if (!
|
|
14597
|
+
const path8 = filePath || this.#snapshotPath;
|
|
14598
|
+
if (!path8) {
|
|
14598
14599
|
throw new InvalidArgumentError("Snapshot path is required");
|
|
14599
14600
|
}
|
|
14600
|
-
const resolvedPath = resolve(
|
|
14601
|
-
await
|
|
14601
|
+
const resolvedPath = resolve(path8);
|
|
14602
|
+
await mkdir2(dirname(resolvedPath), { recursive: true });
|
|
14602
14603
|
const data = Array.from(this.#snapshots.entries()).map(([hash2, snapshot]) => ({
|
|
14603
14604
|
hash: hash2,
|
|
14604
14605
|
snapshot
|
|
14605
14606
|
}));
|
|
14606
|
-
await
|
|
14607
|
+
await writeFile2(resolvedPath, JSON.stringify(data, null, 2), { flush: true });
|
|
14607
14608
|
}
|
|
14608
14609
|
/**
|
|
14609
14610
|
* Clears all recorded snapshots
|
|
@@ -14742,7 +14743,7 @@ var require_snapshot_recorder = __commonJS({
|
|
|
14742
14743
|
var require_snapshot_agent = __commonJS({
|
|
14743
14744
|
"node_modules/undici/lib/mock/snapshot-agent.js"(exports, module) {
|
|
14744
14745
|
"use strict";
|
|
14745
|
-
var
|
|
14746
|
+
var Agent3 = require_agent();
|
|
14746
14747
|
var MockAgent = require_mock_agent();
|
|
14747
14748
|
var { SnapshotRecorder } = require_snapshot_recorder();
|
|
14748
14749
|
var WrapHandler = require_wrap_handler();
|
|
@@ -14793,7 +14794,7 @@ var require_snapshot_agent = __commonJS({
|
|
|
14793
14794
|
});
|
|
14794
14795
|
this[kSnapshotLoaded] = false;
|
|
14795
14796
|
if (this[kSnapshotMode] === "record" || this[kSnapshotMode] === "update" || this[kSnapshotMode] === "playback" && opts.excludeUrls && opts.excludeUrls.length > 0) {
|
|
14796
|
-
this[kRealAgent] = new
|
|
14797
|
+
this[kRealAgent] = new Agent3(opts);
|
|
14797
14798
|
}
|
|
14798
14799
|
if ((this[kSnapshotMode] === "playback" || this[kSnapshotMode] === "update") && this[kSnapshotPath]) {
|
|
14799
14800
|
this.loadSnapshots().catch(() => {
|
|
@@ -15032,9 +15033,9 @@ var require_global2 = __commonJS({
|
|
|
15032
15033
|
var globalDispatcher = Symbol.for("undici.globalDispatcher.2");
|
|
15033
15034
|
var legacyGlobalDispatcher = Symbol.for("undici.globalDispatcher.1");
|
|
15034
15035
|
var { InvalidArgumentError } = require_errors();
|
|
15035
|
-
var
|
|
15036
|
+
var Agent3 = require_agent();
|
|
15036
15037
|
if (getGlobalDispatcher() === void 0) {
|
|
15037
|
-
setGlobalDispatcher(new
|
|
15038
|
+
setGlobalDispatcher(new Agent3());
|
|
15038
15039
|
}
|
|
15039
15040
|
function setGlobalDispatcher(agent) {
|
|
15040
15041
|
if (!agent || typeof agent.dispatch !== "function") {
|
|
@@ -15229,15 +15230,15 @@ var require_redirect_handler = __commonJS({
|
|
|
15229
15230
|
return;
|
|
15230
15231
|
}
|
|
15231
15232
|
const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin)));
|
|
15232
|
-
const
|
|
15233
|
-
const redirectUrlString = `${origin}${
|
|
15233
|
+
const path8 = search ? `${pathname}${search}` : pathname;
|
|
15234
|
+
const redirectUrlString = `${origin}${path8}`;
|
|
15234
15235
|
for (const historyUrl of this.history) {
|
|
15235
15236
|
if (historyUrl.toString() === redirectUrlString) {
|
|
15236
15237
|
throw new InvalidArgumentError(`Redirect loop detected. Cannot redirect to ${origin}. This typically happens when using a Client or Pool with cross-origin redirects. Use an Agent for cross-origin redirects.`);
|
|
15237
15238
|
}
|
|
15238
15239
|
}
|
|
15239
15240
|
this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin);
|
|
15240
|
-
this.opts.path =
|
|
15241
|
+
this.opts.path = path8;
|
|
15241
15242
|
this.opts.origin = origin;
|
|
15242
15243
|
this.opts.query = null;
|
|
15243
15244
|
}
|
|
@@ -16996,10 +16997,10 @@ var require_cache_handler = __commonJS({
|
|
|
16996
16997
|
}
|
|
16997
16998
|
return locationUrl.pathname + locationUrl.search;
|
|
16998
16999
|
}
|
|
16999
|
-
function deleteCachedUri(store, cacheKey,
|
|
17000
|
+
function deleteCachedUri(store, cacheKey, path8) {
|
|
17000
17001
|
deleteCachedValue(store, {
|
|
17001
17002
|
...cacheKey,
|
|
17002
|
-
path:
|
|
17003
|
+
path: path8
|
|
17003
17004
|
});
|
|
17004
17005
|
for (let i = 0; i < util.safeHTTPMethods.length; i++) {
|
|
17005
17006
|
const method = util.safeHTTPMethods[i];
|
|
@@ -17007,7 +17008,7 @@ var require_cache_handler = __commonJS({
|
|
|
17007
17008
|
deleteCachedValue(store, {
|
|
17008
17009
|
...cacheKey,
|
|
17009
17010
|
method,
|
|
17010
|
-
path:
|
|
17011
|
+
path: path8
|
|
17011
17012
|
});
|
|
17012
17013
|
}
|
|
17013
17014
|
}
|
|
@@ -17018,9 +17019,9 @@ var require_cache_handler = __commonJS({
|
|
|
17018
17019
|
}
|
|
17019
17020
|
const values = Array.isArray(headerValue) ? headerValue : [headerValue];
|
|
17020
17021
|
for (let i = 0; i < values.length; i++) {
|
|
17021
|
-
const
|
|
17022
|
-
if (
|
|
17023
|
-
deleteCachedUri(store, cacheKey,
|
|
17022
|
+
const path8 = getSameOriginPath(cacheKey, values[i]);
|
|
17023
|
+
if (path8 !== void 0) {
|
|
17024
|
+
deleteCachedUri(store, cacheKey, path8);
|
|
17024
17025
|
}
|
|
17025
17026
|
}
|
|
17026
17027
|
}
|
|
@@ -22167,11 +22168,11 @@ var require_fetch = __commonJS({
|
|
|
22167
22168
|
function dispatch({ body }) {
|
|
22168
22169
|
const url2 = requestCurrentURL(request);
|
|
22169
22170
|
const agent = fetchParams.controller.dispatcher;
|
|
22170
|
-
const
|
|
22171
|
+
const path8 = url2.pathname + url2.search;
|
|
22171
22172
|
const hasTrailingQuestionMark = url2.search.length === 0 && url2.href[url2.href.length - url2.hash.length - 1] === "?";
|
|
22172
22173
|
return new Promise((resolve, reject) => agent.dispatch(
|
|
22173
22174
|
{
|
|
22174
|
-
path: hasTrailingQuestionMark ? `${
|
|
22175
|
+
path: hasTrailingQuestionMark ? `${path8}?` : path8,
|
|
22175
22176
|
origin: url2.origin,
|
|
22176
22177
|
method: request.method,
|
|
22177
22178
|
body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body,
|
|
@@ -22721,8 +22722,8 @@ var require_cache3 = __commonJS({
|
|
|
22721
22722
|
* @returns {requestResponseList}
|
|
22722
22723
|
*/
|
|
22723
22724
|
#batchCacheOperations(operations) {
|
|
22724
|
-
const
|
|
22725
|
-
const backupCache = [...
|
|
22725
|
+
const cache2 = this.#relevantRequestResponseList;
|
|
22726
|
+
const backupCache = [...cache2];
|
|
22726
22727
|
const addedItems = [];
|
|
22727
22728
|
const resultList = [];
|
|
22728
22729
|
try {
|
|
@@ -22749,9 +22750,9 @@ var require_cache3 = __commonJS({
|
|
|
22749
22750
|
return [];
|
|
22750
22751
|
}
|
|
22751
22752
|
for (const requestResponse of requestResponses) {
|
|
22752
|
-
const idx =
|
|
22753
|
+
const idx = cache2.indexOf(requestResponse);
|
|
22753
22754
|
assert2(idx !== -1);
|
|
22754
|
-
|
|
22755
|
+
cache2.splice(idx, 1);
|
|
22755
22756
|
}
|
|
22756
22757
|
} else if (operation.type === "put") {
|
|
22757
22758
|
if (operation.response == null) {
|
|
@@ -22781,11 +22782,11 @@ var require_cache3 = __commonJS({
|
|
|
22781
22782
|
}
|
|
22782
22783
|
requestResponses = this.#queryCache(operation.request);
|
|
22783
22784
|
for (const requestResponse of requestResponses) {
|
|
22784
|
-
const idx =
|
|
22785
|
+
const idx = cache2.indexOf(requestResponse);
|
|
22785
22786
|
assert2(idx !== -1);
|
|
22786
|
-
|
|
22787
|
+
cache2.splice(idx, 1);
|
|
22787
22788
|
}
|
|
22788
|
-
|
|
22789
|
+
cache2.push([operation.request, operation.response]);
|
|
22789
22790
|
addedItems.push([operation.request, operation.response]);
|
|
22790
22791
|
}
|
|
22791
22792
|
resultList.push([operation.request, operation.response]);
|
|
@@ -22962,13 +22963,13 @@ var require_cachestorage = __commonJS({
|
|
|
22962
22963
|
if (options.cacheName != null) {
|
|
22963
22964
|
if (this.#caches.has(options.cacheName)) {
|
|
22964
22965
|
const cacheList = this.#caches.get(options.cacheName);
|
|
22965
|
-
const
|
|
22966
|
-
return await
|
|
22966
|
+
const cache2 = new Cache(kConstruct, cacheList);
|
|
22967
|
+
return await cache2.match(request, options);
|
|
22967
22968
|
}
|
|
22968
22969
|
} else {
|
|
22969
22970
|
for (const cacheList of this.#caches.values()) {
|
|
22970
|
-
const
|
|
22971
|
-
const response = await
|
|
22971
|
+
const cache2 = new Cache(kConstruct, cacheList);
|
|
22972
|
+
const response = await cache2.match(request, options);
|
|
22972
22973
|
if (response !== void 0) {
|
|
22973
22974
|
return response;
|
|
22974
22975
|
}
|
|
@@ -22998,12 +22999,12 @@ var require_cachestorage = __commonJS({
|
|
|
22998
22999
|
webidl.argumentLengthCheck(arguments, 1, prefix);
|
|
22999
23000
|
cacheName = webidl.converters.DOMString(cacheName, prefix, "cacheName");
|
|
23000
23001
|
if (this.#caches.has(cacheName)) {
|
|
23001
|
-
const
|
|
23002
|
-
return new Cache(kConstruct,
|
|
23002
|
+
const cache3 = this.#caches.get(cacheName);
|
|
23003
|
+
return new Cache(kConstruct, cache3);
|
|
23003
23004
|
}
|
|
23004
|
-
const
|
|
23005
|
-
this.#caches.set(cacheName,
|
|
23006
|
-
return new Cache(kConstruct,
|
|
23005
|
+
const cache2 = [];
|
|
23006
|
+
this.#caches.set(cacheName, cache2);
|
|
23007
|
+
return new Cache(kConstruct, cache2);
|
|
23007
23008
|
}
|
|
23008
23009
|
/**
|
|
23009
23010
|
* @see https://w3c.github.io/ServiceWorker/#cache-storage-delete
|
|
@@ -23118,9 +23119,9 @@ var require_util4 = __commonJS({
|
|
|
23118
23119
|
}
|
|
23119
23120
|
}
|
|
23120
23121
|
}
|
|
23121
|
-
function validateCookiePath(
|
|
23122
|
-
for (let i = 0; i <
|
|
23123
|
-
const code =
|
|
23122
|
+
function validateCookiePath(path8) {
|
|
23123
|
+
for (let i = 0; i < path8.length; ++i) {
|
|
23124
|
+
const code = path8.charCodeAt(i);
|
|
23124
23125
|
if (code < 32 || // exclude CTLs (0-31)
|
|
23125
23126
|
code > 126 || // exclude DEL and non-ascii
|
|
23126
23127
|
code === 59) {
|
|
@@ -26401,7 +26402,7 @@ var require_undici = __commonJS({
|
|
|
26401
26402
|
var Pool = require_pool();
|
|
26402
26403
|
var BalancedPool = require_balanced_pool();
|
|
26403
26404
|
var RoundRobinPool = require_round_robin_pool();
|
|
26404
|
-
var
|
|
26405
|
+
var Agent3 = require_agent();
|
|
26405
26406
|
var ProxyAgent = require_proxy_agent();
|
|
26406
26407
|
var Socks5ProxyAgent = require_socks5_proxy_agent();
|
|
26407
26408
|
var EnvHttpProxyAgent = require_env_http_proxy_agent();
|
|
@@ -26428,7 +26429,7 @@ var require_undici = __commonJS({
|
|
|
26428
26429
|
module.exports.Pool = Pool;
|
|
26429
26430
|
module.exports.BalancedPool = BalancedPool;
|
|
26430
26431
|
module.exports.RoundRobinPool = RoundRobinPool;
|
|
26431
|
-
module.exports.Agent =
|
|
26432
|
+
module.exports.Agent = Agent3;
|
|
26432
26433
|
module.exports.ProxyAgent = ProxyAgent;
|
|
26433
26434
|
module.exports.Socks5ProxyAgent = Socks5ProxyAgent;
|
|
26434
26435
|
module.exports.EnvHttpProxyAgent = EnvHttpProxyAgent;
|
|
@@ -26474,11 +26475,11 @@ var require_undici = __commonJS({
|
|
|
26474
26475
|
if (typeof opts.path !== "string") {
|
|
26475
26476
|
throw new InvalidArgumentError("invalid opts.path");
|
|
26476
26477
|
}
|
|
26477
|
-
let
|
|
26478
|
+
let path8 = opts.path;
|
|
26478
26479
|
if (!opts.path.startsWith("/")) {
|
|
26479
|
-
|
|
26480
|
+
path8 = `/${path8}`;
|
|
26480
26481
|
}
|
|
26481
|
-
url2 = new URL(util.parseOrigin(url2).origin +
|
|
26482
|
+
url2 = new URL(util.parseOrigin(url2).origin + path8);
|
|
26482
26483
|
} else {
|
|
26483
26484
|
if (!opts) {
|
|
26484
26485
|
opts = typeof url2 === "object" ? url2 : {};
|
|
@@ -26622,8 +26623,7 @@ var init_redact = __esm({
|
|
|
26622
26623
|
// src/api/api.ts
|
|
26623
26624
|
async function fetchJson(params) {
|
|
26624
26625
|
const { url: url2, init, timeoutMs, allowInsecureTls } = params;
|
|
26625
|
-
const
|
|
26626
|
-
const fetcher = allowInsecureTls ? import_undici.fetch : globalThis.fetch;
|
|
26626
|
+
const fetcher = globalThis.fetch;
|
|
26627
26627
|
const controller = new AbortController();
|
|
26628
26628
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
26629
26629
|
let response;
|
|
@@ -26631,8 +26631,7 @@ async function fetchJson(params) {
|
|
|
26631
26631
|
try {
|
|
26632
26632
|
response = await fetcher(url2, {
|
|
26633
26633
|
...init,
|
|
26634
|
-
signal: controller.signal
|
|
26635
|
-
...dispatcher ? { dispatcher } : {}
|
|
26634
|
+
signal: controller.signal
|
|
26636
26635
|
});
|
|
26637
26636
|
text = await response.text().catch(() => "");
|
|
26638
26637
|
} finally {
|
|
@@ -26774,6 +26773,42 @@ async function sendWorkChatReplyMessage(params) {
|
|
|
26774
26773
|
if (!data?.msgId) throw new Error("workchat: msgId missing in reply response");
|
|
26775
26774
|
return { msgId: String(data.msgId) };
|
|
26776
26775
|
}
|
|
26776
|
+
async function uploadWorkChatFile(params) {
|
|
26777
|
+
const { opts, filePath, userId } = params;
|
|
26778
|
+
const token = await getAccessToken(opts);
|
|
26779
|
+
const { readFile } = await import("fs/promises");
|
|
26780
|
+
const pathMod = await import("path");
|
|
26781
|
+
const content = await readFile(filePath);
|
|
26782
|
+
const fileName = pathMod.basename(filePath);
|
|
26783
|
+
const ext = pathMod.extname(fileName).replace(/^\./, "").toLowerCase();
|
|
26784
|
+
const mime = ext === "mp3" || ext === "m4a" ? "audio/mpeg" : ext === "wav" ? "audio/wav" : `image/${ext === "jpg" ? "jpeg" : ext || "png"}`;
|
|
26785
|
+
const form = new FormData();
|
|
26786
|
+
form.set("file", new Blob([new Uint8Array(content)], { type: mime }), fileName);
|
|
26787
|
+
const ownerUserId = userId !== void 0 && String(userId).trim() !== "" ? String(userId) : "0";
|
|
26788
|
+
form.set("userId", ownerUserId);
|
|
26789
|
+
const resp = await fetchJson({
|
|
26790
|
+
url: `${normalizeBaseUrl(opts.baseUrl)}/open-apis/v1/files/upload`,
|
|
26791
|
+
timeoutMs: opts.timeoutMs ?? RequestDefaults.TimeoutMs,
|
|
26792
|
+
allowInsecureTls: opts.allowInsecureTls,
|
|
26793
|
+
init: {
|
|
26794
|
+
method: "POST",
|
|
26795
|
+
headers: {
|
|
26796
|
+
Authorization: `Bearer ${token}`,
|
|
26797
|
+
"x-user-id": ownerUserId
|
|
26798
|
+
},
|
|
26799
|
+
body: form
|
|
26800
|
+
}
|
|
26801
|
+
});
|
|
26802
|
+
const data = unwrapEnvelope(resp);
|
|
26803
|
+
const url2 = typeof data?.url === "string" ? data.url.trim() : "";
|
|
26804
|
+
if (!url2) throw new Error("workchat: url missing in file upload response");
|
|
26805
|
+
return {
|
|
26806
|
+
url: url2,
|
|
26807
|
+
fileName: typeof data?.fileName === "string" ? data.fileName : void 0,
|
|
26808
|
+
suffix: typeof data?.suffix === "string" ? data.suffix : void 0,
|
|
26809
|
+
fileSize: typeof data?.fileSize === "number" ? data.fileSize : void 0
|
|
26810
|
+
};
|
|
26811
|
+
}
|
|
26777
26812
|
async function notifyAgentCreatedStatus(opts, agentId) {
|
|
26778
26813
|
try {
|
|
26779
26814
|
const token = await getAccessToken(opts);
|
|
@@ -26788,11 +26823,10 @@ async function notifyAgentCreatedStatus(opts, agentId) {
|
|
|
26788
26823
|
logger.error(`agent-created/status failed: ${String(err)}`);
|
|
26789
26824
|
}
|
|
26790
26825
|
}
|
|
26791
|
-
var
|
|
26826
|
+
var tokenCache;
|
|
26792
26827
|
var init_api = __esm({
|
|
26793
26828
|
"src/api/api.ts"() {
|
|
26794
26829
|
"use strict";
|
|
26795
|
-
import_undici = __toESM(require_undici(), 1);
|
|
26796
26830
|
init_types();
|
|
26797
26831
|
init_logger();
|
|
26798
26832
|
init_redact();
|
|
@@ -26853,7 +26887,17 @@ function parseWorkChatFrame(data) {
|
|
|
26853
26887
|
if (type === "CALLBACK" && String(envelope?.metadata?.topic || "").trim().toUpperCase() === "AGENT_MESSAGE") {
|
|
26854
26888
|
const payload = parseMaybeJson(envelope?.data) ?? {};
|
|
26855
26889
|
const message = payload?.message;
|
|
26856
|
-
const
|
|
26890
|
+
const messageType = typeof message === "object" && message !== null ? String(message.type ?? "").trim().toLowerCase() : "";
|
|
26891
|
+
const rawContent = typeof message === "string" ? message : typeof message?.content === "string" ? message.content : "";
|
|
26892
|
+
let mediaUrl;
|
|
26893
|
+
let text = rawContent;
|
|
26894
|
+
if (messageType === "image" || messageType === "audio") {
|
|
26895
|
+
mediaUrl = extractMediaUrl(rawContent) ?? firstFileUrl(payload);
|
|
26896
|
+
text = messageType === "image" ? "[\u7528\u6237\u53D1\u9001\u4E86\u4E00\u5F20\u56FE\u7247]" : "[\u7528\u6237\u53D1\u9001\u4E86\u4E00\u6761\u8BED\u97F3]";
|
|
26897
|
+
} else if (!text.trim()) {
|
|
26898
|
+
mediaUrl = firstFileUrl(payload);
|
|
26899
|
+
if (mediaUrl) text = "[\u7528\u6237\u53D1\u9001\u4E86\u4E00\u4E2A\u6587\u4EF6]";
|
|
26900
|
+
}
|
|
26857
26901
|
return {
|
|
26858
26902
|
type: "agent_message",
|
|
26859
26903
|
message: {
|
|
@@ -26861,12 +26905,26 @@ function parseWorkChatFrame(data) {
|
|
|
26861
26905
|
userId: String(payload?.userId ?? ""),
|
|
26862
26906
|
openConversationId: String(payload?.conversationId ?? ""),
|
|
26863
26907
|
messageId: String(payload?.msgId ?? ""),
|
|
26864
|
-
...payload?.agentId !== void 0 ? { agentId: String(payload.agentId) } : {}
|
|
26908
|
+
...payload?.agentId !== void 0 ? { agentId: String(payload.agentId) } : {},
|
|
26909
|
+
...mediaUrl ? { mediaUrl, mediaType: messageType || "file" } : {}
|
|
26865
26910
|
}
|
|
26866
26911
|
};
|
|
26867
26912
|
}
|
|
26868
26913
|
return { type: "ignored", ignoredKind: `${type}/${topicLower || "(no topic)"}` };
|
|
26869
26914
|
}
|
|
26915
|
+
function extractMediaUrl(content) {
|
|
26916
|
+
if (!content.trim()) return void 0;
|
|
26917
|
+
try {
|
|
26918
|
+
const parsed = JSON.parse(content);
|
|
26919
|
+
return typeof parsed?.url === "string" && parsed.url.trim() ? parsed.url.trim() : void 0;
|
|
26920
|
+
} catch {
|
|
26921
|
+
return void 0;
|
|
26922
|
+
}
|
|
26923
|
+
}
|
|
26924
|
+
function firstFileUrl(payload) {
|
|
26925
|
+
const url2 = Array.isArray(payload?.fileUrl) ? payload.fileUrl[0] : void 0;
|
|
26926
|
+
return typeof url2 === "string" && url2.trim() ? url2.trim() : void 0;
|
|
26927
|
+
}
|
|
26870
26928
|
function buildPongFrame(pongData) {
|
|
26871
26929
|
return JSON.stringify({
|
|
26872
26930
|
code: 200,
|
|
@@ -26880,8 +26938,10 @@ function generateMessageSid() {
|
|
|
26880
26938
|
}
|
|
26881
26939
|
function workChatMessageToMsgContext(message, accountId) {
|
|
26882
26940
|
const fromUserId = message.userId ?? "";
|
|
26941
|
+
const body = message.mediaUrl ? `${message.text ?? ""}
|
|
26942
|
+
[media] ${message.mediaUrl}` : message.text ?? "";
|
|
26883
26943
|
const ctx = {
|
|
26884
|
-
Body:
|
|
26944
|
+
Body: body,
|
|
26885
26945
|
From: fromUserId,
|
|
26886
26946
|
To: fromUserId,
|
|
26887
26947
|
AccountId: accountId,
|
|
@@ -26899,6 +26959,10 @@ function workChatMessageToMsgContext(message, accountId) {
|
|
|
26899
26959
|
if (message.agentId) {
|
|
26900
26960
|
ctx.AgentId = message.agentId;
|
|
26901
26961
|
}
|
|
26962
|
+
if (message.mediaUrl) {
|
|
26963
|
+
ctx.MediaUrl = message.mediaUrl;
|
|
26964
|
+
ctx.MediaType = message.mediaType ?? "file";
|
|
26965
|
+
}
|
|
26902
26966
|
return ctx;
|
|
26903
26967
|
}
|
|
26904
26968
|
var init_inbound = __esm({
|
|
@@ -27105,8 +27169,8 @@ function startBindingListener(sessionKey, opts, timeoutMs) {
|
|
|
27105
27169
|
clearWorkChatTokenCache(opts.appKey || "default");
|
|
27106
27170
|
const { endpoint, ticket } = await openConnection(opts);
|
|
27107
27171
|
const url2 = `${endpoint}?ticket=${encodeURIComponent(ticket)}`;
|
|
27108
|
-
const dispatcher = opts.allowInsecureTls ? new
|
|
27109
|
-
ws = new
|
|
27172
|
+
const dispatcher = opts.allowInsecureTls ? new import_undici.Agent({ connect: { rejectUnauthorized: false } }) : void 0;
|
|
27173
|
+
ws = new import_undici.WebSocket(url2, dispatcher ? { dispatcher } : void 0);
|
|
27110
27174
|
const entryNow = bindingListeners.get(sessionKey);
|
|
27111
27175
|
if (!entryNow || entryNow.done) {
|
|
27112
27176
|
try {
|
|
@@ -27232,12 +27296,12 @@ function completeWorkChatBinding(completion) {
|
|
|
27232
27296
|
);
|
|
27233
27297
|
return true;
|
|
27234
27298
|
}
|
|
27235
|
-
var
|
|
27299
|
+
var import_undici, BIND_CMD, BIND_TYPE, BIND_NAME, ACTIVE_BINDING_TTL_MS, activeBindings, pendingWaiters, bindingListeners;
|
|
27236
27300
|
var init_login_qr = __esm({
|
|
27237
27301
|
"src/auth/login-qr.ts"() {
|
|
27238
27302
|
"use strict";
|
|
27239
27303
|
init_logger();
|
|
27240
|
-
|
|
27304
|
+
import_undici = __toESM(require_undici(), 1);
|
|
27241
27305
|
init_api();
|
|
27242
27306
|
init_inbound();
|
|
27243
27307
|
init_inbound();
|
|
@@ -27252,9 +27316,74 @@ var init_login_qr = __esm({
|
|
|
27252
27316
|
}
|
|
27253
27317
|
});
|
|
27254
27318
|
|
|
27319
|
+
// src/api/session-guard.ts
|
|
27320
|
+
function pauseSession(accountId) {
|
|
27321
|
+
const until = Date.now() + SESSION_PAUSE_DURATION_MS;
|
|
27322
|
+
pauseUntilMap.set(accountId, until);
|
|
27323
|
+
logger.info(
|
|
27324
|
+
`session-guard: paused accountId=${accountId} until=${new Date(until).toISOString()} (${SESSION_PAUSE_DURATION_MS / 1e3}s)`
|
|
27325
|
+
);
|
|
27326
|
+
}
|
|
27327
|
+
function isSessionPaused(accountId) {
|
|
27328
|
+
const until = pauseUntilMap.get(accountId);
|
|
27329
|
+
if (until === void 0) return false;
|
|
27330
|
+
if (Date.now() >= until) {
|
|
27331
|
+
pauseUntilMap.delete(accountId);
|
|
27332
|
+
return false;
|
|
27333
|
+
}
|
|
27334
|
+
return true;
|
|
27335
|
+
}
|
|
27336
|
+
function getRemainingPauseMs(accountId) {
|
|
27337
|
+
const until = pauseUntilMap.get(accountId);
|
|
27338
|
+
if (until === void 0) return 0;
|
|
27339
|
+
const remaining = until - Date.now();
|
|
27340
|
+
if (remaining <= 0) {
|
|
27341
|
+
pauseUntilMap.delete(accountId);
|
|
27342
|
+
return 0;
|
|
27343
|
+
}
|
|
27344
|
+
return remaining;
|
|
27345
|
+
}
|
|
27346
|
+
function assertSessionActive(accountId) {
|
|
27347
|
+
if (isSessionPaused(accountId)) {
|
|
27348
|
+
const remainingMin = Math.ceil(getRemainingPauseMs(accountId) / 6e4);
|
|
27349
|
+
throw new Error(
|
|
27350
|
+
`session paused for accountId=${accountId}, ${remainingMin} min remaining \u2014 the WorkChat binding is invalid, re-scan the QR code to fix`
|
|
27351
|
+
);
|
|
27352
|
+
}
|
|
27353
|
+
}
|
|
27354
|
+
function isPermanentBindingError(errMsg) {
|
|
27355
|
+
return PERMANENT_ERROR_PATTERNS.some((p) => errMsg.includes(p));
|
|
27356
|
+
}
|
|
27357
|
+
function pauseOnPermanentError(accountId, errMsg) {
|
|
27358
|
+
if (!isPermanentBindingError(errMsg)) return false;
|
|
27359
|
+
if (!isSessionPaused(accountId)) {
|
|
27360
|
+
pauseSession(accountId);
|
|
27361
|
+
logger.warn(
|
|
27362
|
+
`session-guard: permanent binding error, pausing accountId=${accountId} err="${errMsg.slice(0, 120)}" \u2014 re-scan required`
|
|
27363
|
+
);
|
|
27364
|
+
}
|
|
27365
|
+
return true;
|
|
27366
|
+
}
|
|
27367
|
+
var SESSION_PAUSE_DURATION_MS, PERMANENT_ERROR_PATTERNS, pauseUntilMap;
|
|
27368
|
+
var init_session_guard = __esm({
|
|
27369
|
+
"src/api/session-guard.ts"() {
|
|
27370
|
+
"use strict";
|
|
27371
|
+
init_logger();
|
|
27372
|
+
SESSION_PAUSE_DURATION_MS = 60 * 60 * 1e3;
|
|
27373
|
+
PERMANENT_ERROR_PATTERNS = [
|
|
27374
|
+
"\u667A\u80FD\u4F53\u4E0D\u80FD\u4E3A\u7A7A",
|
|
27375
|
+
"\u667A\u80FD\u4F53\u4E0D\u662F\u63A5\u6536\u4EBA\u7684\u667A\u80FD\u4F53",
|
|
27376
|
+
"\u8BBE\u5907\u94FE\u63A5\u5F02\u5E38",
|
|
27377
|
+
"\u7533\u8BF7\u7ED1\u5B9A\u7684AppKey\u4E0D\u5B58\u5728"
|
|
27378
|
+
];
|
|
27379
|
+
pauseUntilMap = /* @__PURE__ */ new Map();
|
|
27380
|
+
}
|
|
27381
|
+
});
|
|
27382
|
+
|
|
27255
27383
|
// src/messaging/send.ts
|
|
27256
27384
|
var send_exports = {};
|
|
27257
27385
|
__export(send_exports, {
|
|
27386
|
+
buildApiOptions: () => buildApiOptions,
|
|
27258
27387
|
pushWorkChatMessage: () => pushWorkChatMessage,
|
|
27259
27388
|
replyWorkChatMessage: () => replyWorkChatMessage
|
|
27260
27389
|
});
|
|
@@ -27300,6 +27429,7 @@ async function replyWorkChatMessage(params) {
|
|
|
27300
27429
|
logger.info(`reply sent to=${to} messageId=${result.msgId}`);
|
|
27301
27430
|
return { messageId: result.msgId };
|
|
27302
27431
|
} catch (err) {
|
|
27432
|
+
pauseOnPermanentError(account.accountId, err instanceof Error ? err.message : String(err));
|
|
27303
27433
|
logger.error(`replyWorkChatMessage: failed to=${to} err=${String(err)}`);
|
|
27304
27434
|
throw err;
|
|
27305
27435
|
}
|
|
@@ -27325,6 +27455,7 @@ async function pushWorkChatMessage(params) {
|
|
|
27325
27455
|
logger.info(`push sent to=${to} messageId=${result.msgId}`);
|
|
27326
27456
|
return { messageId: result.msgId };
|
|
27327
27457
|
} catch (err) {
|
|
27458
|
+
pauseOnPermanentError(account.accountId, err instanceof Error ? err.message : String(err));
|
|
27328
27459
|
logger.error(`pushWorkChatMessage: failed to=${to} err=${String(err)}`);
|
|
27329
27460
|
throw err;
|
|
27330
27461
|
}
|
|
@@ -27334,15 +27465,230 @@ var init_send = __esm({
|
|
|
27334
27465
|
"use strict";
|
|
27335
27466
|
init_types();
|
|
27336
27467
|
init_api();
|
|
27468
|
+
init_session_guard();
|
|
27469
|
+
init_logger();
|
|
27470
|
+
}
|
|
27471
|
+
});
|
|
27472
|
+
|
|
27473
|
+
// src/messaging/send-media.ts
|
|
27474
|
+
var send_media_exports = {};
|
|
27475
|
+
__export(send_media_exports, {
|
|
27476
|
+
downloadRemoteMediaToTemp: () => downloadRemoteMediaToTemp,
|
|
27477
|
+
isLocalMediaSource: () => isLocalMediaSource,
|
|
27478
|
+
resolveLocalMediaPath: () => resolveLocalMediaPath,
|
|
27479
|
+
sendWorkChatMediaFile: () => sendWorkChatMediaFile
|
|
27480
|
+
});
|
|
27481
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
27482
|
+
import os4 from "os";
|
|
27483
|
+
import path5 from "path";
|
|
27484
|
+
function isLocalMediaSource(mediaUrl) {
|
|
27485
|
+
const trimmed = mediaUrl.trim();
|
|
27486
|
+
if (trimmed.startsWith("http://") || trimmed.startsWith("https://")) return false;
|
|
27487
|
+
return trimmed.startsWith("/") || trimmed.startsWith("./") || trimmed.startsWith("../") || trimmed.startsWith("~") || trimmed.startsWith("file://") || path5.isAbsolute(trimmed);
|
|
27488
|
+
}
|
|
27489
|
+
function resolveLocalMediaPath(mediaUrl) {
|
|
27490
|
+
if (mediaUrl.startsWith("file://")) {
|
|
27491
|
+
const parsed = new URL(mediaUrl);
|
|
27492
|
+
return process.platform === "win32" ? parsed.pathname.replace(/^\/([A-Za-z]:)/, "$1") : parsed.pathname;
|
|
27493
|
+
}
|
|
27494
|
+
if (mediaUrl.startsWith("~")) {
|
|
27495
|
+
return path5.join(os4.homedir(), mediaUrl.slice(1));
|
|
27496
|
+
}
|
|
27497
|
+
return path5.resolve(mediaUrl);
|
|
27498
|
+
}
|
|
27499
|
+
function resolveMediaMsgType(filePath) {
|
|
27500
|
+
const ext = path5.extname(filePath).replace(/^\./, "").toLowerCase();
|
|
27501
|
+
return AUDIO_EXTENSIONS.has(ext) ? "audio" : "image";
|
|
27502
|
+
}
|
|
27503
|
+
function requireAgentId(account, agentId) {
|
|
27504
|
+
const resolved = agentId ?? account.agentId;
|
|
27505
|
+
if (!resolved) {
|
|
27506
|
+
throw new Error("workchat: agentId is required \u2014 complete the binding QR flow first");
|
|
27507
|
+
}
|
|
27508
|
+
return resolved;
|
|
27509
|
+
}
|
|
27510
|
+
async function sendMediaRequest(params) {
|
|
27511
|
+
const agentId = requireAgentId(params.account, params.agentId);
|
|
27512
|
+
assertSessionActive(params.account.accountId);
|
|
27513
|
+
const opts = buildApiOptions(params.account);
|
|
27514
|
+
const body = {
|
|
27515
|
+
agentId,
|
|
27516
|
+
receiveId: params.account.userId ?? params.to,
|
|
27517
|
+
msgType: params.msgType,
|
|
27518
|
+
content: params.content,
|
|
27519
|
+
...params.conversationId ? { conversationId: params.conversationId } : {}
|
|
27520
|
+
};
|
|
27521
|
+
if (params.replyToMessageId) body.is_last = true;
|
|
27522
|
+
try {
|
|
27523
|
+
if (params.replyToMessageId) {
|
|
27524
|
+
const result2 = await sendWorkChatReplyMessage({ opts, messageId: params.replyToMessageId, body });
|
|
27525
|
+
logger.info(`reply media sent to=${params.to} messageId=${result2.msgId}`);
|
|
27526
|
+
return { messageId: result2.msgId };
|
|
27527
|
+
}
|
|
27528
|
+
const result = await sendWorkChatMessage({ opts, body });
|
|
27529
|
+
logger.info(`push media sent to=${params.to} messageId=${result.msgId}`);
|
|
27530
|
+
return { messageId: result.msgId };
|
|
27531
|
+
} catch (err) {
|
|
27532
|
+
pauseOnPermanentError(params.account.accountId, err instanceof Error ? err.message : String(err));
|
|
27533
|
+
throw err;
|
|
27534
|
+
}
|
|
27535
|
+
}
|
|
27536
|
+
async function sendWorkChatMediaFile(params) {
|
|
27537
|
+
const { account, to, filePath } = params;
|
|
27538
|
+
const opts = buildApiOptions(account);
|
|
27539
|
+
logger.info(`sendMedia: uploading filePath=${filePath} to=${to}`);
|
|
27540
|
+
const uploaded = await uploadWorkChatFile({ opts, filePath, userId: account.userId ?? to });
|
|
27541
|
+
logger.info(`sendMedia: upload done urlLen=${uploaded.url.length} suffix=${uploaded.suffix ?? "(none)"}`);
|
|
27542
|
+
const caption = params.text?.trim() ?? "";
|
|
27543
|
+
if (caption) {
|
|
27544
|
+
await pushWorkChatMessage({
|
|
27545
|
+
account,
|
|
27546
|
+
to,
|
|
27547
|
+
text: caption,
|
|
27548
|
+
conversationId: params.conversationId,
|
|
27549
|
+
agentId: params.agentId
|
|
27550
|
+
});
|
|
27551
|
+
}
|
|
27552
|
+
const msgType = resolveMediaMsgType(filePath) === "audio" ? WorkChatMsgType.Audio : WorkChatMsgType.Image;
|
|
27553
|
+
return sendMediaRequest({
|
|
27554
|
+
account,
|
|
27555
|
+
to,
|
|
27556
|
+
msgType,
|
|
27557
|
+
content: JSON.stringify({ url: uploaded.url }),
|
|
27558
|
+
replyToMessageId: params.replyToMessageId,
|
|
27559
|
+
conversationId: params.conversationId,
|
|
27560
|
+
agentId: params.agentId
|
|
27561
|
+
});
|
|
27562
|
+
}
|
|
27563
|
+
function tempMediaPath(ext) {
|
|
27564
|
+
return path5.join(REMOTE_MEDIA_DIR, `${generateId("remote").replace(/:/g, "-")}${ext}`);
|
|
27565
|
+
}
|
|
27566
|
+
function extensionFromUrlOrContentType(contentType, url2) {
|
|
27567
|
+
const fromUrl = path5.extname(new URL(url2).pathname).toLowerCase();
|
|
27568
|
+
if (fromUrl) return fromUrl;
|
|
27569
|
+
if (contentType?.startsWith("audio/mpeg")) return ".mp3";
|
|
27570
|
+
if (contentType?.startsWith("audio/wav")) return ".wav";
|
|
27571
|
+
if (contentType?.startsWith("audio/mp4")) return ".m4a";
|
|
27572
|
+
if (contentType?.startsWith("image/")) return ".png";
|
|
27573
|
+
return ".bin";
|
|
27574
|
+
}
|
|
27575
|
+
async function downloadRemoteMediaToTemp(url2) {
|
|
27576
|
+
const controller = new AbortController();
|
|
27577
|
+
const timeoutId = setTimeout(() => controller.abort(), REMOTE_MEDIA_DOWNLOAD_TIMEOUT_MS);
|
|
27578
|
+
let response;
|
|
27579
|
+
try {
|
|
27580
|
+
response = await globalThis.fetch(url2, { signal: controller.signal });
|
|
27581
|
+
} finally {
|
|
27582
|
+
clearTimeout(timeoutId);
|
|
27583
|
+
}
|
|
27584
|
+
if (!response.ok) {
|
|
27585
|
+
throw new Error(
|
|
27586
|
+
`remote media download failed: ${response.status} ${response.statusText} url=${url2.slice(0, 80)}`
|
|
27587
|
+
);
|
|
27588
|
+
}
|
|
27589
|
+
const buf = Buffer.from(await response.arrayBuffer());
|
|
27590
|
+
const ext = extensionFromUrlOrContentType(response.headers.get("content-type"), url2);
|
|
27591
|
+
await mkdir(REMOTE_MEDIA_DIR, { recursive: true });
|
|
27592
|
+
const filePath = tempMediaPath(ext);
|
|
27593
|
+
await writeFile(filePath, buf);
|
|
27594
|
+
logger.debug(`downloadRemoteMediaToTemp: saved ${buf.length} bytes to ${filePath}`);
|
|
27595
|
+
return filePath;
|
|
27596
|
+
}
|
|
27597
|
+
var AUDIO_EXTENSIONS, REMOTE_MEDIA_DIR, REMOTE_MEDIA_DOWNLOAD_TIMEOUT_MS;
|
|
27598
|
+
var init_send_media = __esm({
|
|
27599
|
+
"src/messaging/send-media.ts"() {
|
|
27600
|
+
"use strict";
|
|
27601
|
+
init_api();
|
|
27602
|
+
init_session_guard();
|
|
27603
|
+
init_types();
|
|
27604
|
+
init_logger();
|
|
27605
|
+
init_random();
|
|
27606
|
+
init_send();
|
|
27607
|
+
AUDIO_EXTENSIONS = /* @__PURE__ */ new Set(["wav", "m4a", "mp3"]);
|
|
27608
|
+
REMOTE_MEDIA_DIR = path5.join(os4.tmpdir(), "openclaw", "workchat", "media");
|
|
27609
|
+
REMOTE_MEDIA_DOWNLOAD_TIMEOUT_MS = 6e4;
|
|
27610
|
+
}
|
|
27611
|
+
});
|
|
27612
|
+
|
|
27613
|
+
// src/messaging/outbound-hooks.ts
|
|
27614
|
+
var outbound_hooks_exports = {};
|
|
27615
|
+
__export(outbound_hooks_exports, {
|
|
27616
|
+
applyWorkChatMessageSendingHook: () => applyWorkChatMessageSendingHook,
|
|
27617
|
+
emitWorkChatMessageSent: () => emitWorkChatMessageSent
|
|
27618
|
+
});
|
|
27619
|
+
import {
|
|
27620
|
+
fireAndForgetHook,
|
|
27621
|
+
buildCanonicalSentMessageHookContext,
|
|
27622
|
+
toPluginMessageContext,
|
|
27623
|
+
toPluginMessageSentEvent
|
|
27624
|
+
} from "openclaw/plugin-sdk/hook-runtime";
|
|
27625
|
+
import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
|
|
27626
|
+
async function applyWorkChatMessageSendingHook(params) {
|
|
27627
|
+
const hookRunner = getGlobalHookRunner();
|
|
27628
|
+
if (!hookRunner?.hasHooks("message_sending")) {
|
|
27629
|
+
return { cancelled: false, text: params.text };
|
|
27630
|
+
}
|
|
27631
|
+
try {
|
|
27632
|
+
const hookResult = await hookRunner.runMessageSending(
|
|
27633
|
+
{
|
|
27634
|
+
to: params.to,
|
|
27635
|
+
content: params.text,
|
|
27636
|
+
metadata: {
|
|
27637
|
+
channel: CHANNEL_ID,
|
|
27638
|
+
accountId: params.accountId,
|
|
27639
|
+
...params.mediaUrl ? { mediaUrls: [params.mediaUrl] } : {}
|
|
27640
|
+
}
|
|
27641
|
+
},
|
|
27642
|
+
{ channelId: CHANNEL_ID, accountId: params.accountId }
|
|
27643
|
+
);
|
|
27644
|
+
if (hookResult?.cancel) {
|
|
27645
|
+
return { cancelled: true, text: params.text };
|
|
27646
|
+
}
|
|
27647
|
+
return {
|
|
27648
|
+
cancelled: false,
|
|
27649
|
+
text: hookResult?.content ?? params.text
|
|
27650
|
+
};
|
|
27651
|
+
} catch (err) {
|
|
27652
|
+
logger.warn(`message_sending hook error, proceeding with send: ${String(err)}`);
|
|
27653
|
+
return { cancelled: false, text: params.text };
|
|
27654
|
+
}
|
|
27655
|
+
}
|
|
27656
|
+
function emitWorkChatMessageSent(params) {
|
|
27657
|
+
const hookRunner = getGlobalHookRunner();
|
|
27658
|
+
if (!hookRunner?.hasHooks("message_sent")) return;
|
|
27659
|
+
const canonical = buildCanonicalSentMessageHookContext({
|
|
27660
|
+
to: params.to,
|
|
27661
|
+
content: params.content,
|
|
27662
|
+
success: params.success,
|
|
27663
|
+
error: params.error,
|
|
27664
|
+
channelId: CHANNEL_ID,
|
|
27665
|
+
accountId: params.accountId,
|
|
27666
|
+
conversationId: params.to
|
|
27667
|
+
});
|
|
27668
|
+
fireAndForgetHook(
|
|
27669
|
+
Promise.resolve(
|
|
27670
|
+
hookRunner.runMessageSent(
|
|
27671
|
+
toPluginMessageSentEvent(canonical),
|
|
27672
|
+
toPluginMessageContext(canonical)
|
|
27673
|
+
)
|
|
27674
|
+
),
|
|
27675
|
+
"workchat: message_sent plugin hook failed"
|
|
27676
|
+
);
|
|
27677
|
+
}
|
|
27678
|
+
var CHANNEL_ID;
|
|
27679
|
+
var init_outbound_hooks = __esm({
|
|
27680
|
+
"src/messaging/outbound-hooks.ts"() {
|
|
27681
|
+
"use strict";
|
|
27337
27682
|
init_logger();
|
|
27683
|
+
CHANNEL_ID = "openclaw-workchat";
|
|
27338
27684
|
}
|
|
27339
27685
|
});
|
|
27340
27686
|
|
|
27341
27687
|
// src/messaging/debug-mode.ts
|
|
27342
27688
|
import fs5 from "fs";
|
|
27343
|
-
import
|
|
27689
|
+
import path6 from "path";
|
|
27344
27690
|
function resolveDebugModePath() {
|
|
27345
|
-
return
|
|
27691
|
+
return path6.join(resolveStateDir(), "openclaw-workchat", "debug-mode.json");
|
|
27346
27692
|
}
|
|
27347
27693
|
function loadState() {
|
|
27348
27694
|
try {
|
|
@@ -27355,7 +27701,7 @@ function loadState() {
|
|
|
27355
27701
|
}
|
|
27356
27702
|
function saveState(state) {
|
|
27357
27703
|
const filePath = resolveDebugModePath();
|
|
27358
|
-
fs5.mkdirSync(
|
|
27704
|
+
fs5.mkdirSync(path6.dirname(filePath), { recursive: true });
|
|
27359
27705
|
fs5.writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
|
|
27360
27706
|
}
|
|
27361
27707
|
function toggleDebugMode(accountId) {
|
|
@@ -27465,77 +27811,73 @@ var init_slash_commands = __esm({
|
|
|
27465
27811
|
}
|
|
27466
27812
|
});
|
|
27467
27813
|
|
|
27468
|
-
// src/
|
|
27469
|
-
var
|
|
27470
|
-
__export(
|
|
27471
|
-
|
|
27472
|
-
|
|
27814
|
+
// src/storage/seen-msgids.ts
|
|
27815
|
+
var seen_msgids_exports = {};
|
|
27816
|
+
__export(seen_msgids_exports, {
|
|
27817
|
+
_resetSeenMsgIdsForTest: () => _resetSeenMsgIdsForTest,
|
|
27818
|
+
isDuplicateMessage: () => isDuplicateMessage,
|
|
27819
|
+
recordMessageProcessed: () => recordMessageProcessed
|
|
27473
27820
|
});
|
|
27474
|
-
import
|
|
27475
|
-
|
|
27476
|
-
|
|
27477
|
-
|
|
27478
|
-
|
|
27479
|
-
}
|
|
27480
|
-
|
|
27481
|
-
|
|
27482
|
-
|
|
27483
|
-
|
|
27484
|
-
return { cancelled: false, text: params.text };
|
|
27485
|
-
}
|
|
27821
|
+
import fs6 from "fs";
|
|
27822
|
+
import path7 from "path";
|
|
27823
|
+
function resolveSeenFilePath(accountId) {
|
|
27824
|
+
const safe = accountId.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
27825
|
+
return path7.join(resolveStateDir(), "openclaw-workchat", "accounts", `${safe}.seen-msgids.json`);
|
|
27826
|
+
}
|
|
27827
|
+
function loadSeen(accountId) {
|
|
27828
|
+
const cached2 = cache.get(accountId);
|
|
27829
|
+
if (cached2) return cached2;
|
|
27830
|
+
let ids = [];
|
|
27486
27831
|
try {
|
|
27487
|
-
const
|
|
27488
|
-
|
|
27489
|
-
|
|
27490
|
-
|
|
27491
|
-
metadata: {
|
|
27492
|
-
channel: CHANNEL_ID,
|
|
27493
|
-
accountId: params.accountId,
|
|
27494
|
-
...params.mediaUrl ? { mediaUrls: [params.mediaUrl] } : {}
|
|
27495
|
-
}
|
|
27496
|
-
},
|
|
27497
|
-
{ channelId: CHANNEL_ID, accountId: params.accountId }
|
|
27498
|
-
);
|
|
27499
|
-
if (hookResult?.cancel) {
|
|
27500
|
-
return { cancelled: true, text: params.text };
|
|
27832
|
+
const raw = fs6.readFileSync(resolveSeenFilePath(accountId), "utf-8");
|
|
27833
|
+
const parsed = JSON.parse(raw);
|
|
27834
|
+
if (Array.isArray(parsed.msgIds)) {
|
|
27835
|
+
ids = parsed.msgIds.filter((x) => typeof x === "string" && x !== "");
|
|
27501
27836
|
}
|
|
27502
|
-
|
|
27503
|
-
|
|
27504
|
-
|
|
27505
|
-
|
|
27837
|
+
} catch {
|
|
27838
|
+
}
|
|
27839
|
+
const entry = { ids, index: new Set(ids) };
|
|
27840
|
+
cache.set(accountId, entry);
|
|
27841
|
+
return entry;
|
|
27842
|
+
}
|
|
27843
|
+
function persistSeen(accountId, seen) {
|
|
27844
|
+
try {
|
|
27845
|
+
const filePath = resolveSeenFilePath(accountId);
|
|
27846
|
+
fs6.mkdirSync(path7.dirname(filePath), { recursive: true });
|
|
27847
|
+
fs6.writeFileSync(filePath, JSON.stringify({ msgIds: seen.ids }), "utf-8");
|
|
27506
27848
|
} catch (err) {
|
|
27507
|
-
logger.warn(`
|
|
27508
|
-
return { cancelled: false, text: params.text };
|
|
27849
|
+
logger.warn(`seen-msgids persist failed accountId=${accountId}: ${String(err)}`);
|
|
27509
27850
|
}
|
|
27510
27851
|
}
|
|
27511
|
-
function
|
|
27512
|
-
|
|
27513
|
-
|
|
27514
|
-
|
|
27515
|
-
to: params.to,
|
|
27516
|
-
content: params.content,
|
|
27517
|
-
success: params.success,
|
|
27518
|
-
error: params.error,
|
|
27519
|
-
channelId: CHANNEL_ID,
|
|
27520
|
-
accountId: params.accountId,
|
|
27521
|
-
conversationId: params.to
|
|
27522
|
-
});
|
|
27523
|
-
fireAndForgetHook(
|
|
27524
|
-
Promise.resolve(
|
|
27525
|
-
hookRunner.runMessageSent(
|
|
27526
|
-
toPluginMessageSentEvent(canonical),
|
|
27527
|
-
toPluginMessageContext(canonical)
|
|
27528
|
-
)
|
|
27529
|
-
),
|
|
27530
|
-
"workchat: message_sent plugin hook failed"
|
|
27531
|
-
);
|
|
27852
|
+
function isDuplicateMessage(accountId, msgId) {
|
|
27853
|
+
if (!msgId) return false;
|
|
27854
|
+
const seen = loadSeen(accountId);
|
|
27855
|
+
return seen.index.has(msgId);
|
|
27532
27856
|
}
|
|
27533
|
-
|
|
27534
|
-
|
|
27535
|
-
|
|
27857
|
+
function recordMessageProcessed(accountId, msgId) {
|
|
27858
|
+
if (!msgId) return true;
|
|
27859
|
+
const seen = loadSeen(accountId);
|
|
27860
|
+
if (seen.index.has(msgId)) return false;
|
|
27861
|
+
seen.index.add(msgId);
|
|
27862
|
+
seen.ids.push(msgId);
|
|
27863
|
+
if (seen.ids.length > SEEN_LIMIT) {
|
|
27864
|
+
const drop = seen.ids.length - SEEN_LIMIT;
|
|
27865
|
+
for (const old of seen.ids.splice(0, drop)) seen.index.delete(old);
|
|
27866
|
+
}
|
|
27867
|
+
persistSeen(accountId, seen);
|
|
27868
|
+
return true;
|
|
27869
|
+
}
|
|
27870
|
+
function _resetSeenMsgIdsForTest() {
|
|
27871
|
+
cache.clear();
|
|
27872
|
+
}
|
|
27873
|
+
var SEEN_LIMIT, cache;
|
|
27874
|
+
var init_seen_msgids = __esm({
|
|
27875
|
+
"src/storage/seen-msgids.ts"() {
|
|
27536
27876
|
"use strict";
|
|
27877
|
+
init_state_dir();
|
|
27537
27878
|
init_logger();
|
|
27538
|
-
|
|
27879
|
+
SEEN_LIMIT = 500;
|
|
27880
|
+
cache = /* @__PURE__ */ new Map();
|
|
27539
27881
|
}
|
|
27540
27882
|
});
|
|
27541
27883
|
|
|
@@ -27873,6 +28215,28 @@ function loadWorkChatOutboundHooks() {
|
|
|
27873
28215
|
workchatOutboundHooksPromise ??= Promise.resolve().then(() => (init_outbound_hooks(), outbound_hooks_exports));
|
|
27874
28216
|
return workchatOutboundHooksPromise;
|
|
27875
28217
|
}
|
|
28218
|
+
async function downloadInboundMedia(url2, deps) {
|
|
28219
|
+
try {
|
|
28220
|
+
if (deps.channelRuntime?.media?.fetchRemoteMedia) {
|
|
28221
|
+
const fetched = await deps.channelRuntime.media.fetchRemoteMedia({
|
|
28222
|
+
url: url2,
|
|
28223
|
+
maxBytes: WORKCHAT_MEDIA_MAX_BYTES
|
|
28224
|
+
});
|
|
28225
|
+
return { buffer: fetched.buffer, contentType: fetched.contentType };
|
|
28226
|
+
}
|
|
28227
|
+
} catch (err) {
|
|
28228
|
+
logger.warn(`fetchRemoteMedia failed, trying plain fetch: ${String(err)}`);
|
|
28229
|
+
}
|
|
28230
|
+
const res = await globalThis.fetch(url2);
|
|
28231
|
+
if (!res.ok) {
|
|
28232
|
+
throw new Error(`inbound media download failed: HTTP ${res.status}`);
|
|
28233
|
+
}
|
|
28234
|
+
const buffer = Buffer.from(await res.arrayBuffer());
|
|
28235
|
+
if (buffer.length > WORKCHAT_MEDIA_MAX_BYTES) {
|
|
28236
|
+
throw new Error(`inbound media exceeds limit (${buffer.length} bytes)`);
|
|
28237
|
+
}
|
|
28238
|
+
return { buffer, contentType: res.headers.get("content-type") ?? void 0 };
|
|
28239
|
+
}
|
|
27876
28240
|
async function applyWorkChatMessageSendingHook2(params) {
|
|
27877
28241
|
try {
|
|
27878
28242
|
const hooks = await loadWorkChatOutboundHooks();
|
|
@@ -28016,13 +28380,21 @@ async function processOneFrame(result, rawFrame, deps) {
|
|
|
28016
28380
|
logger.debug("inbound: empty body, ignoring");
|
|
28017
28381
|
return;
|
|
28018
28382
|
}
|
|
28383
|
+
if (message.messageId) {
|
|
28384
|
+
const { isDuplicateMessage: isDuplicateMessage2, recordMessageProcessed: recordMessageProcessed2 } = await Promise.resolve().then(() => (init_seen_msgids(), seen_msgids_exports));
|
|
28385
|
+
if (isDuplicateMessage2(deps.accountId, message.messageId)) {
|
|
28386
|
+
logger.info(`inbound: duplicate msgId=${message.messageId}, dropping`);
|
|
28387
|
+
return;
|
|
28388
|
+
}
|
|
28389
|
+
recordMessageProcessed2(deps.accountId, message.messageId);
|
|
28390
|
+
}
|
|
28019
28391
|
const receivedAt = Date.now();
|
|
28020
28392
|
const debug = isDebugMode(deps.accountId);
|
|
28021
28393
|
const debugTrace = [];
|
|
28022
28394
|
const debugTs = { received: receivedAt };
|
|
28023
28395
|
const ctx = workChatMessageToMsgContext(message, deps.accountId);
|
|
28024
28396
|
logger.info(
|
|
28025
|
-
`inbound: from=${ctx.From} to=${ctx.To} bodyLen=${ctx.Body.length} conversationId=${ctx.ConversationId ?? "(none)"}`
|
|
28397
|
+
`inbound: from=${ctx.From} to=${ctx.To} bodyLen=${ctx.Body.length} conversationId=${ctx.ConversationId ?? "(none)"} hasMedia=${Boolean(ctx.MediaUrl)}`
|
|
28026
28398
|
);
|
|
28027
28399
|
logger.debug(`inbound raw frame: ${rawFrame.slice(0, 200)}`);
|
|
28028
28400
|
if (ctx.Body.trim().startsWith("/")) {
|
|
@@ -28037,6 +28409,24 @@ async function processOneFrame(result, rawFrame, deps) {
|
|
|
28037
28409
|
return;
|
|
28038
28410
|
}
|
|
28039
28411
|
}
|
|
28412
|
+
if (ctx.MediaUrl && deps.channelRuntime?.media?.saveMediaBuffer) {
|
|
28413
|
+
try {
|
|
28414
|
+
const media = await downloadInboundMedia(ctx.MediaUrl, deps);
|
|
28415
|
+
if (media) {
|
|
28416
|
+
const saved = await deps.channelRuntime.media.saveMediaBuffer(
|
|
28417
|
+
media.buffer,
|
|
28418
|
+
media.contentType,
|
|
28419
|
+
"inbound",
|
|
28420
|
+
WORKCHAT_MEDIA_MAX_BYTES
|
|
28421
|
+
);
|
|
28422
|
+
ctx.MediaPath = saved.path;
|
|
28423
|
+
ctx.MediaType = media.contentType ?? ctx.MediaType;
|
|
28424
|
+
logger.info(`inbound media saved: path=${saved.path} type=${media.contentType}`);
|
|
28425
|
+
}
|
|
28426
|
+
} catch (err) {
|
|
28427
|
+
deps.errLog(`inbound media download failed url=${redactBody(ctx.MediaUrl)}: ${String(err)}`);
|
|
28428
|
+
}
|
|
28429
|
+
}
|
|
28040
28430
|
const rawBody = ctx.Body?.trim() ?? "";
|
|
28041
28431
|
ctx.CommandBody = rawBody;
|
|
28042
28432
|
const senderId = ctx.From;
|
|
@@ -28137,7 +28527,10 @@ async function processOneFrame(result, rawFrame, deps) {
|
|
|
28137
28527
|
const rawText = String(payload.text ?? "");
|
|
28138
28528
|
const f = new StreamingMarkdownFilter2();
|
|
28139
28529
|
let text = f.feed(rawText) + f.flush();
|
|
28140
|
-
|
|
28530
|
+
const mediaUrl = payload.mediaUrl ?? payload.mediaUrls?.[0];
|
|
28531
|
+
logger.info(
|
|
28532
|
+
`outbound: to=${ctx.To} textLen=${text.length} mediaUrl=${mediaUrl ? "present" : "none"}`
|
|
28533
|
+
);
|
|
28141
28534
|
if (debug) {
|
|
28142
28535
|
debugDeliveries.push({
|
|
28143
28536
|
textLen: text.length,
|
|
@@ -28148,7 +28541,8 @@ async function processOneFrame(result, rawFrame, deps) {
|
|
|
28148
28541
|
const sendingResult = await applyWorkChatMessageSendingHook2({
|
|
28149
28542
|
to: ctx.To,
|
|
28150
28543
|
text,
|
|
28151
|
-
accountId: deps.accountId
|
|
28544
|
+
accountId: deps.accountId,
|
|
28545
|
+
mediaUrl
|
|
28152
28546
|
});
|
|
28153
28547
|
if (sendingResult.cancelled) {
|
|
28154
28548
|
logger.info(`outbound: cancelled by message_sending hook to=${ctx.To}`);
|
|
@@ -28156,6 +28550,40 @@ async function processOneFrame(result, rawFrame, deps) {
|
|
|
28156
28550
|
}
|
|
28157
28551
|
text = sendingResult.text;
|
|
28158
28552
|
try {
|
|
28553
|
+
if (mediaUrl) {
|
|
28554
|
+
const { isLocalMediaSource: isLocalMediaSource2, resolveLocalMediaPath: resolveLocalMediaPath2, downloadRemoteMediaToTemp: downloadRemoteMediaToTemp2, sendWorkChatMediaFile: sendWorkChatMediaFile2 } = await Promise.resolve().then(() => (init_send_media(), send_media_exports));
|
|
28555
|
+
let filePath;
|
|
28556
|
+
if (isLocalMediaSource2(mediaUrl)) {
|
|
28557
|
+
filePath = resolveLocalMediaPath2(mediaUrl);
|
|
28558
|
+
logger.debug(`outbound: local media resolved filePath=${filePath}`);
|
|
28559
|
+
} else if (mediaUrl.startsWith("http://") || mediaUrl.startsWith("https://")) {
|
|
28560
|
+
logger.debug(`outbound: downloading remote mediaUrl=${mediaUrl.slice(0, 80)}...`);
|
|
28561
|
+
filePath = await downloadRemoteMediaToTemp2(mediaUrl);
|
|
28562
|
+
} else {
|
|
28563
|
+
logger.warn(
|
|
28564
|
+
`outbound: unrecognized mediaUrl scheme, sending text only mediaUrl=${mediaUrl.slice(0, 80)}`
|
|
28565
|
+
);
|
|
28566
|
+
filePath = "";
|
|
28567
|
+
}
|
|
28568
|
+
if (filePath) {
|
|
28569
|
+
await sendWorkChatMediaFile2({
|
|
28570
|
+
account: {
|
|
28571
|
+
...deps.account,
|
|
28572
|
+
agentId: ctx.AgentId ?? deps.account.agentId,
|
|
28573
|
+
userId: ctx.From || deps.account.userId
|
|
28574
|
+
},
|
|
28575
|
+
to: ctx.To,
|
|
28576
|
+
filePath,
|
|
28577
|
+
text,
|
|
28578
|
+
replyToMessageId: ctx.MessageSid,
|
|
28579
|
+
conversationId: ctx.ConversationId,
|
|
28580
|
+
agentId: ctx.AgentId
|
|
28581
|
+
});
|
|
28582
|
+
emitWorkChatMessageSent2({ to: ctx.To, content: text, success: true, accountId: deps.accountId });
|
|
28583
|
+
logger.info(`outbound: media reply sent OK to=${ctx.To}`);
|
|
28584
|
+
return;
|
|
28585
|
+
}
|
|
28586
|
+
}
|
|
28159
28587
|
const result2 = await replyWorkChatMessage2({
|
|
28160
28588
|
account: {
|
|
28161
28589
|
...deps.account,
|
|
@@ -28180,7 +28608,14 @@ async function processOneFrame(result, rawFrame, deps) {
|
|
|
28180
28608
|
onError: (err, info) => {
|
|
28181
28609
|
deps.errLog(`workchat reply ${info.kind}: ${String(err)}`);
|
|
28182
28610
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
28183
|
-
|
|
28611
|
+
let notice;
|
|
28612
|
+
if (errMsg.includes("remote media download failed")) {
|
|
28613
|
+
notice = `\u26A0\uFE0F \u5A92\u4F53\u6587\u4EF6\u4E0B\u8F7D\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u94FE\u63A5\u662F\u5426\u53EF\u8BBF\u95EE\u3002`;
|
|
28614
|
+
} else if (errMsg.includes("file upload response") || errMsg.includes("upload failed")) {
|
|
28615
|
+
notice = `\u26A0\uFE0F \u5A92\u4F53\u6587\u4EF6\u4E0A\u4F20\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002`;
|
|
28616
|
+
} else {
|
|
28617
|
+
notice = `\u26A0\uFE0F \u6D88\u606F\u53D1\u9001\u5931\u8D25\uFF1A${errMsg}`;
|
|
28618
|
+
}
|
|
28184
28619
|
void sendWorkChatErrorNotice({
|
|
28185
28620
|
account: deps.account,
|
|
28186
28621
|
to: ctx.To,
|
|
@@ -28250,7 +28685,7 @@ ${debugTrace.join("\n")}`;
|
|
|
28250
28685
|
}
|
|
28251
28686
|
}
|
|
28252
28687
|
}
|
|
28253
|
-
var workchatOutboundHooksPromise, createTypingCallbacksPromise;
|
|
28688
|
+
var workchatOutboundHooksPromise, WORKCHAT_MEDIA_MAX_BYTES, createTypingCallbacksPromise;
|
|
28254
28689
|
var init_process_message = __esm({
|
|
28255
28690
|
"src/messaging/process-message.ts"() {
|
|
28256
28691
|
"use strict";
|
|
@@ -28264,6 +28699,7 @@ var init_process_message = __esm({
|
|
|
28264
28699
|
init_inbound();
|
|
28265
28700
|
init_slash_commands();
|
|
28266
28701
|
workchatOutboundHooksPromise = null;
|
|
28702
|
+
WORKCHAT_MEDIA_MAX_BYTES = 100 * 1024 * 1024;
|
|
28267
28703
|
}
|
|
28268
28704
|
});
|
|
28269
28705
|
|
|
@@ -28318,8 +28754,8 @@ async function monitorWorkChatProvider(opts) {
|
|
|
28318
28754
|
localIp: opts.localIp
|
|
28319
28755
|
});
|
|
28320
28756
|
const url2 = `${endpoint}?ticket=${encodeURIComponent(ticket)}`;
|
|
28321
|
-
const dispatcher = apiOpts.allowInsecureTls ? new
|
|
28322
|
-
ws = new
|
|
28757
|
+
const dispatcher = apiOpts.allowInsecureTls ? new import_undici2.Agent({ connect: { rejectUnauthorized: false } }) : void 0;
|
|
28758
|
+
ws = new import_undici2.WebSocket(url2, dispatcher ? { dispatcher } : void 0);
|
|
28323
28759
|
await new Promise((resolve, reject) => {
|
|
28324
28760
|
const timer = setTimeout(
|
|
28325
28761
|
() => reject(new Error("workchat websocket connection timeout")),
|
|
@@ -28452,11 +28888,11 @@ async function monitorWorkChatProvider(opts) {
|
|
|
28452
28888
|
}
|
|
28453
28889
|
}
|
|
28454
28890
|
}
|
|
28455
|
-
var
|
|
28891
|
+
var import_undici2, WS_CONNECT_TIMEOUT_MS, RECONNECT_BACKOFF_BASE_MS, RECONNECT_BACKOFF_MAX_MS, RATE_LIMIT_BACKOFF_MS;
|
|
28456
28892
|
var init_monitor = __esm({
|
|
28457
28893
|
"src/monitor/monitor.ts"() {
|
|
28458
28894
|
"use strict";
|
|
28459
|
-
|
|
28895
|
+
import_undici2 = __toESM(require_undici(), 1);
|
|
28460
28896
|
init_api();
|
|
28461
28897
|
init_api();
|
|
28462
28898
|
init_inbound();
|
|
@@ -29573,6 +30009,7 @@ init_accounts();
|
|
|
29573
30009
|
init_types();
|
|
29574
30010
|
init_login_qr();
|
|
29575
30011
|
init_send();
|
|
30012
|
+
init_send_media();
|
|
29576
30013
|
init_logger();
|
|
29577
30014
|
function resolveOutboundAccount(cfg, accountId) {
|
|
29578
30015
|
const allIds = listWorkChatAccountIds(cfg);
|
|
@@ -29625,7 +30062,8 @@ var workchatPlugin = {
|
|
|
29625
30062
|
messageToolHints: () => [
|
|
29626
30063
|
"To send a message to the current WorkChat user, use the message tool with action='send'. You do not need to specify 'to' \u2014 the current conversation recipient is used automatically.",
|
|
29627
30064
|
"IMPORTANT: When creating a cron job (scheduled task) for the current WorkChat user, you MUST set delivery.to to the user's WorkChat ID (the numeric ID from the current conversation) AND set delivery.accountId to the current AccountId. Without an explicit 'to', the cron delivery will fail with 'requires target'. Without an explicit 'accountId', the message may be sent from the wrong bot account. Example: delivery: { mode: 'announce', channel: 'openclaw-workchat', to: '<current_user_id>', accountId: '<current_AccountId>' }.",
|
|
29628
|
-
"
|
|
30065
|
+
"To send an image or audio file to the current user, use the message tool with action='send' and set 'media' to a local file path or a remote HTTPS URL. Supported audio formats: wav, m4a, mp3; supported image formats: bmp, gif, jpg, jpeg, png, webp. Remote URLs are downloaded and re-uploaded to WorkChat storage automatically \u2014 the client renders image/audio cards, never bare links.",
|
|
30066
|
+
"IMPORTANT: When generating or saving a file to send, always use an absolute path (e.g. /tmp/photo.png or C:\\tmp\\photo.png on Windows), never a relative path like ./photo.png. Relative paths cannot be resolved and the file will not be delivered."
|
|
29629
30067
|
]
|
|
29630
30068
|
},
|
|
29631
30069
|
reload: { configPrefixes: ["channels.openclaw-workchat"] },
|
|
@@ -29660,13 +30098,62 @@ var workchatPlugin = {
|
|
|
29660
30098
|
},
|
|
29661
30099
|
sendMedia: async (ctx) => {
|
|
29662
30100
|
const account = resolveOutboundAccount(ctx.cfg, ctx.accountId);
|
|
29663
|
-
const
|
|
29664
|
-
const
|
|
29665
|
-
|
|
30101
|
+
const aLog = logger.withAccount(account.accountId);
|
|
30102
|
+
const mediaUrl = ctx.mediaUrl?.trim();
|
|
30103
|
+
let text = ctx.text ?? "";
|
|
30104
|
+
const { applyWorkChatMessageSendingHook: applyWorkChatMessageSendingHook3, emitWorkChatMessageSent: emitWorkChatMessageSent3 } = await Promise.resolve().then(() => (init_outbound_hooks(), outbound_hooks_exports));
|
|
30105
|
+
const sendingResult = await applyWorkChatMessageSendingHook3({
|
|
29666
30106
|
to: ctx.to,
|
|
29667
|
-
text
|
|
30107
|
+
text,
|
|
30108
|
+
accountId: account.accountId,
|
|
30109
|
+
mediaUrl
|
|
30110
|
+
}).catch((err) => {
|
|
30111
|
+
aLog.warn(`message_sending hook error, proceeding: ${String(err)}`);
|
|
30112
|
+
return { cancelled: false, text };
|
|
29668
30113
|
});
|
|
29669
|
-
|
|
30114
|
+
if (sendingResult.cancelled) {
|
|
30115
|
+
aLog.info(`sendMedia: cancelled by message_sending hook to=${ctx.to}`);
|
|
30116
|
+
return { channel: "openclaw-workchat", messageId: "" };
|
|
30117
|
+
}
|
|
30118
|
+
text = sendingResult.text;
|
|
30119
|
+
if (!mediaUrl) {
|
|
30120
|
+
try {
|
|
30121
|
+
const result = await pushWorkChatMessage({ account, to: ctx.to, text });
|
|
30122
|
+
emitWorkChatMessageSent3({ to: ctx.to, content: text, success: true, accountId: account.accountId });
|
|
30123
|
+
return { channel: "openclaw-workchat", messageId: result.messageId };
|
|
30124
|
+
} catch (err) {
|
|
30125
|
+
emitWorkChatMessageSent3({ to: ctx.to, content: text, success: false, error: String(err), accountId: account.accountId });
|
|
30126
|
+
throw err;
|
|
30127
|
+
}
|
|
30128
|
+
}
|
|
30129
|
+
let filePath;
|
|
30130
|
+
try {
|
|
30131
|
+
if (isLocalMediaSource(mediaUrl)) {
|
|
30132
|
+
filePath = resolveLocalMediaPath(mediaUrl);
|
|
30133
|
+
aLog.debug(`sendMedia: uploading local file ${filePath}`);
|
|
30134
|
+
} else {
|
|
30135
|
+
aLog.debug(`sendMedia: downloading remote mediaUrl=${mediaUrl.slice(0, 80)}...`);
|
|
30136
|
+
filePath = await downloadRemoteMediaToTemp(mediaUrl);
|
|
30137
|
+
aLog.debug(`sendMedia: remote media downloaded to ${filePath}`);
|
|
30138
|
+
}
|
|
30139
|
+
} catch (err) {
|
|
30140
|
+
emitWorkChatMessageSent3({ to: ctx.to, content: text, success: false, error: String(err), accountId: account.accountId });
|
|
30141
|
+
throw err;
|
|
30142
|
+
}
|
|
30143
|
+
try {
|
|
30144
|
+
const result = await sendWorkChatMediaFile({
|
|
30145
|
+
account,
|
|
30146
|
+
to: ctx.to,
|
|
30147
|
+
filePath,
|
|
30148
|
+
text,
|
|
30149
|
+
replyToMessageId: ctx.replyToId?.trim() || void 0
|
|
30150
|
+
});
|
|
30151
|
+
emitWorkChatMessageSent3({ to: ctx.to, content: text, success: true, accountId: account.accountId });
|
|
30152
|
+
return { channel: "openclaw-workchat", messageId: result.messageId };
|
|
30153
|
+
} catch (err) {
|
|
30154
|
+
emitWorkChatMessageSent3({ to: ctx.to, content: text, success: false, error: String(err), accountId: account.accountId });
|
|
30155
|
+
throw err;
|
|
30156
|
+
}
|
|
29670
30157
|
}
|
|
29671
30158
|
},
|
|
29672
30159
|
status: {
|
|
@@ -30680,10 +31167,10 @@ function mergeDefs(...defs) {
|
|
|
30680
31167
|
function cloneDef(schema) {
|
|
30681
31168
|
return mergeDefs(schema._zod.def);
|
|
30682
31169
|
}
|
|
30683
|
-
function getElementAtPath(obj,
|
|
30684
|
-
if (!
|
|
31170
|
+
function getElementAtPath(obj, path8) {
|
|
31171
|
+
if (!path8)
|
|
30685
31172
|
return obj;
|
|
30686
|
-
return
|
|
31173
|
+
return path8.reduce((acc, key) => acc?.[key], obj);
|
|
30687
31174
|
}
|
|
30688
31175
|
function promiseAllObject(promisesObj) {
|
|
30689
31176
|
const keys = Object.keys(promisesObj);
|
|
@@ -31023,11 +31510,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
31023
31510
|
}
|
|
31024
31511
|
return false;
|
|
31025
31512
|
}
|
|
31026
|
-
function prefixIssues(
|
|
31513
|
+
function prefixIssues(path8, issues) {
|
|
31027
31514
|
return issues.map((iss) => {
|
|
31028
31515
|
var _a3;
|
|
31029
31516
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
31030
|
-
iss.path.unshift(
|
|
31517
|
+
iss.path.unshift(path8);
|
|
31031
31518
|
return iss;
|
|
31032
31519
|
});
|
|
31033
31520
|
}
|
|
@@ -31489,16 +31976,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
|
|
|
31489
31976
|
}
|
|
31490
31977
|
function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
31491
31978
|
const fieldErrors = { _errors: [] };
|
|
31492
|
-
const processError = (error63,
|
|
31979
|
+
const processError = (error63, path8 = []) => {
|
|
31493
31980
|
for (const issue2 of error63.issues) {
|
|
31494
31981
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
31495
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
31982
|
+
issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
|
|
31496
31983
|
} else if (issue2.code === "invalid_key") {
|
|
31497
|
-
processError({ issues: issue2.issues }, [...
|
|
31984
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
31498
31985
|
} else if (issue2.code === "invalid_element") {
|
|
31499
|
-
processError({ issues: issue2.issues }, [...
|
|
31986
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
31500
31987
|
} else {
|
|
31501
|
-
const fullpath = [...
|
|
31988
|
+
const fullpath = [...path8, ...issue2.path];
|
|
31502
31989
|
if (fullpath.length === 0) {
|
|
31503
31990
|
fieldErrors._errors.push(mapper(issue2));
|
|
31504
31991
|
} else {
|
|
@@ -31537,17 +32024,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
|
31537
32024
|
}
|
|
31538
32025
|
function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
31539
32026
|
const result = { errors: [] };
|
|
31540
|
-
const processError = (error63,
|
|
32027
|
+
const processError = (error63, path8 = []) => {
|
|
31541
32028
|
var _a3;
|
|
31542
32029
|
for (const issue2 of error63.issues) {
|
|
31543
32030
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
31544
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
32031
|
+
issue2.errors.map((issues) => processError({ issues }, [...path8, ...issue2.path]));
|
|
31545
32032
|
} else if (issue2.code === "invalid_key") {
|
|
31546
|
-
processError({ issues: issue2.issues }, [...
|
|
32033
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
31547
32034
|
} else if (issue2.code === "invalid_element") {
|
|
31548
|
-
processError({ issues: issue2.issues }, [...
|
|
32035
|
+
processError({ issues: issue2.issues }, [...path8, ...issue2.path]);
|
|
31549
32036
|
} else {
|
|
31550
|
-
const fullpath = [...
|
|
32037
|
+
const fullpath = [...path8, ...issue2.path];
|
|
31551
32038
|
if (fullpath.length === 0) {
|
|
31552
32039
|
result.errors.push(mapper(issue2));
|
|
31553
32040
|
continue;
|
|
@@ -31586,8 +32073,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
|
31586
32073
|
}
|
|
31587
32074
|
function toDotPath(_path) {
|
|
31588
32075
|
const segs = [];
|
|
31589
|
-
const
|
|
31590
|
-
for (const seg of
|
|
32076
|
+
const path8 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
32077
|
+
for (const seg of path8) {
|
|
31591
32078
|
if (typeof seg === "number")
|
|
31592
32079
|
segs.push(`[${seg}]`);
|
|
31593
32080
|
else if (typeof seg === "symbol")
|
|
@@ -48716,13 +49203,13 @@ function resolveRef(ref, ctx) {
|
|
|
48716
49203
|
if (!ref.startsWith("#")) {
|
|
48717
49204
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
48718
49205
|
}
|
|
48719
|
-
const
|
|
48720
|
-
if (
|
|
49206
|
+
const path8 = ref.slice(1).split("/").filter(Boolean);
|
|
49207
|
+
if (path8.length === 0) {
|
|
48721
49208
|
return ctx.rootSchema;
|
|
48722
49209
|
}
|
|
48723
49210
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
48724
|
-
if (
|
|
48725
|
-
const key =
|
|
49211
|
+
if (path8[0] === defsKey) {
|
|
49212
|
+
const key = path8[1] === void 0 ? void 0 : decodeJSONPointerSegment(path8[1]);
|
|
48726
49213
|
if (!key || !ctx.defs[key]) {
|
|
48727
49214
|
throw new Error(`Reference not found: ${ref}`);
|
|
48728
49215
|
}
|
|
@@ -49356,21 +49843,21 @@ function visit(schema, fnOrHandlers) {
|
|
|
49356
49843
|
const h = fnOrHandlers[node2._zod.def.type];
|
|
49357
49844
|
return h ? h(node2, rewritten) : node2;
|
|
49358
49845
|
};
|
|
49359
|
-
const
|
|
49846
|
+
const cache2 = /* @__PURE__ */ new Map();
|
|
49360
49847
|
function run(s) {
|
|
49361
|
-
const cached2 =
|
|
49848
|
+
const cached2 = cache2.get(s);
|
|
49362
49849
|
if (cached2 === RESOLVING) {
|
|
49363
49850
|
return new $ZodLazy({
|
|
49364
49851
|
type: "lazy",
|
|
49365
|
-
getter: () =>
|
|
49852
|
+
getter: () => cache2.get(s)
|
|
49366
49853
|
});
|
|
49367
49854
|
}
|
|
49368
49855
|
if (cached2 !== void 0)
|
|
49369
49856
|
return cached2;
|
|
49370
|
-
|
|
49857
|
+
cache2.set(s, RESOLVING);
|
|
49371
49858
|
const inner = mapInner(s);
|
|
49372
49859
|
const mapped = fn(inner, inner !== s);
|
|
49373
|
-
|
|
49860
|
+
cache2.set(s, mapped);
|
|
49374
49861
|
return mapped;
|
|
49375
49862
|
}
|
|
49376
49863
|
function mapInner(s) {
|