@senguoyun/dsh-arkme 0.1.51 → 0.1.52
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/docs/dsh-input-system-topic.md +26 -0
- package/lib/client.js +4279 -3022
- package/lib/client.js.map +1 -1
- package/lib/extension-profile-restart-helper.js +10 -6
- package/lib/harness-model-client.js +8 -0
- package/lib/index.js +99 -57
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-Be8cvpQd.js → persistent-runtime-BRy2sNmS.js} +321 -82
- package/lib/{plugin-updater-helper-B0yVav4f.js → plugin-updater-helper-n8JrMPum.js} +1 -1
- package/lib/{plugin-updater-helper-BbjKUV9T.js → plugin-updater-helper-y7wzJLOx.js} +11 -4
- package/lib/plugin-updater-helper.js +1 -1
- package/lib/sdk.js +8 -0
- package/lib/types/arkme-service.d.ts +3 -0
- package/lib/types/arkme-service.d.ts.map +1 -1
- package/lib/types/call-record-presentation.d.ts +2 -0
- package/lib/types/call-record-presentation.d.ts.map +1 -1
- package/lib/types/client/ArkmeBotConversationSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeBotCreateDialog.d.ts.map +1 -1
- package/lib/types/client/ArkmeCallDetailContent.d.ts +13 -0
- package/lib/types/client/ArkmeCallDetailContent.d.ts.map +1 -0
- package/lib/types/client/ArkmeCallDetailDrawer.d.ts +2 -1
- package/lib/types/client/ArkmeCallDetailDrawer.d.ts.map +1 -1
- package/lib/types/client/ArkmeCallRecordContent.d.ts +4 -2
- package/lib/types/client/ArkmeCallRecordContent.d.ts.map +1 -1
- package/lib/types/client/ArkmeCallSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeComposerSendButton.d.ts +10 -0
- package/lib/types/client/ArkmeComposerSendButton.d.ts.map +1 -0
- package/lib/types/client/ArkmeDshAgentInputMarker.d.ts +1 -1
- package/lib/types/client/ArkmeDshAgentInputMarker.d.ts.map +1 -1
- package/lib/types/client/ArkmeLinkText.d.ts +1 -1
- package/lib/types/client/ArkmeLinkText.d.ts.map +1 -1
- package/lib/types/client/ArkmeLogin.d.ts.map +1 -1
- package/lib/types/client/ArkmeMarketplace.d.ts +1 -0
- package/lib/types/client/ArkmeMarketplace.d.ts.map +1 -1
- package/lib/types/client/ArkmeMentionSuggestionRow.d.ts +20 -0
- package/lib/types/client/ArkmeMentionSuggestionRow.d.ts.map +1 -0
- package/lib/types/client/ArkmeMessageActions.d.ts.map +1 -1
- package/lib/types/client/ArkmeNoteDetails.d.ts +6 -2
- package/lib/types/client/ArkmeNoteDetails.d.ts.map +1 -1
- package/lib/types/client/ArkmeOfficialAuthorGuide.d.ts +7 -0
- package/lib/types/client/ArkmeOfficialAuthorGuide.d.ts.map +1 -0
- package/lib/types/client/ArkmePersistentShell.d.ts +1 -1
- package/lib/types/client/ArkmePersistentShell.d.ts.map +1 -1
- package/lib/types/client/ArkmeRichContent.d.ts +2 -1
- package/lib/types/client/ArkmeRichContent.d.ts.map +1 -1
- package/lib/types/client/ArkmeRichText.d.ts +9 -5
- package/lib/types/client/ArkmeRichText.d.ts.map +1 -1
- package/lib/types/client/ArkmeScanGuide.d.ts +5 -0
- package/lib/types/client/ArkmeScanGuide.d.ts.map +1 -0
- package/lib/types/client/ArkmeSidebar.d.ts +3 -35
- package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
- package/lib/types/client/ArkmeSourceBreadcrumb.d.ts.map +1 -1
- package/lib/types/client/ArkmeTopicDirectoryPopover.d.ts +2 -1
- package/lib/types/client/ArkmeTopicDirectoryPopover.d.ts.map +1 -1
- package/lib/types/client/ArkmeTopicReadOnlyNotice.d.ts +3 -0
- package/lib/types/client/ArkmeTopicReadOnlyNotice.d.ts.map +1 -0
- package/lib/types/client/ArkmeVirtualWorkspace.d.ts +13 -7
- package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
- package/lib/types/client/api.d.ts +1 -1
- package/lib/types/client/api.d.ts.map +1 -1
- package/lib/types/client/arkme-login-locales.d.ts +13 -0
- package/lib/types/client/arkme-login-locales.d.ts.map +1 -1
- package/lib/types/client/call-detail-presentation.d.ts +13 -0
- package/lib/types/client/call-detail-presentation.d.ts.map +1 -0
- package/lib/types/client/chat-directory-store.d.ts.map +1 -1
- package/lib/types/client/composer-draft-store.d.ts +7 -0
- package/lib/types/client/composer-draft-store.d.ts.map +1 -1
- package/lib/types/client/conversation-composer-presentation.d.ts +3 -0
- package/lib/types/client/conversation-composer-presentation.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +2 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/mention-candidates.d.ts +46 -0
- package/lib/types/client/mention-candidates.d.ts.map +1 -0
- package/lib/types/client/navigation-cache.d.ts.map +1 -1
- package/lib/types/client/read-deadline.d.ts +3 -0
- package/lib/types/client/read-deadline.d.ts.map +1 -0
- package/lib/types/client/realtime-client-events.d.ts.map +1 -1
- package/lib/types/client/realtime-connection.d.ts +9 -0
- package/lib/types/client/realtime-connection.d.ts.map +1 -0
- package/lib/types/client/recordings/RecordingTranscriptForward.d.ts.map +1 -1
- package/lib/types/client/scan-guide-icons.d.ts +7 -0
- package/lib/types/client/scan-guide-icons.d.ts.map +1 -0
- package/lib/types/client/scan-guide-styles.d.ts +2 -0
- package/lib/types/client/scan-guide-styles.d.ts.map +1 -0
- package/lib/types/client/slots-contract.d.ts +23 -0
- package/lib/types/client/slots-contract.d.ts.map +1 -1
- package/lib/types/client/source-tree.d.ts.map +1 -1
- package/lib/types/client/use-call-record-preview.d.ts +8 -0
- package/lib/types/client/use-call-record-preview.d.ts.map +1 -0
- package/lib/types/client/use-call-transcript-playback.d.ts +13 -0
- package/lib/types/client/use-call-transcript-playback.d.ts.map +1 -0
- package/lib/types/dsh-agent-input-source.d.ts +0 -1
- package/lib/types/dsh-agent-input-source.d.ts.map +1 -1
- package/lib/types/extensions/profile-restart-helper.d.ts.map +1 -1
- package/lib/types/host-api.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/plugin-updater-helper.d.ts.map +1 -1
- package/lib/types/realtime-events.d.ts +9 -5
- package/lib/types/realtime-events.d.ts.map +1 -1
- package/lib/types/sdk/index.d.ts +4 -0
- package/lib/types/sdk/index.d.ts.map +1 -1
- package/lib/types/services/bot-conversation-service.d.ts.map +1 -1
- package/lib/types/services/bot-service.d.ts.map +1 -1
- package/lib/types/services/call-history-service.d.ts +3 -1
- package/lib/types/services/call-history-service.d.ts.map +1 -1
- package/lib/types/services/chat-service.d.ts +1 -0
- package/lib/types/services/chat-service.d.ts.map +1 -1
- package/lib/types/services/media-service.d.ts.map +1 -1
- package/lib/types/services/search-service.d.ts.map +1 -1
- package/lib/types/services/source-service.d.ts +4 -0
- package/lib/types/services/source-service.d.ts.map +1 -1
- package/lib/types/services/topic-metadata.d.ts +10 -0
- package/lib/types/services/topic-metadata.d.ts.map +1 -0
- package/lib/types/services/topic-record-page.d.ts +18 -0
- package/lib/types/services/topic-record-page.d.ts.map +1 -0
- package/lib/types/tools/business/conversation/index.d.ts.map +1 -1
- package/lib/types/tools/business/conversation/topic-home-visibility.d.ts +2 -0
- package/lib/types/tools/business/conversation/topic-home-visibility.d.ts.map +1 -0
- package/lib/types/tools/business/index.d.ts.map +1 -1
- package/lib/types/tools/ports/bots.d.ts +1 -0
- package/lib/types/tools/ports/bots.d.ts.map +1 -1
- package/lib/types/tools/ports/conversations.d.ts +3 -0
- package/lib/types/tools/ports/conversations.d.ts.map +1 -1
- package/lib/types/tools/registry/registrar.d.ts.map +1 -1
- package/lib/types/topic-policy.d.ts +9 -0
- package/lib/types/topic-policy.d.ts.map +1 -0
- package/lib/types/types.d.ts +22 -1
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -15558,6 +15558,48 @@ async function patchChatPolicy(runtime, session, chatSessionUid, patch, signal)
|
|
|
15558
15558
|
return updated;
|
|
15559
15559
|
}
|
|
15560
15560
|
//#endregion
|
|
15561
|
+
//#region src/services/topic-record-page.ts
|
|
15562
|
+
/** Transport contract shared by timeline reading and complete pre-dissolution enumeration.
|
|
15563
|
+
* Privacy visibility and mutation policy remain in their respective business owners.
|
|
15564
|
+
*/
|
|
15565
|
+
async function readTopicRecordPage(runtime, session, topicUid, options) {
|
|
15566
|
+
const data = await runtime.authenticatedPost("/api/v1/topics/display/records/page", {
|
|
15567
|
+
topic_uid: topicUid,
|
|
15568
|
+
limit: options.limit,
|
|
15569
|
+
...options.cursor === void 0 ? {} : {
|
|
15570
|
+
cursor_send_at: options.cursor.sendAtMillis,
|
|
15571
|
+
cursor_record_uid: options.cursor.itemUid
|
|
15572
|
+
}
|
|
15573
|
+
}, session, options.signal);
|
|
15574
|
+
const sendAt = data.next_cursor_send_at;
|
|
15575
|
+
const uid = stringValue$2(data.next_cursor_record_uid).trim();
|
|
15576
|
+
const hasCursor = typeof sendAt === "number" && Number.isSafeInteger(sendAt) && sendAt > 0 && uid !== "";
|
|
15577
|
+
if (data.topic_uid !== topicUid || !Array.isArray(data.records) || typeof data.has_more !== "boolean" || data.privacy_state !== 1 && data.privacy_state !== 2 || data.has_more && !hasCursor || data.records.some((raw) => stringValue$2(objectValue$2(raw).record_uid).trim() === "")) throw new ArkmePluginError("topic-record-page-invalid", "主题快记返回不完整,请重试或确认服务端已升级", true, 502);
|
|
15578
|
+
if (data.has_more && options.cursor !== void 0 && sendAt === options.cursor.sendAtMillis && uid === options.cursor.itemUid) throw new ArkmePluginError("topic-record-page-invalid", "主题快记分页未推进,请重试", true, 502);
|
|
15579
|
+
return {
|
|
15580
|
+
records: data.records,
|
|
15581
|
+
privacyState: data.privacy_state,
|
|
15582
|
+
hasMore: data.has_more,
|
|
15583
|
+
...hasCursor ? { nextCursor: {
|
|
15584
|
+
sendAtMillis: sendAt,
|
|
15585
|
+
itemUid: uid
|
|
15586
|
+
} } : {}
|
|
15587
|
+
};
|
|
15588
|
+
}
|
|
15589
|
+
//#endregion
|
|
15590
|
+
//#region src/services/topic-metadata.ts
|
|
15591
|
+
/** Lightweight topic identity/settings contract. It never loads records or summary statistics. */
|
|
15592
|
+
async function readTopicMetadata(runtime, session, topicUid, signal) {
|
|
15593
|
+
const core = objectValue$2((await runtime.authenticatedPost("/api/v1/topics/display/metadata", { topic_uid: topicUid }, session, signal)).topic_core);
|
|
15594
|
+
const topicKind = typeof core.kind === "number" ? core.kind : 0;
|
|
15595
|
+
if (stringValue$2(core.topic_uid).trim() !== topicUid || !Number.isSafeInteger(topicKind) || topicKind <= 0 || core.privacy_state !== 1 && core.privacy_state !== 2 || typeof core.show_in_home !== "boolean") throw new ArkmePluginError("topic-metadata-invalid", "主题信息返回不完整,请重试或确认服务端已升级", true, 502);
|
|
15596
|
+
return {
|
|
15597
|
+
topicKind,
|
|
15598
|
+
privacyState: core.privacy_state,
|
|
15599
|
+
showInHome: core.show_in_home
|
|
15600
|
+
};
|
|
15601
|
+
}
|
|
15602
|
+
//#endregion
|
|
15561
15603
|
//#region node_modules/bail/index.js
|
|
15562
15604
|
/**
|
|
15563
15605
|
* Throw a given error.
|
|
@@ -35063,6 +35105,17 @@ function arkmeEmojiPlainText(value) {
|
|
|
35063
35105
|
if (value === "" || !value.includes("_emoji:")) return value;
|
|
35064
35106
|
return arkmeEmojiTextRuns(value).map((run) => run.kind === "emoji" ? run.emoji.unicode : run.text).join("");
|
|
35065
35107
|
}
|
|
35108
|
+
const ARKME_DSH_INPUT_TOPIC_TITLE = "发给 DSH 的消息";
|
|
35109
|
+
/** Display only; source identities and stored titles remain unchanged. */
|
|
35110
|
+
function arkmeTopicDisplayName(title, topicKind) {
|
|
35111
|
+
return topicKind === 3 ? ARKME_DSH_INPUT_TOPIC_TITLE : title;
|
|
35112
|
+
}
|
|
35113
|
+
function isArkmeDSHInputTopic(source) {
|
|
35114
|
+
return source?.kind === "topic" && source.topicKind === 3;
|
|
35115
|
+
}
|
|
35116
|
+
function arkmeSourceAllowsUserWrite(source) {
|
|
35117
|
+
return !isArkmeDSHInputTopic(source);
|
|
35118
|
+
}
|
|
35066
35119
|
//#endregion
|
|
35067
35120
|
//#region src/services/source-service.ts
|
|
35068
35121
|
const SOURCE_LIST_CACHE_TTL_MS = 3e4;
|
|
@@ -35600,6 +35653,7 @@ var SourceService = class {
|
|
|
35600
35653
|
const topicUid = stringValue$2(created.topic_uid).trim();
|
|
35601
35654
|
if (topicUid === "" || numberValue$26(created.status) !== 1) throw new ArkmePluginError("topic-create-contract-invalid", "主题创建响应不完整", true, 502);
|
|
35602
35655
|
const sourceRef = await this.sealSourceRef(session.userId, "topic", topicUid, title);
|
|
35656
|
+
const topicHierarchyKey = await this.topicHierarchyKey(session.userId, topicUid);
|
|
35603
35657
|
if (parentTopicUid !== void 0) try {
|
|
35604
35658
|
if (numberValue$26(objectValue$2((await this.runtime.authenticatedPost("/api/v1/topics/hierarchy/bind", {
|
|
35605
35659
|
parent_topic_uid: parentTopicUid,
|
|
@@ -35620,6 +35674,7 @@ var SourceService = class {
|
|
|
35620
35674
|
return {
|
|
35621
35675
|
source: {
|
|
35622
35676
|
sourceRef,
|
|
35677
|
+
topicHierarchyKey,
|
|
35623
35678
|
kind: "topic",
|
|
35624
35679
|
displayName: title,
|
|
35625
35680
|
activeAtMillis: createdAtMillis,
|
|
@@ -35630,10 +35685,16 @@ var SourceService = class {
|
|
|
35630
35685
|
};
|
|
35631
35686
|
}
|
|
35632
35687
|
throw new ArkmePluginError("topic-hierarchy-bind-failed", "未能创建子主题,已自动清理,请重试", true, 409, { cause: bindError });
|
|
35688
|
+
} finally {
|
|
35689
|
+
this.invalidateSourceListCache(session.userId, "send_to_self");
|
|
35633
35690
|
}
|
|
35634
35691
|
return { source: {
|
|
35635
35692
|
sourceRef,
|
|
35636
|
-
|
|
35693
|
+
topicHierarchyKey,
|
|
35694
|
+
...parentSourceRef !== void 0 && parentTopicUid !== void 0 ? {
|
|
35695
|
+
parentSourceRef,
|
|
35696
|
+
parentTopicHierarchyKey: await this.topicHierarchyKey(session.userId, parentTopicUid)
|
|
35697
|
+
} : {},
|
|
35637
35698
|
kind: "topic",
|
|
35638
35699
|
displayName: title,
|
|
35639
35700
|
activeAtMillis: createdAtMillis,
|
|
@@ -35666,6 +35727,20 @@ var SourceService = class {
|
|
|
35666
35727
|
displayName: title
|
|
35667
35728
|
};
|
|
35668
35729
|
}
|
|
35730
|
+
/** Reuse the record owner's topic policy, without replaying title/privacy defaults. */
|
|
35731
|
+
async topicHomeVisibility(sourceRef, showInHome, signal) {
|
|
35732
|
+
const session = await this.runtime.requireSession();
|
|
35733
|
+
const topic = await this.openSourceRef(sourceRef, session.userId);
|
|
35734
|
+
if (topic.kind !== "topic") throw new ArkmePluginError("topic-policy-invalid", "请选择主题", false);
|
|
35735
|
+
if (showInHome === void 0) return { showInHome: (await readTopicMetadata(this.runtime, session, topic.ownerRef, signal)).showInHome };
|
|
35736
|
+
const value = (await this.runtime.authenticatedPost("/api/v1/topics/display/policy/set", {
|
|
35737
|
+
topic_uid: topic.ownerRef,
|
|
35738
|
+
show_in_home: showInHome
|
|
35739
|
+
}, session, void 0)).show_in_home;
|
|
35740
|
+
if (typeof value !== "boolean") throw new ArkmePluginError("topic-policy-contract-invalid", "主题设置响应不完整,请重试", true, 502);
|
|
35741
|
+
this.invalidateSourceListCache(session.userId, "send_to_self");
|
|
35742
|
+
return { showInHome: value };
|
|
35743
|
+
}
|
|
35669
35744
|
/**
|
|
35670
35745
|
* Dissolving a topic promotes its direct children and moves the topic's own
|
|
35671
35746
|
* records into its parent. Root-topic records return to the default category.
|
|
@@ -35764,21 +35839,18 @@ var SourceService = class {
|
|
|
35764
35839
|
let cursorSendAt;
|
|
35765
35840
|
let cursorRecordUid;
|
|
35766
35841
|
for (let pageIndex = 0; pageIndex < 1e3; pageIndex += 1) {
|
|
35767
|
-
const
|
|
35768
|
-
topic_uid: topicUid,
|
|
35842
|
+
const page = await readTopicRecordPage(this.runtime, session, topicUid, {
|
|
35769
35843
|
limit: 100,
|
|
35770
|
-
...cursorSendAt === void 0 ? {} : {
|
|
35771
|
-
|
|
35772
|
-
|
|
35773
|
-
|
|
35774
|
-
|
|
35775
|
-
|
|
35776
|
-
if (uid !== "") recordUids.add(uid);
|
|
35777
|
-
}
|
|
35844
|
+
...cursorSendAt === void 0 || cursorRecordUid === void 0 ? {} : { cursor: {
|
|
35845
|
+
sendAtMillis: cursorSendAt,
|
|
35846
|
+
itemUid: cursorRecordUid
|
|
35847
|
+
} }
|
|
35848
|
+
});
|
|
35849
|
+
for (const raw of page.records) recordUids.add(stringValue$2(objectValue$2(raw).record_uid).trim());
|
|
35778
35850
|
onProgress?.(recordUids.size);
|
|
35779
|
-
if (
|
|
35780
|
-
const nextSendAt =
|
|
35781
|
-
const nextRecordUid =
|
|
35851
|
+
if (!page.hasMore) return [...recordUids];
|
|
35852
|
+
const nextSendAt = page.nextCursor?.sendAtMillis ?? 0;
|
|
35853
|
+
const nextRecordUid = page.nextCursor?.itemUid ?? "";
|
|
35782
35854
|
const cursorKey = `${String(nextSendAt)}:${nextRecordUid}`;
|
|
35783
35855
|
if (nextSendAt <= 0 || nextRecordUid === "" || seenCursors.has(cursorKey)) throw new ArkmePluginError("topic-dissolve-record-page-invalid", "主题快记加载不完整,未解散主题,请刷新后重试", true, 502);
|
|
35784
35856
|
seenCursors.add(cursorKey);
|
|
@@ -35916,6 +35988,11 @@ var SourceService = class {
|
|
|
35916
35988
|
const entry = objectValue$2(raw);
|
|
35917
35989
|
const core = objectValue$2(entry.topic_core);
|
|
35918
35990
|
if (arkmePrivacyLockedTopic(entry) || core.status !== 1) continue;
|
|
35991
|
+
const topicKind = numberValue$26(core.kind) || 1;
|
|
35992
|
+
if (!arkmeSourceAllowsUserWrite({
|
|
35993
|
+
kind: "topic",
|
|
35994
|
+
topicKind
|
|
35995
|
+
})) continue;
|
|
35919
35996
|
const topicUid = stringValue$2(core.topic_uid).trim();
|
|
35920
35997
|
const title = stringValue$2(core.title).trim();
|
|
35921
35998
|
if (!topicUid || !title || seen.has(topicUid)) continue;
|
|
@@ -35923,6 +36000,7 @@ var SourceService = class {
|
|
|
35923
36000
|
const recordCount = objectValue$2(entry.summary).record_count;
|
|
35924
36001
|
items.push({
|
|
35925
36002
|
kind: "topic",
|
|
36003
|
+
topicKind,
|
|
35926
36004
|
displayName: title,
|
|
35927
36005
|
activeAtMillis: numberValue$26(core.update_at),
|
|
35928
36006
|
unreadCount: 0,
|
|
@@ -36113,6 +36191,7 @@ var SourceService = class {
|
|
|
36113
36191
|
const parentTopicUid = stringValue$2(parentTopicUidByChild.get(topicUid) ?? core.parent_topic_uid ?? core.parent_uid ?? item.parent_topic_uid ?? item.parent_uid ?? parent.topic_uid ?? parent.uid).trim();
|
|
36114
36192
|
topicDescriptors.push({
|
|
36115
36193
|
topicUid,
|
|
36194
|
+
topicKind: numberValue$26(core.kind) || 1,
|
|
36116
36195
|
...parentTopicUid === "" || parentTopicUid === topicUid ? {} : { parentTopicUid },
|
|
36117
36196
|
siblingOrder: numberValue$26(siblingOrderByChild.get(topicUid) ?? core.sibling_order ?? item.sibling_order),
|
|
36118
36197
|
title,
|
|
@@ -36139,7 +36218,8 @@ var SourceService = class {
|
|
|
36139
36218
|
...parentTopicHierarchyKey === void 0 ? {} : { parentTopicHierarchyKey },
|
|
36140
36219
|
...topic.siblingOrder > 0 ? { siblingOrder: topic.siblingOrder } : {},
|
|
36141
36220
|
kind: "topic",
|
|
36142
|
-
|
|
36221
|
+
topicKind: topic.topicKind,
|
|
36222
|
+
displayName: arkmeTopicDisplayName(topic.title, topic.topicKind),
|
|
36143
36223
|
...topic.latestPreview === "" ? {} : { latestPreview: topic.latestPreview },
|
|
36144
36224
|
activeAtMillis: topic.activeAtMillis,
|
|
36145
36225
|
unreadCount: 0,
|
|
@@ -36657,7 +36737,7 @@ function botConversationCapabilities(target, provider) {
|
|
|
36657
36737
|
const owner = target.kind === "subject" ? BOT_CONVERSATION_OWNER.subject : target.kind === "chat" ? BOT_CONVERSATION_OWNER.chat : void 0;
|
|
36658
36738
|
return {
|
|
36659
36739
|
directChatAvailable: owner !== void 0,
|
|
36660
|
-
privateChatOutboundEnabled: owner
|
|
36740
|
+
privateChatOutboundEnabled: owner !== void 0 && provider === "openclaw",
|
|
36661
36741
|
refreshOnRecordChanges: owner === BOT_CONVERSATION_OWNER.subject,
|
|
36662
36742
|
conversationProjection: owner === BOT_CONVERSATION_OWNER.subject ? "record" : owner === BOT_CONVERSATION_OWNER.chat ? "chat" : "none"
|
|
36663
36743
|
};
|
|
@@ -36746,10 +36826,18 @@ var BotService = class {
|
|
|
36746
36826
|
name,
|
|
36747
36827
|
provider,
|
|
36748
36828
|
description,
|
|
36749
|
-
avatar
|
|
36829
|
+
avatar,
|
|
36830
|
+
direct_chat_owner: BOT_CONVERSATION_OWNER.chat,
|
|
36831
|
+
request_uid: input.requestUid?.trim() || randomUUID()
|
|
36750
36832
|
}, session, options.signal);
|
|
36751
36833
|
} catch (error) {
|
|
36752
|
-
if (error instanceof ArkmePluginError && [
|
|
36834
|
+
if (error instanceof ArkmePluginError && ([
|
|
36835
|
+
"arkme-network-error",
|
|
36836
|
+
"arkme-timeout",
|
|
36837
|
+
"arkme-response-invalid",
|
|
36838
|
+
"arkme-code-1002"
|
|
36839
|
+
].includes(error.code) || error.code === "arkme-http-error" && error.retryable)) throw new ArkmePluginError("bot-create-outcome-unknown", "Bot 创建结果未知,请刷新 Bot 列表确认;不会自动重试", false, 409, { cause: error });
|
|
36840
|
+
if (error instanceof ArkmePluginError && error.code === "arkme-code-1001") throw new ArkmePluginError(error.code, error.message, false, 400, { cause: error });
|
|
36753
36841
|
throw error;
|
|
36754
36842
|
}
|
|
36755
36843
|
try {
|
|
@@ -37097,6 +37185,7 @@ var BotService = class {
|
|
|
37097
37185
|
const signature = createHmac("sha256", secret).update(`bot-directory-entry-v1:${userId}:${payload}`).digest("base64url");
|
|
37098
37186
|
return [{
|
|
37099
37187
|
...bot,
|
|
37188
|
+
privateChatOutboundEnabled: bot.directChatAvailable && bot.provider === "openclaw",
|
|
37100
37189
|
botRef: `arkme-bot-directory-entry-v1.${payload}.${signature}`
|
|
37101
37190
|
}];
|
|
37102
37191
|
});
|
|
@@ -37255,7 +37344,6 @@ var SubjectBotConversationAdapter = class {
|
|
|
37255
37344
|
async send(context, contentInput, signal) {
|
|
37256
37345
|
this.subjectTarget(context);
|
|
37257
37346
|
const content = contentInput.trim();
|
|
37258
|
-
if (context.reference.provider === "webhook") throw new ArkmePluginError("bot-conversation-send-unsupported", "Webhook Bot 仅接收外部系统推送", false, 400);
|
|
37259
37347
|
if (content === "" || content.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("bot-conversation-content-invalid", "Bot 消息为空或超过长度限制", false, 400);
|
|
37260
37348
|
let data;
|
|
37261
37349
|
try {
|
|
@@ -37408,6 +37496,7 @@ var BotConversationService = class {
|
|
|
37408
37496
|
}
|
|
37409
37497
|
async send(botRef, content, options = {}) {
|
|
37410
37498
|
const context = await this.context(botRef);
|
|
37499
|
+
if (context.reference.provider === "webhook") throw new ArkmePluginError("bot-conversation-send-unsupported", "Webhook Bot 仅接收外部系统推送", false, 400);
|
|
37411
37500
|
const result = await this.adapter(context).send(context, content, options.signal);
|
|
37412
37501
|
if (context.reference.target.kind === "subject") await this.invalidateRecordProjection();
|
|
37413
37502
|
return result;
|
|
@@ -37636,6 +37725,44 @@ function object(value) {
|
|
|
37636
37725
|
function first(source, keys) {
|
|
37637
37726
|
return keys.map((key) => source[key]).find((value) => value !== void 0 && value !== null && value !== "");
|
|
37638
37727
|
}
|
|
37728
|
+
/** Flutter-compatible summary templates, resolved on the host before projection. */
|
|
37729
|
+
function renderCallRecordSummary(source, viewerUserId, displayNames = /* @__PURE__ */ new Map()) {
|
|
37730
|
+
const fallback = String(first(source, [
|
|
37731
|
+
"sm",
|
|
37732
|
+
"call_summary",
|
|
37733
|
+
"callSummary",
|
|
37734
|
+
"summary_text",
|
|
37735
|
+
"summaryText",
|
|
37736
|
+
"summary"
|
|
37737
|
+
]) ?? "").trim();
|
|
37738
|
+
const template = String(first(source, [
|
|
37739
|
+
"smt",
|
|
37740
|
+
"call_summary_template",
|
|
37741
|
+
"callSummaryTemplate",
|
|
37742
|
+
"summary_template",
|
|
37743
|
+
"summaryTemplate"
|
|
37744
|
+
]) ?? "").trim();
|
|
37745
|
+
const labels = object(first(source, [
|
|
37746
|
+
"ssl",
|
|
37747
|
+
"summary_speaker_labels",
|
|
37748
|
+
"call_summary_speaker_labels"
|
|
37749
|
+
]));
|
|
37750
|
+
const users = object(first(source, [
|
|
37751
|
+
"ssu",
|
|
37752
|
+
"summary_speaker_user_ids",
|
|
37753
|
+
"call_summary_speaker_user_ids"
|
|
37754
|
+
]));
|
|
37755
|
+
const rendered = template.replace(/\{\{(user|speaker):([^{}]+)\}\}/g, (token, kind, key) => {
|
|
37756
|
+
const userId = Number(kind === "user" ? key : users[token] ?? users[key]);
|
|
37757
|
+
if (userId > 0 && userId === viewerUserId) return "我";
|
|
37758
|
+
const name = displayNames.get(userId);
|
|
37759
|
+
if (name?.trim()) return name.trim();
|
|
37760
|
+
const label = kind === "speaker" ? labels[token] ?? labels[key] : void 0;
|
|
37761
|
+
return typeof label === "string" && label.trim() ? label.trim() : token;
|
|
37762
|
+
});
|
|
37763
|
+
const text = rendered && !rendered.includes("{{") ? rendered : fallback;
|
|
37764
|
+
return text.includes("{{") ? "" : text;
|
|
37765
|
+
}
|
|
37639
37766
|
function callRecordCandidates(raw) {
|
|
37640
37767
|
const root = object(raw);
|
|
37641
37768
|
const record = object(root.record);
|
|
@@ -37769,9 +37896,27 @@ function projectCallRecord(raw, viewerUserId) {
|
|
|
37769
37896
|
text = isCaller ? "对方离线" : "未接听(离线)";
|
|
37770
37897
|
break;
|
|
37771
37898
|
}
|
|
37899
|
+
const summary = renderCallRecordSummary(source, viewerUserId);
|
|
37900
|
+
const rawStatus = String(first(source, [
|
|
37901
|
+
"ss",
|
|
37902
|
+
"call_summary_status",
|
|
37903
|
+
"summary_status",
|
|
37904
|
+
"summaryStatus"
|
|
37905
|
+
]) ?? "").toLowerCase();
|
|
37906
|
+
const summaryStatus = [
|
|
37907
|
+
"pending",
|
|
37908
|
+
"processing",
|
|
37909
|
+
"generating"
|
|
37910
|
+
].includes(rawStatus) ? "pending" : [
|
|
37911
|
+
"done",
|
|
37912
|
+
"success",
|
|
37913
|
+
"finished"
|
|
37914
|
+
].includes(rawStatus) ? "done" : ["failed", "error"].includes(rawStatus) ? "failed" : void 0;
|
|
37772
37915
|
return {
|
|
37773
37916
|
mediaType,
|
|
37774
|
-
text
|
|
37917
|
+
text,
|
|
37918
|
+
...summary && !summary.includes("{{") ? { summaryText: summary } : {},
|
|
37919
|
+
...summaryStatus ? { summaryStatus } : {}
|
|
37775
37920
|
};
|
|
37776
37921
|
}
|
|
37777
37922
|
//#endregion
|
|
@@ -38122,9 +38267,11 @@ function decodeJson(value) {
|
|
|
38122
38267
|
var CallHistoryService = class {
|
|
38123
38268
|
runtime;
|
|
38124
38269
|
profile;
|
|
38125
|
-
|
|
38270
|
+
media;
|
|
38271
|
+
constructor(runtime, profile, media) {
|
|
38126
38272
|
this.runtime = runtime;
|
|
38127
38273
|
this.profile = profile;
|
|
38274
|
+
this.media = media;
|
|
38128
38275
|
}
|
|
38129
38276
|
async listCallHistory(options = {}, signal) {
|
|
38130
38277
|
const session = await this.runtime.requireSession();
|
|
@@ -38467,13 +38614,6 @@ var CallHistoryService = class {
|
|
|
38467
38614
|
"callResult",
|
|
38468
38615
|
"result"
|
|
38469
38616
|
]);
|
|
38470
|
-
const summaryText = safeSummary(firstString$1(raw, [
|
|
38471
|
-
"call_summary",
|
|
38472
|
-
"callSummary",
|
|
38473
|
-
"summary_text",
|
|
38474
|
-
"summaryText",
|
|
38475
|
-
"summary"
|
|
38476
|
-
]));
|
|
38477
38617
|
const summaryUpdatedAtMillis = firstEpochMillis(raw, [
|
|
38478
38618
|
"call_summary_updated_at",
|
|
38479
38619
|
"callSummaryUpdatedAt",
|
|
@@ -38487,7 +38627,7 @@ var CallHistoryService = class {
|
|
|
38487
38627
|
"mediaType"
|
|
38488
38628
|
]));
|
|
38489
38629
|
const videoRecord = callVideoRecord(raw, mediaType, session.userId);
|
|
38490
|
-
const transcriptSegments = this.transcriptSegments(raw, startedAtMillis).slice(0, 200);
|
|
38630
|
+
const transcriptSegments = this.transcriptSegments(raw, startedAtMillis, session.userId).slice(0, 200);
|
|
38491
38631
|
const hangupUserId = callResult.toLowerCase().replace(/[_\s-]/g, "") === "normalend" ? listValue$19(raw.member_actions).map(objectValue$2).reverse().find((action) => firstString$1(action, ["action"]).toLowerCase() === "hangup" && firstNumber(action, ["user_id"]) > 0)?.user_id : void 0;
|
|
38492
38632
|
const participantSeeds = this.participants(raw, session.userId);
|
|
38493
38633
|
const userIds = [
|
|
@@ -38503,6 +38643,7 @@ var CallHistoryService = class {
|
|
|
38503
38643
|
...userId === session.userId ? { isCurrentUser: true } : {}
|
|
38504
38644
|
});
|
|
38505
38645
|
const participants = await this.attachParticipantAvatars(participantSeeds.slice(0, 50), session, signal);
|
|
38646
|
+
const summaryText = safeSummary(renderCallRecordSummary(raw, session.userId, new Map(participants.flatMap((participant) => participant.userId ? [[participant.userId, participant.displayName]] : []))));
|
|
38506
38647
|
const hangupParticipant = participants.find((participant) => participant.userId === numberValue$22(hangupUserId));
|
|
38507
38648
|
return {
|
|
38508
38649
|
callRef: await this.sealCallRef({
|
|
@@ -38583,7 +38724,7 @@ var CallHistoryService = class {
|
|
|
38583
38724
|
};
|
|
38584
38725
|
}).filter((item) => item !== void 0).slice(0, 50);
|
|
38585
38726
|
}
|
|
38586
|
-
transcriptSegments(raw, startedAtMillis) {
|
|
38727
|
+
transcriptSegments(raw, startedAtMillis, viewerUserId) {
|
|
38587
38728
|
return listValue$19(firstValue(raw, [
|
|
38588
38729
|
"segments",
|
|
38589
38730
|
"transcript_segments",
|
|
@@ -38601,6 +38742,13 @@ var CallHistoryService = class {
|
|
|
38601
38742
|
"segmentId",
|
|
38602
38743
|
"id"
|
|
38603
38744
|
]) || `segment-${String(index + 1)}`;
|
|
38745
|
+
const remoteAudioUrl = firstString$1(rawItem, ["audio_url", "audioUrl"]);
|
|
38746
|
+
const audioBlock = remoteAudioUrl ? this.media?.forwardContentBlocks([{
|
|
38747
|
+
type: 2,
|
|
38748
|
+
name: "通话片段",
|
|
38749
|
+
download_url: remoteAudioUrl
|
|
38750
|
+
}], viewerUserId).find((block) => block.kind === "audio") : void 0;
|
|
38751
|
+
const audioUrl = audioBlock ? `${this.runtime.config.routePath}/media?ref=${encodeURIComponent(audioBlock.mediaRef)}` : void 0;
|
|
38604
38752
|
const speakerUserId = Math.trunc(firstNumber(rawItem, [
|
|
38605
38753
|
"speaker_user_id",
|
|
38606
38754
|
"speakerUserId",
|
|
@@ -38625,6 +38773,7 @@ var CallHistoryService = class {
|
|
|
38625
38773
|
const absoluteEnd = end >= 1e11;
|
|
38626
38774
|
return {
|
|
38627
38775
|
segmentId,
|
|
38776
|
+
...audioUrl ? { audioUrl } : {},
|
|
38628
38777
|
speakerDisplayName: firstString$1(rawItem, [
|
|
38629
38778
|
"speaker_display_name",
|
|
38630
38779
|
"speakerDisplayName",
|
|
@@ -42673,6 +42822,8 @@ function arkmeRichContentPayload(input, normalizedTextContent, mentionPayload) {
|
|
|
42673
42822
|
}
|
|
42674
42823
|
const OFFICIAL_AUTHOR_USER_ID = 11;
|
|
42675
42824
|
const OFFICIAL_AUTHOR_FALLBACK_DISPLAY_NAME = "即我作者";
|
|
42825
|
+
const RESERVED_ASEN_BOT_UID = "asen";
|
|
42826
|
+
const RESERVED_ASEN_DISPLAY_NAME = "阿森";
|
|
42676
42827
|
const MAX_MESSAGE_COPY_LINK_ITEMS = 100;
|
|
42677
42828
|
const RECORD_UID_PATTERN$1 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
42678
42829
|
const CHAT_MEMBER_REF_PREFIX = "arkme-chat-member-v1";
|
|
@@ -43730,7 +43881,7 @@ var ChatService = class {
|
|
|
43730
43881
|
callHistory;
|
|
43731
43882
|
memberEvents;
|
|
43732
43883
|
favoriteStickerMutationTail = Promise.resolve();
|
|
43733
|
-
constructor(runtime, source, profile, media, record, bot, arko, aiPolish, realtime, privacy = new ArkmePrivacyVisibilityService(runtime), messageActions, callHistory = new CallHistoryService(runtime, profile)) {
|
|
43884
|
+
constructor(runtime, source, profile, media, record, bot, arko, aiPolish, realtime, privacy = new ArkmePrivacyVisibilityService(runtime), messageActions, callHistory = new CallHistoryService(runtime, profile, media)) {
|
|
43734
43885
|
this.runtime = runtime;
|
|
43735
43886
|
this.source = source;
|
|
43736
43887
|
this.profile = profile;
|
|
@@ -44369,14 +44520,13 @@ var ChatService = class {
|
|
|
44369
44520
|
}
|
|
44370
44521
|
if (source.kind === "topic") {
|
|
44371
44522
|
const lockedRecordUids = await this.privacy.lockedRecordUids(session, options.signal);
|
|
44372
|
-
const
|
|
44373
|
-
|
|
44374
|
-
limit
|
|
44375
|
-
|
|
44376
|
-
|
|
44377
|
-
|
|
44378
|
-
|
|
44379
|
-
const rawRecords = listValue$16(data.records).filter((raw) => !arkmePrivacyLockedRecord(raw) && !lockedRecordUids.has(this.record.recordUid(raw)));
|
|
44523
|
+
const [page, metadata] = await Promise.all([readTopicRecordPage(this.runtime, session, source.ownerRef, {
|
|
44524
|
+
...options,
|
|
44525
|
+
limit
|
|
44526
|
+
}), readTopicMetadata(this.runtime, session, source.ownerRef, options.signal)]);
|
|
44527
|
+
if (arkmePrivacyLockedTopic({ privacy_state: page.privacyState }) || metadata.privacyState === 2) throw new ArkmePluginError("topic-privacy-locked", "隐私锁主题不能在 Arkme 插件中查看", false, 403);
|
|
44528
|
+
const topicKind = metadata.topicKind;
|
|
44529
|
+
const rawRecords = page.records.filter((raw) => !arkmePrivacyLockedRecord(raw) && !lockedRecordUids.has(this.record.recordUid(raw)));
|
|
44380
44530
|
const media = await this.media.hydrateRecordMediaPage(rawRecords, session, options.signal);
|
|
44381
44531
|
const signingKey = await this.runtime.stateStore.uniqueCode();
|
|
44382
44532
|
const records = rawRecords.map((raw) => {
|
|
@@ -44388,16 +44538,15 @@ var ChatService = class {
|
|
|
44388
44538
|
});
|
|
44389
44539
|
return this.withRecordTopicAssignmentRef(source, item, session.userId, signingKey, numberValue$19(objectValue$2(raw).owner_user_id), source.ownerRef);
|
|
44390
44540
|
});
|
|
44391
|
-
const nextSendAt = numberValue$19(data.next_cursor_send_at);
|
|
44392
|
-
const nextUid = stringValue$2(data.next_cursor_record_uid).trim();
|
|
44393
44541
|
return {
|
|
44394
|
-
source:
|
|
44542
|
+
source: {
|
|
44543
|
+
...await this.source.sourceItem(source),
|
|
44544
|
+
topicKind,
|
|
44545
|
+
displayName: arkmeTopicDisplayName(source.displayName, topicKind)
|
|
44546
|
+
},
|
|
44395
44547
|
items: records.map((item) => this.withRecordMessageActionRef(source, item, session.userId, signingKey)),
|
|
44396
|
-
hasMore:
|
|
44397
|
-
...
|
|
44398
|
-
sendAtMillis: nextSendAt,
|
|
44399
|
-
itemUid: nextUid
|
|
44400
|
-
} } : {}
|
|
44548
|
+
hasMore: page.hasMore,
|
|
44549
|
+
...page.nextCursor === void 0 ? {} : { nextCursor: page.nextCursor }
|
|
44401
44550
|
};
|
|
44402
44551
|
}
|
|
44403
44552
|
const aiPolishDecorations = source.kind === "group_chat" && options.cursor === void 0 ? Promise.allSettled([this.aiPolish.queryGroupAiPolishConfig(source.ownerRef, session, options.signal), this.aiPolish.queryGroupAiPolishNotices(source.ownerRef, session, options.signal)]) : void 0;
|
|
@@ -44948,13 +45097,21 @@ var ChatService = class {
|
|
|
44948
45097
|
parent_record_uid: parentRecordUid,
|
|
44949
45098
|
limit: 100
|
|
44950
45099
|
}, session, signal);
|
|
44951
|
-
const projections =
|
|
45100
|
+
const projections = [];
|
|
45101
|
+
for (const child of listValue$16(data.children)) {
|
|
44952
45102
|
const extension = chatExtensionTreeItemFromData(child, parentRecordUid);
|
|
44953
|
-
|
|
44954
|
-
|
|
45103
|
+
if (extension === void 0) continue;
|
|
45104
|
+
const record = objectValue$2(objectValue$2(objectValue$2(child).item).record);
|
|
45105
|
+
const payload = objectValue$2(record.payload);
|
|
45106
|
+
const mentions = await this.timelineMentionTargets(record, payload, session.userId, chatSessionUid);
|
|
45107
|
+
projections.push({
|
|
45108
|
+
extension: mentions === void 0 ? extension : {
|
|
45109
|
+
...extension,
|
|
45110
|
+
mentions
|
|
45111
|
+
},
|
|
44955
45112
|
mediaRecord: chatExtensionMediaRecord(child, extension.recordUid)
|
|
44956
|
-
}
|
|
44957
|
-
}
|
|
45113
|
+
});
|
|
45114
|
+
}
|
|
44958
45115
|
const extensions = (await this.hydrateExtensionMedia(projections, session, signal)).sort((left, right) => right.sendAtMillis - left.sendAtMillis);
|
|
44959
45116
|
const extensionCount = Math.max(integerLikeValue(data.total), extensions.length);
|
|
44960
45117
|
return extensionCount <= 0 ? void 0 : {
|
|
@@ -45661,22 +45818,30 @@ var ChatService = class {
|
|
|
45661
45818
|
const leadingTrim = textFormat === "markdown" ? 0 : rawText.length - rawText.trimStart().length;
|
|
45662
45819
|
const uniqueRefs = [...new Set(inputs.map((input) => input.botRef.trim()))];
|
|
45663
45820
|
if (uniqueRefs.some((ref) => ref === "")) throw new ArkmePluginError("bot-mention-ref-invalid", "Bot mention 引用为空", false);
|
|
45664
|
-
const
|
|
45821
|
+
const requestedReservedAsen = uniqueRefs.some((ref) => ref.toLowerCase() === RESERVED_ASEN_BOT_UID);
|
|
45822
|
+
const regularRefs = uniqueRefs.filter((ref) => ref.toLowerCase() !== RESERVED_ASEN_BOT_UID);
|
|
45823
|
+
const references = await Promise.all(regularRefs.map(async (ref) => ({
|
|
45665
45824
|
ref,
|
|
45666
45825
|
value: await this.bot.openBotRef(ref, session.userId)
|
|
45667
45826
|
})));
|
|
45668
45827
|
const allowedByBotId = /* @__PURE__ */ new Map();
|
|
45828
|
+
const reservedAsen = requestedReservedAsen ? {
|
|
45829
|
+
bot_uid: RESERVED_ASEN_BOT_UID,
|
|
45830
|
+
display_name_snapshot: RESERVED_ASEN_DISPLAY_NAME
|
|
45831
|
+
} : void 0;
|
|
45669
45832
|
if (source.kind === "group_chat") {
|
|
45670
|
-
|
|
45671
|
-
|
|
45672
|
-
|
|
45673
|
-
|
|
45674
|
-
|
|
45675
|
-
|
|
45676
|
-
|
|
45677
|
-
|
|
45833
|
+
if (references.length > 0) {
|
|
45834
|
+
const groupBots = await this.bot.listMentionableGroupBots(source, session, signal);
|
|
45835
|
+
const requested = new Set(references.map((item) => item.value.botId));
|
|
45836
|
+
for (const { botId, name } of groupBots) {
|
|
45837
|
+
if (!requested.has(botId)) continue;
|
|
45838
|
+
allowedByBotId.set(botId, {
|
|
45839
|
+
bot_uid: botId,
|
|
45840
|
+
display_name_snapshot: name
|
|
45841
|
+
});
|
|
45842
|
+
}
|
|
45678
45843
|
}
|
|
45679
|
-
} else {
|
|
45844
|
+
} else if (references.length > 0) {
|
|
45680
45845
|
const bots = (await this.bot.listBots(signal === void 0 ? {} : { signal })).items;
|
|
45681
45846
|
const botNameByRef = new Map(bots.filter((bot) => bot.provider === "openclaw").map((bot) => [bot.botRef, bot.name]));
|
|
45682
45847
|
for (const reference of references) {
|
|
@@ -45692,8 +45857,9 @@ var ChatService = class {
|
|
|
45692
45857
|
const refToBotId = new Map(references.map((item) => [item.ref, item.value.botId]));
|
|
45693
45858
|
return [...inputs].sort((left, right) => left.startIndex - right.startIndex).map((input) => {
|
|
45694
45859
|
const botRef = input.botRef.trim();
|
|
45695
|
-
const
|
|
45696
|
-
const
|
|
45860
|
+
const isReservedAsen = botRef.toLowerCase() === RESERVED_ASEN_BOT_UID;
|
|
45861
|
+
const botId = isReservedAsen ? void 0 : refToBotId.get(botRef);
|
|
45862
|
+
const bot = isReservedAsen ? reservedAsen : botId === void 0 ? void 0 : allowedByBotId.get(botId);
|
|
45697
45863
|
if (bot === void 0) throw new ArkmePluginError("bot-mention-not-available", "所选 Bot 当前不可 mention", false, 409);
|
|
45698
45864
|
const startIndex = Math.trunc(input.startIndex) - leadingTrim;
|
|
45699
45865
|
const length = Math.trunc(input.length);
|
|
@@ -45708,29 +45874,48 @@ var ChatService = class {
|
|
|
45708
45874
|
});
|
|
45709
45875
|
}
|
|
45710
45876
|
async groupBotMentionSend(sourceRef, source, text, botRefs, recordUid, relationUid, session, signal, options = {}) {
|
|
45711
|
-
const
|
|
45877
|
+
const normalizedRefs = botRefs.map((ref) => {
|
|
45878
|
+
const normalized = ref.trim();
|
|
45879
|
+
return normalized.toLowerCase() === RESERVED_ASEN_BOT_UID ? RESERVED_ASEN_BOT_UID : normalized;
|
|
45880
|
+
});
|
|
45881
|
+
const uniqueRefs = new Set(normalizedRefs);
|
|
45712
45882
|
if (uniqueRefs.has("") || uniqueRefs.size !== botRefs.length) throw new ArkmePluginError("bot-mention-ref-invalid", "Bot mention 引用为空或重复", false);
|
|
45713
|
-
const
|
|
45883
|
+
const requestedReservedAsen = [...uniqueRefs].some((ref) => ref.toLowerCase() === RESERVED_ASEN_BOT_UID);
|
|
45884
|
+
const regularRefs = [...uniqueRefs].filter((ref) => ref.toLowerCase() !== RESERVED_ASEN_BOT_UID);
|
|
45885
|
+
const references = await Promise.all(regularRefs.map(async (ref) => ({
|
|
45714
45886
|
ref,
|
|
45715
45887
|
value: await this.bot.openBotRef(ref, session.userId)
|
|
45716
45888
|
})));
|
|
45717
45889
|
const requestedById = new Map(references.map((item) => [item.value.botId, item.ref]));
|
|
45718
45890
|
if (requestedById.size !== references.length) throw new ArkmePluginError("bot-mention-ref-invalid", "Bot mention 引用重复", false);
|
|
45719
|
-
const groupBots = await this.bot.listMentionableGroupBots(source, session, signal);
|
|
45720
45891
|
const mentions = [];
|
|
45721
45892
|
let visibleText = "";
|
|
45722
|
-
|
|
45723
|
-
|
|
45724
|
-
const
|
|
45893
|
+
if (requestedById.size > 0) {
|
|
45894
|
+
const groupBots = await this.bot.listMentionableGroupBots(source, session, signal);
|
|
45895
|
+
for (const { botId, name } of groupBots) {
|
|
45896
|
+
if (!requestedById.has(botId)) continue;
|
|
45897
|
+
const display = `@${name}`;
|
|
45898
|
+
const startIndex = visibleText.length;
|
|
45899
|
+
visibleText += `${display} `;
|
|
45900
|
+
mentions.push({
|
|
45901
|
+
bot_uid: botId,
|
|
45902
|
+
display_name_snapshot: name,
|
|
45903
|
+
start_index: startIndex,
|
|
45904
|
+
length: display.length
|
|
45905
|
+
});
|
|
45906
|
+
requestedById.delete(botId);
|
|
45907
|
+
}
|
|
45908
|
+
}
|
|
45909
|
+
if (requestedReservedAsen) {
|
|
45910
|
+
const display = `@${RESERVED_ASEN_DISPLAY_NAME}`;
|
|
45725
45911
|
const startIndex = visibleText.length;
|
|
45726
45912
|
visibleText += `${display} `;
|
|
45727
45913
|
mentions.push({
|
|
45728
|
-
bot_uid:
|
|
45729
|
-
display_name_snapshot:
|
|
45914
|
+
bot_uid: RESERVED_ASEN_BOT_UID,
|
|
45915
|
+
display_name_snapshot: RESERVED_ASEN_DISPLAY_NAME,
|
|
45730
45916
|
start_index: startIndex,
|
|
45731
45917
|
length: display.length
|
|
45732
45918
|
});
|
|
45733
|
-
requestedById.delete(botId);
|
|
45734
45919
|
}
|
|
45735
45920
|
if (requestedById.size > 0) throw new ArkmePluginError("bot-mention-not-installed", "所选 Bot 未安装到该群聊", false, 409);
|
|
45736
45921
|
visibleText += text;
|
|
@@ -46186,6 +46371,51 @@ var ChatService = class {
|
|
|
46186
46371
|
async chatSourceFromBundle(bundle, session, cached, timelineItems) {
|
|
46187
46372
|
return await this.source.chatSourceFromBundle(bundle, session, cached, timelineItems);
|
|
46188
46373
|
}
|
|
46374
|
+
async timelineMentionTargets(record, payload, viewerUserId, chatSessionUid) {
|
|
46375
|
+
const metadata = arkmeMentionMetadataFromRecord(record, payload);
|
|
46376
|
+
const targets = [];
|
|
46377
|
+
for (const rawMention of listValue$16(metadata.human_mentions ?? metadata.humanMentions)) {
|
|
46378
|
+
const mention = objectValue$2(rawMention);
|
|
46379
|
+
const startIndex = integerLikeValue(mention.start_index ?? mention.startIndex);
|
|
46380
|
+
const length = integerLikeValue(mention.length);
|
|
46381
|
+
const displayName = stringValue$2(mention.display_name_snapshot ?? mention.displayNameSnapshot).trim();
|
|
46382
|
+
const userId = integerLikeValue(mention.user_id ?? mention.userId);
|
|
46383
|
+
if (startIndex < 0 || length < 2 || displayName === "") continue;
|
|
46384
|
+
if (userId === 0) {
|
|
46385
|
+
targets.push({
|
|
46386
|
+
kind: "all",
|
|
46387
|
+
startIndex,
|
|
46388
|
+
length,
|
|
46389
|
+
displayName
|
|
46390
|
+
});
|
|
46391
|
+
continue;
|
|
46392
|
+
}
|
|
46393
|
+
if (userId > 0) targets.push({
|
|
46394
|
+
kind: "member",
|
|
46395
|
+
startIndex,
|
|
46396
|
+
length,
|
|
46397
|
+
displayName,
|
|
46398
|
+
memberRef: await this.sealChatMemberRef(viewerUserId, chatSessionUid, userId)
|
|
46399
|
+
});
|
|
46400
|
+
}
|
|
46401
|
+
for (const rawMention of listValue$16(metadata.bot_mentions ?? metadata.botMentions)) {
|
|
46402
|
+
const mention = objectValue$2(rawMention);
|
|
46403
|
+
const startIndex = integerLikeValue(mention.start_index ?? mention.startIndex);
|
|
46404
|
+
const length = integerLikeValue(mention.length);
|
|
46405
|
+
const displayName = stringValue$2(mention.display_name_snapshot ?? mention.displayNameSnapshot).trim();
|
|
46406
|
+
const botRef = stringValue$2(mention.bot_uid ?? mention.botUid).trim();
|
|
46407
|
+
if (startIndex < 0 || length < 2 || displayName === "" || botRef === "") continue;
|
|
46408
|
+
targets.push({
|
|
46409
|
+
kind: "bot",
|
|
46410
|
+
startIndex,
|
|
46411
|
+
length,
|
|
46412
|
+
displayName,
|
|
46413
|
+
botRef
|
|
46414
|
+
});
|
|
46415
|
+
}
|
|
46416
|
+
targets.sort((left, right) => left.startIndex - right.startIndex);
|
|
46417
|
+
return targets.length === 0 ? void 0 : targets;
|
|
46418
|
+
}
|
|
46189
46419
|
async chatTimelineItems(data, session, chatSessionUid, projectedSourceKind) {
|
|
46190
46420
|
const items = [];
|
|
46191
46421
|
const signingKey = await this.runtime.stateStore.uniqueCode();
|
|
@@ -46220,6 +46450,7 @@ var ChatService = class {
|
|
|
46220
46450
|
const conversationPreview = arkmeChatConversationPreview(item);
|
|
46221
46451
|
const callRecord = await this.callHistory.timelineCallRecord(item, session.userId);
|
|
46222
46452
|
const senderName = stringValue$2(relation.display_name_snapshot).trim() || "Arkme用户";
|
|
46453
|
+
const mentions = await this.timelineMentionTargets(record, payload, session.userId, chatSessionUid);
|
|
46223
46454
|
const mentionsViewer = senderUserId !== session.userId && arkmeMentionMetadataMentionsViewer(record, payload, session.userId);
|
|
46224
46455
|
items.push({
|
|
46225
46456
|
itemUid: uid,
|
|
@@ -46254,6 +46485,7 @@ var ChatService = class {
|
|
|
46254
46485
|
isMe: senderUserId === session.userId,
|
|
46255
46486
|
...callRecord === void 0 ? {} : { callRecord },
|
|
46256
46487
|
...mentionsViewer ? { mentionsViewer: true } : {},
|
|
46488
|
+
...mentions === void 0 ? {} : { mentions },
|
|
46257
46489
|
sendAtMillis,
|
|
46258
46490
|
title: stringValue$2(payload.title),
|
|
46259
46491
|
textContent: stringValue$2(payload.text_content),
|
|
@@ -46856,6 +47088,7 @@ var ChatService = class {
|
|
|
46856
47088
|
const contentBlocks = this.media.richContentBlocks(item, session.userId);
|
|
46857
47089
|
const extensionProjection = this.timelineExtensionProjection(item, session.userId);
|
|
46858
47090
|
const senderName = stringValue$2(relation.display_name_snapshot).trim() || "Arkme用户";
|
|
47091
|
+
const mentions = await this.timelineMentionTargets(record, payload, session.userId, source.ownerRef);
|
|
46859
47092
|
const captureContext = timelineCaptureContext({
|
|
46860
47093
|
...record,
|
|
46861
47094
|
...payload
|
|
@@ -46894,6 +47127,7 @@ var ChatService = class {
|
|
|
46894
47127
|
...agentSource === void 0 ? {} : { agentSource },
|
|
46895
47128
|
isMe: senderUserId === session.userId,
|
|
46896
47129
|
...callRecord === void 0 ? {} : { callRecord },
|
|
47130
|
+
...mentions === void 0 ? {} : { mentions },
|
|
46897
47131
|
sendAtMillis,
|
|
46898
47132
|
title: stringValue$2(payload.title),
|
|
46899
47133
|
textContent: stringValue$2(payload.text_content),
|
|
@@ -78979,6 +79213,10 @@ function allowedSignedImageHost$2(environment, hostname) {
|
|
|
78979
79213
|
function allowedSignedAudioHost(environment, hostname) {
|
|
78980
79214
|
return (environment === "prod" ? ["jotmo-useraudio.oss-cn-hangzhou.aliyuncs.com"] : ["jotmo-useraudio-test.oss-cn-hangzhou.aliyuncs.com"]).includes(hostname.toLowerCase());
|
|
78981
79215
|
}
|
|
79216
|
+
/** Call transcript clips use a separate COS bucket, not the user-audio OSS bucket. */
|
|
79217
|
+
function allowedSignedCallAudioHost(environment, hostname) {
|
|
79218
|
+
return environment === "prod" && hostname.toLowerCase() === "webrtc-record-prod-1403070603.cos.ap-shanghai.myqcloud.com";
|
|
79219
|
+
}
|
|
78982
79220
|
/** Record audio can originate from the dedicated audio or generic file bucket. */
|
|
78983
79221
|
function allowedSignedRecordAudioHost(environment, hostname) {
|
|
78984
79222
|
return allowedSignedAudioHost(environment, hostname) || allowedSignedImageHost$2(environment, hostname);
|
|
@@ -79248,7 +79486,7 @@ var MediaService = class {
|
|
|
79248
79486
|
}
|
|
79249
79487
|
if (originalOnly && descriptor.purpose !== "original") throw new ArkmePluginError("original-unavailable", "原文件不可用,请刷新后重试;不会用预览图代替原文件", false, 404);
|
|
79250
79488
|
const url = new URL(descriptor.remoteUrl);
|
|
79251
|
-
if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || !(allowedSignedImageHost$2(this.runtime.config.environment, url.hostname) || allowedSignedAudioHost(this.runtime.config.environment, url.hostname))) throw new ArkmePluginError("media-host-rejected", "媒体来源不受信任", false, 403);
|
|
79489
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.port !== "" || url.hash !== "" || !(allowedSignedImageHost$2(this.runtime.config.environment, url.hostname) || allowedSignedAudioHost(this.runtime.config.environment, url.hostname) || allowedSignedCallAudioHost(this.runtime.config.environment, url.hostname))) throw new ArkmePluginError("media-host-rejected", "媒体来源不受信任", false, 403);
|
|
79252
79490
|
const response = await this.runtime.fetchImpl(url, {
|
|
79253
79491
|
headers: range === void 0 ? {} : { Range: range },
|
|
79254
79492
|
redirect: "error",
|
|
@@ -79745,7 +79983,7 @@ var MediaService = class {
|
|
|
79745
79983
|
const value = safeHttpsUrl(raw);
|
|
79746
79984
|
if (value === void 0) return void 0;
|
|
79747
79985
|
const url = new URL(value);
|
|
79748
|
-
return url.port === "" && url.hash === "" && (allowedSignedImageHost$2(this.runtime.config.environment, url.hostname) || allowedSignedAudioHost(this.runtime.config.environment, url.hostname)) ? value : void 0;
|
|
79986
|
+
return url.port === "" && url.hash === "" && (allowedSignedImageHost$2(this.runtime.config.environment, url.hostname) || allowedSignedAudioHost(this.runtime.config.environment, url.hostname) || allowedSignedCallAudioHost(this.runtime.config.environment, url.hostname)) ? value : void 0;
|
|
79749
79987
|
};
|
|
79750
79988
|
const downloadUrl = trustedUrl(file.download_url ?? file.downloadUrl);
|
|
79751
79989
|
const previewUrl = trustedUrl(file.preview_url ?? file.previewUrl);
|
|
@@ -84236,10 +84474,6 @@ var RelatedRecordingService = class {
|
|
|
84236
84474
|
return `arkme-shared-recording-detail-v1.${encoded}.${createHmac("sha256", signingKey).update(encoded).digest("base64url")}`;
|
|
84237
84475
|
}
|
|
84238
84476
|
};
|
|
84239
|
-
function isDshAgentInputSourceTitle(value) {
|
|
84240
|
-
const normalized = value?.trim().toLowerCase();
|
|
84241
|
-
return normalized === "dsh agent input" || normalized === "DSH Agent 输入".toLowerCase();
|
|
84242
|
-
}
|
|
84243
84477
|
//#endregion
|
|
84244
84478
|
//#region src/services/search-service.ts
|
|
84245
84479
|
function numberValue$2(value) {
|
|
@@ -84624,7 +84858,6 @@ var SearchService = class {
|
|
|
84624
84858
|
const linkMatch = textContent.match(/https:\/\/[^\s<>()]+/u);
|
|
84625
84859
|
const sourceTitle = stringValue$2(topic.title ?? chat.title).trim();
|
|
84626
84860
|
const creationSource = Math.trunc(numberValue$2(core.creation_source ?? item.creation_source));
|
|
84627
|
-
const normalizedCreationSource = creationSource > 0 ? creationSource : isDshAgentInputSourceTitle(sourceTitle) ? 3 : 0;
|
|
84628
84861
|
return {
|
|
84629
84862
|
recordUid,
|
|
84630
84863
|
sourceKind: Math.trunc(numberValue$2(item.source_kind)),
|
|
@@ -84638,7 +84871,7 @@ var SearchService = class {
|
|
|
84638
84871
|
...stringValue$2(core.nickname).trim() === "" ? {} : { nickname: stringValue$2(core.nickname).trim() },
|
|
84639
84872
|
...numberValue$2(core.template_kind) <= 0 ? {} : { templateKind: Math.trunc(numberValue$2(core.template_kind)) },
|
|
84640
84873
|
...numberValue$2(core.display_kind) <= 0 ? {} : { displayKind: Math.trunc(numberValue$2(core.display_kind)) },
|
|
84641
|
-
...
|
|
84874
|
+
...creationSource <= 0 ? {} : { creationSource },
|
|
84642
84875
|
...sourceTitle === "" ? {} : { sourceTitle },
|
|
84643
84876
|
media,
|
|
84644
84877
|
files,
|
|
@@ -88296,7 +88529,7 @@ var ArkmeService = class {
|
|
|
88296
88529
|
this.calendar = new CalendarService(this.runtime, this.privacy);
|
|
88297
88530
|
this.wechat = new WechatService(this.runtime);
|
|
88298
88531
|
this.profile = new ProfileService(this.runtime);
|
|
88299
|
-
this.callHistory = new CallHistoryService(this.runtime, this.profile);
|
|
88532
|
+
this.callHistory = new CallHistoryService(this.runtime, this.profile, { forwardContentBlocks: (files, viewerUserId) => this.media.forwardContentBlocks(files, viewerUserId) });
|
|
88300
88533
|
this.extensionReview = new ExtensionReviewService(this.runtime, this.profile, { createTextForConversation: async (recordUid, textContent) => {
|
|
88301
88534
|
return await this.createTextForConversation(recordUid, textContent);
|
|
88302
88535
|
} });
|
|
@@ -88635,6 +88868,7 @@ var ArkmeService = class {
|
|
|
88635
88868
|
imageLibrary: true,
|
|
88636
88869
|
sourceDirectory: true,
|
|
88637
88870
|
localFirstDirectory: true,
|
|
88871
|
+
topicHomeVisibility: true,
|
|
88638
88872
|
contactDirectoryReads: true,
|
|
88639
88873
|
sourceTimeline: true,
|
|
88640
88874
|
forwardContent: true,
|
|
@@ -88992,6 +89226,11 @@ var ArkmeService = class {
|
|
|
88992
89226
|
async renameTopic(sourceRef, title) {
|
|
88993
89227
|
return await this.source.renameTopic(sourceRef, title);
|
|
88994
89228
|
}
|
|
89229
|
+
async topicHomeVisibility(sourceRef, showInHome, signal) {
|
|
89230
|
+
const result = await this.source.topicHomeVisibility(sourceRef, showInHome, signal);
|
|
89231
|
+
if (showInHome !== void 0) await this.realtime.invalidateRecordProjection();
|
|
89232
|
+
return result;
|
|
89233
|
+
}
|
|
88995
89234
|
async dissolveTopic(sourceRef, parentSourceRef, childSourceRefs, requestId, expectedRecordCount) {
|
|
88996
89235
|
return await this.source.dissolveTopic(sourceRef, parentSourceRef, childSourceRefs, requestId, expectedRecordCount);
|
|
88997
89236
|
}
|