@senguoyun/dsh-arkme 0.1.13 → 0.1.14

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.
Files changed (129) hide show
  1. package/docs/consumer-plugin-contract.md +3 -1
  2. package/docs/extension-market-controls.md +46 -7
  3. package/docs/gui-production-integration.md +10 -9
  4. package/lib/client.js +43662 -46867
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +455 -315
  7. package/lib/persistent-extension.js +1 -1
  8. package/lib/{persistent-runtime-Cki0XC3L.js → persistent-runtime-BAArZI-P.js} +467 -96
  9. package/lib/sdk.js +51 -15
  10. package/lib/types/arkme-service.d.ts +14 -9
  11. package/lib/types/arkme-service.d.ts.map +1 -1
  12. package/lib/types/bot-avatar-ref.d.ts +3 -0
  13. package/lib/types/bot-avatar-ref.d.ts.map +1 -0
  14. package/lib/types/client/ArkmeBotCreateDialog.d.ts +6 -0
  15. package/lib/types/client/ArkmeBotCreateDialog.d.ts.map +1 -0
  16. package/lib/types/client/ArkmeCalendarSurface.d.ts +4 -1
  17. package/lib/types/client/ArkmeCalendarSurface.d.ts.map +1 -1
  18. package/lib/types/client/ArkmeConversationSurface.d.ts +8 -18
  19. package/lib/types/client/ArkmeConversationSurface.d.ts.map +1 -1
  20. package/lib/types/client/ArkmeExtensionPublishDialog.d.ts.map +1 -1
  21. package/lib/types/client/ArkmeFooterDropdown.d.ts.map +1 -1
  22. package/lib/types/client/ArkmeLogin.d.ts.map +1 -1
  23. package/lib/types/client/ArkmeMarketplace.d.ts +14 -3
  24. package/lib/types/client/ArkmeMarketplace.d.ts.map +1 -1
  25. package/lib/types/client/ArkmePersistentShell.d.ts +20 -0
  26. package/lib/types/client/ArkmePersistentShell.d.ts.map +1 -0
  27. package/lib/types/client/ArkmeProductNavigation.d.ts +4 -3
  28. package/lib/types/client/ArkmeProductNavigation.d.ts.map +1 -1
  29. package/lib/types/client/ArkmeQuickAdd.d.ts.map +1 -1
  30. package/lib/types/client/ArkmeRecordingSurface.d.ts +3 -109
  31. package/lib/types/client/ArkmeRecordingSurface.d.ts.map +1 -1
  32. package/lib/types/client/ArkmeSettingsRow.d.ts +1 -1
  33. package/lib/types/client/ArkmeSettingsRow.d.ts.map +1 -1
  34. package/lib/types/client/ArkmeSettingsSurface.d.ts +4 -1
  35. package/lib/types/client/ArkmeSettingsSurface.d.ts.map +1 -1
  36. package/lib/types/client/ArkmeSidebar.d.ts +7 -1
  37. package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
  38. package/lib/types/client/ArkmeStartupAuthGate.d.ts.map +1 -1
  39. package/lib/types/client/ArkmeVirtualWorkspace.d.ts +8 -9
  40. package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
  41. package/lib/types/client/ArkmeWorldSurface.d.ts +63 -4
  42. package/lib/types/client/ArkmeWorldSurface.d.ts.map +1 -1
  43. package/lib/types/client/DeepSeekHarnessSurface.d.ts +6 -0
  44. package/lib/types/client/DeepSeekHarnessSurface.d.ts.map +1 -0
  45. package/lib/types/client/api.d.ts +1 -1
  46. package/lib/types/client/api.d.ts.map +1 -1
  47. package/lib/types/client/arkme-emoji.d.ts +3 -0
  48. package/lib/types/client/arkme-emoji.d.ts.map +1 -0
  49. package/lib/types/client/index.d.ts +6 -4
  50. package/lib/types/client/index.d.ts.map +1 -1
  51. package/lib/types/client/redesign/ArkmeRootFrame.d.ts +19 -0
  52. package/lib/types/client/redesign/ArkmeRootFrame.d.ts.map +1 -0
  53. package/lib/types/client/redesign/ArkmeTaskSurface.d.ts +15 -0
  54. package/lib/types/client/redesign/ArkmeTaskSurface.d.ts.map +1 -0
  55. package/lib/types/client/redesign/ArkmeWorkspaceDialog.d.ts +9 -0
  56. package/lib/types/client/redesign/ArkmeWorkspaceDialog.d.ts.map +1 -0
  57. package/lib/types/client/redesign/layout-controller.d.ts +17 -0
  58. package/lib/types/client/redesign/layout-controller.d.ts.map +1 -0
  59. package/lib/types/client/redesign/styles.d.ts +3 -0
  60. package/lib/types/client/redesign/styles.d.ts.map +1 -0
  61. package/lib/types/client/redesign/task-session.d.ts +14 -0
  62. package/lib/types/client/redesign/task-session.d.ts.map +1 -0
  63. package/lib/types/client/redesign/theme-presenter.d.ts +10 -0
  64. package/lib/types/client/redesign/theme-presenter.d.ts.map +1 -0
  65. package/lib/types/client/slots-contract.d.ts +2 -2
  66. package/lib/types/client/slots-contract.d.ts.map +1 -1
  67. package/lib/types/client/ui-controller.d.ts +19 -9
  68. package/lib/types/client/ui-controller.d.ts.map +1 -1
  69. package/lib/types/client/world-voiceprint-expectation-copy.d.ts +7 -0
  70. package/lib/types/client/world-voiceprint-expectation-copy.d.ts.map +1 -0
  71. package/lib/types/extensions/manager.d.ts +3 -0
  72. package/lib/types/extensions/manager.d.ts.map +1 -1
  73. package/lib/types/extensions/owned-inventory.d.ts +27 -1
  74. package/lib/types/extensions/owned-inventory.d.ts.map +1 -1
  75. package/lib/types/extensions/owned-refs.d.ts +1 -0
  76. package/lib/types/extensions/owned-refs.d.ts.map +1 -1
  77. package/lib/types/extensions/owned-store.d.ts +8 -0
  78. package/lib/types/extensions/owned-store.d.ts.map +1 -1
  79. package/lib/types/extensions/publisher-role.d.ts +9 -0
  80. package/lib/types/extensions/publisher-role.d.ts.map +1 -0
  81. package/lib/types/extensions/types.d.ts +11 -0
  82. package/lib/types/extensions/types.d.ts.map +1 -1
  83. package/lib/types/host-api.d.ts.map +1 -1
  84. package/lib/types/index.d.ts +2 -2
  85. package/lib/types/index.d.ts.map +1 -1
  86. package/lib/types/outgoing-call-assets.d.ts.map +1 -1
  87. package/lib/types/recording-presentation.d.ts +2 -2
  88. package/lib/types/recording-presentation.d.ts.map +1 -1
  89. package/lib/types/sdk/index.d.ts +22 -8
  90. package/lib/types/sdk/index.d.ts.map +1 -1
  91. package/lib/types/services/bot-service.d.ts.map +1 -1
  92. package/lib/types/services/record-service.d.ts +2 -1
  93. package/lib/types/services/record-service.d.ts.map +1 -1
  94. package/lib/types/services/recording-service.d.ts +2 -4
  95. package/lib/types/services/recording-service.d.ts.map +1 -1
  96. package/lib/types/services/world-service.d.ts +40 -6
  97. package/lib/types/services/world-service.d.ts.map +1 -1
  98. package/lib/types/tools/business/bots/create.d.ts.map +1 -1
  99. package/lib/types/tools/business/index.d.ts.map +1 -1
  100. package/lib/types/tools/business/recordings/index.d.ts +1 -2
  101. package/lib/types/tools/business/recordings/index.d.ts.map +1 -1
  102. package/lib/types/tools/business/world/index.d.ts +2 -0
  103. package/lib/types/tools/business/world/index.d.ts.map +1 -1
  104. package/lib/types/tools/business/world/user.d.ts +2 -0
  105. package/lib/types/tools/business/world/user.d.ts.map +1 -0
  106. package/lib/types/tools/business/world/voiceprint-social-context.d.ts +2 -0
  107. package/lib/types/tools/business/world/voiceprint-social-context.d.ts.map +1 -0
  108. package/lib/types/tools/extensions/index.d.ts.map +1 -1
  109. package/lib/types/tools/ports/recordings.d.ts +2 -3
  110. package/lib/types/tools/ports/recordings.d.ts.map +1 -1
  111. package/lib/types/tools/ports/world.d.ts +10 -1
  112. package/lib/types/tools/ports/world.d.ts.map +1 -1
  113. package/lib/types/tools/prompts/business.d.ts.map +1 -1
  114. package/lib/types/types.d.ts +39 -16
  115. package/lib/types/types.d.ts.map +1 -1
  116. package/package.json +7 -4
  117. package/assets/desktop_call/avatar-lin-xiaoman.jpeg +0 -0
  118. package/assets/desktop_call/avatar-mother.jpg +0 -0
  119. package/assets/desktop_call/avatar-self.png +0 -0
  120. package/assets/desktop_call/call-add-linear.svg +0 -13
  121. package/assets/desktop_call/icon-scan-add-contact.svg +0 -4
  122. package/assets/desktop_call/profile-circle-linear.svg +0 -11
  123. package/assets/desktop_call/user-add-linear.svg +0 -15
  124. package/lib/types/client/ArkmeCallHistorySurface.d.ts +0 -57
  125. package/lib/types/client/ArkmeCallHistorySurface.d.ts.map +0 -1
  126. package/lib/types/client/demo-audio.d.ts +0 -2
  127. package/lib/types/client/demo-audio.d.ts.map +0 -1
  128. package/lib/types/client/personal-test-edition.d.ts +0 -17
  129. package/lib/types/client/personal-test-edition.d.ts.map +0 -1
@@ -2454,6 +2454,13 @@ var AuthService = class {
2454
2454
  }
2455
2455
  };
2456
2456
  //#endregion
2457
+ //#region src/bot-avatar-ref.ts
2458
+ const ARKME_BOT_AVATAR_REF_PATTERN = /^file_asset:\/\/[A-Za-z0-9_-]{8,128}$/;
2459
+ /** Bot avatars cross process boundaries only as account-scoped file asset references. */
2460
+ function isArkmeBotAvatarRef(value) {
2461
+ return ARKME_BOT_AVATAR_REF_PATTERN.test(value.trim());
2462
+ }
2463
+ //#endregion
2457
2464
  //#region src/secret-value.ts
2458
2465
  var SecretValue = class {
2459
2466
  #value;
@@ -2528,6 +2535,7 @@ var BotService = class {
2528
2535
  const avatar = input.avatar?.trim() ?? "";
2529
2536
  if (name === "") throw new ArkmePluginError("bot-name-invalid", "Bot 名称不能为空", false);
2530
2537
  if (provider !== "openclaw" && provider !== "webhook") throw new ArkmePluginError("bot-provider-unsupported", "Bot Provider 不受支持", false, 400);
2538
+ if (avatar !== "" && !isArkmeBotAvatarRef(avatar)) throw new ArkmePluginError("bot-avatar-invalid", "Bot 头像引用无效", false, 400);
2531
2539
  const session = await this.runtime.requireSession();
2532
2540
  let data;
2533
2541
  try {
@@ -7389,6 +7397,43 @@ var RecordService = class {
7389
7397
  };
7390
7398
  }
7391
7399
  }
7400
+ async createFileAssetsForConversation(recordUid, textContent, assets) {
7401
+ const session = await this.runtime.requireSession();
7402
+ const normalizedUid = recordUid.trim();
7403
+ const normalizedText = textContent.trim();
7404
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(normalizedUid)) throw new ArkmePluginError("record-uid-invalid", "写入标识无效,请重试", false);
7405
+ if (assets.length === 0 || assets.length > 20 || normalizedText.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("record-file-assets-invalid", "附件内容为空、过长或数量超限", false);
7406
+ for (const asset of assets) if (!/^[A-Za-z0-9._:-]{8,256}$/.test(asset.fileAssetUid) || asset.fileName.trim() === "" || asset.fileName.length > 255 || !Number.isSafeInteger(asset.size) || asset.size <= 0 || ![
7407
+ 1,
7408
+ 2,
7409
+ 3,
7410
+ 4
7411
+ ].includes(asset.fileKind)) throw new ArkmePluginError("record-file-asset-invalid", "附件资产参数无效", false);
7412
+ const data = await this.runtime.authenticatedPost("/api/v1/records/create", {
7413
+ record_uid: normalizedUid,
7414
+ template_kind: 2,
7415
+ display_kind: 0,
7416
+ title: "",
7417
+ text_content: normalizedText,
7418
+ content_payload: {
7419
+ payload_kind: 2,
7420
+ schema_version: 1,
7421
+ text_state: normalizedText === "" ? 3 : 1,
7422
+ media_refs: assets.map((asset, index) => ({
7423
+ file_asset_uid: asset.fileAssetUid,
7424
+ content_file_role: 1,
7425
+ render_role: 1,
7426
+ sort_order: index,
7427
+ file_name: asset.fileName
7428
+ }))
7429
+ },
7430
+ send_at: Date.now()
7431
+ }, session);
7432
+ return {
7433
+ recordUid: stringValue$1(data.record_uid).trim() || normalizedUid,
7434
+ status: numberValue$7(data.status)
7435
+ };
7436
+ }
7392
7437
  async pendingWrites() {
7393
7438
  const session = await this.runtime.requireSession();
7394
7439
  return await this.runtime.stateStore.listPending(session.userId);
@@ -7532,7 +7577,7 @@ function displayTimestamp(value) {
7532
7577
  const parsed = Date.parse(stringValue(value));
7533
7578
  return Number.isFinite(parsed) ? parsed : 0;
7534
7579
  }
7535
- function projectRecordingTranscripts(response, speakerResponse, source = "system") {
7580
+ function projectRecordingTranscripts(response, speakerResponse) {
7536
7581
  const data = objectValue(response);
7537
7582
  const sessions = /* @__PURE__ */ new Map();
7538
7583
  const sessionSpeakerColorIndexes = /* @__PURE__ */ new Map();
@@ -7576,32 +7621,7 @@ function projectRecordingTranscripts(response, speakerResponse, source = "system
7576
7621
  const sessionSpeakers = listValue$6(session.spk_ls ?? session.speakers).map(objectValue);
7577
7622
  const childOffset = numberValue$6(child.start_at);
7578
7623
  const childStart = childOffset >= 1e11 ? childOffset : numberValue$6(session.start_at) + childOffset;
7579
- const rows = listValue$6(source === "doubao" ? child.doubao_asr : child.asr);
7580
- const doubaoStatus = numberValue$6(child.doubao_asr_status);
7581
- if (source === "doubao" && (doubaoStatus === 1 || doubaoStatus === 2 || doubaoStatus === 4 || doubaoStatus === 5)) {
7582
- const transcriptStatus = doubaoStatus === 1 || doubaoStatus === 2 ? "processing" : doubaoStatus === 4 ? "silent" : "failed";
7583
- const text = transcriptStatus === "processing" ? "豆包转写中..." : transcriptStatus === "silent" ? "豆包未识别到人声" : "豆包转写失败";
7584
- const label = transcriptStatus === "processing" ? "豆包转写中" : transcriptStatus === "silent" ? "豆包静音" : "豆包失败";
7585
- projected.push({
7586
- itemId: `${childId || sessionId}:doubao:status`,
7587
- sessionId,
7588
- childId,
7589
- asrItemIndex: 0,
7590
- transcriptSource: "doubao",
7591
- startAtMillis: childStart,
7592
- endAtMillis: childStart + Math.max(0, numberValue$6(child.duration)),
7593
- speakerNumber: -1,
7594
- speakerColorIndex: -1,
7595
- speakerLabel: label,
7596
- isSelf: false,
7597
- isBackground: false,
7598
- text,
7599
- transcriptStatus,
7600
- sourceIndex
7601
- });
7602
- sourceIndex += 1;
7603
- continue;
7604
- }
7624
+ const rows = listValue$6(child.asr);
7605
7625
  for (let index = 0; index < rows.length; index += 1) {
7606
7626
  const row = objectValue(rows[index]);
7607
7627
  const isBackground = numberValue$6(row.b ?? row.background) === 1 || row.background === true;
@@ -7615,15 +7635,15 @@ function projectRecordingTranscripts(response, speakerResponse, source = "system
7615
7635
  const persistentSpeakerNumber = optionalNumberValue(sessionSpeaker.speaker_display_number ?? sessionSpeaker.speakerDisplayNumber);
7616
7636
  const speakerNumber = persistentSpeakerNumber !== void 0 && persistentSpeakerNumber > 0 ? persistentSpeakerNumber : rawSpeakerNumber;
7617
7637
  const speakerColorIndex = sessionSpeakerColorIndexes.get(`${sessionId}:${rawSpeakerNumber}`) ?? Math.max(0, rawSpeakerNumber);
7618
- const speakerLabel = source === "doubao" ? rawSpeakerNumber >= 0 ? `豆包说话人 ${rawSpeakerNumber + 1}` : "豆包说话人" : speakerNumber >= 0 ? `说话人 ${speakerNumber}` : "未知说话人";
7638
+ const speakerLabel = speakerNumber >= 0 ? `说话人 ${speakerNumber}` : "未知说话人";
7619
7639
  const startOffset = numberValue$6(row.s ?? row.start_at);
7620
7640
  const endOffset = Math.max(startOffset, numberValue$6(row.e ?? row.end_at));
7621
7641
  projected.push({
7622
- itemId: source === "system" ? `${childId || sessionId}:${index}` : `${childId || sessionId}:doubao:${index}`,
7642
+ itemId: `${childId || sessionId}:${index}`,
7623
7643
  sessionId,
7624
7644
  childId,
7625
7645
  asrItemIndex: index,
7626
- transcriptSource: source,
7646
+ transcriptSource: "system",
7627
7647
  startAtMillis: childStart + startOffset,
7628
7648
  endAtMillis: childStart + endOffset,
7629
7649
  speakerNumber,
@@ -7632,7 +7652,6 @@ function projectRecordingTranscripts(response, speakerResponse, source = "system
7632
7652
  isSelf,
7633
7653
  isBackground,
7634
7654
  text,
7635
- ...source === "doubao" ? { transcriptStatus: "ready" } : {},
7636
7655
  sourceIndex
7637
7656
  });
7638
7657
  sourceIndex += 1;
@@ -7879,21 +7898,7 @@ var RecordingService = class {
7879
7898
  days
7880
7899
  };
7881
7900
  }
7882
- async recordingTranscript(dateStamp, signal, source = "system") {
7883
- const sections = await this.recordingTranscriptSections(dateStamp, signal);
7884
- return source === "doubao" ? sections.doubao : sections.system;
7885
- }
7886
- async startRecordingDoubaoBackfill(dateStamp, signal) {
7887
- const date = this.recordingDayStart(dateStamp).getTime();
7888
- const session = await this.runtime.requireSession();
7889
- const data = await this.runtime.authenticatedAudioPost("/api/v1/audio/doubao-asr/backfill-day", { start_at: date }, session, signal);
7890
- return {
7891
- queuedChildCount: Math.max(0, Math.trunc(numberValue$5(data.queued_child_count))),
7892
- inFlightChildCount: Math.max(0, Math.trunc(numberValue$5(data.in_flight_child_count))),
7893
- missingAudioChildCount: Math.max(0, Math.trunc(numberValue$5(data.missing_audio_child_count)))
7894
- };
7895
- }
7896
- async recordingTranscriptSections(dateStamp, signal) {
7901
+ async recordingTranscript(dateStamp, signal) {
7897
7902
  const dayStart = this.recordingDayStart(dateStamp);
7898
7903
  const date = dayStart.getTime();
7899
7904
  const session = await this.runtime.requireSession();
@@ -7905,29 +7910,14 @@ var RecordingService = class {
7905
7910
  let totalDurationMillis = 0;
7906
7911
  for (const rawSession of listValue$5(transcriptResult.value.session_ls)) totalDurationMillis += Math.max(0, numberValue$5(objectValue$1(rawSession).duration));
7907
7912
  const speakerData = speakerResult.status === "fulfilled" ? listValue$5(speakerResult.value.spk_ls) : [];
7908
- const identityCoverage = speakerResult.status === "fulfilled" ? "complete" : "partial";
7909
- const systemItems = projectRecordingTranscripts(transcriptResult.value, speakerData, "system");
7910
- const doubaoItems = projectRecordingTranscripts(transcriptResult.value, speakerData, "doubao");
7911
- const system = {
7912
- state: systemItems.length > 0 ? "ready" : "empty",
7913
- items: systemItems,
7914
- message: systemItems.length > 0 ? "" : "当天无录音",
7915
- identityCoverage,
7913
+ const items = projectRecordingTranscripts(transcriptResult.value, speakerData);
7914
+ return {
7915
+ state: items.length > 0 ? "ready" : "empty",
7916
+ items,
7917
+ message: items.length > 0 ? "" : "当天无录音",
7918
+ identityCoverage: speakerResult.status === "fulfilled" ? "complete" : "partial",
7916
7919
  totalDurationMillis
7917
7920
  };
7918
- const hasProcessing = doubaoItems.some((item) => item.transcriptStatus === "processing");
7919
- const hasReady = doubaoItems.some((item) => item.transcriptStatus === "ready" || item.transcriptStatus === "silent" || item.transcriptStatus === void 0);
7920
- const hasFailed = doubaoItems.some((item) => item.transcriptStatus === "failed");
7921
- return {
7922
- system,
7923
- doubao: {
7924
- state: hasProcessing ? "processing" : hasReady ? "ready" : hasFailed ? "failed" : "empty",
7925
- items: doubaoItems,
7926
- message: hasProcessing ? "豆包转写中" : hasReady ? "" : hasFailed ? "豆包转写失败" : "豆包转写尚未生成",
7927
- identityCoverage,
7928
- totalDurationMillis
7929
- }
7930
- };
7931
7921
  }
7932
7922
  async recordingProjection(dateStamp, kind, signal) {
7933
7923
  const dayStart = this.recordingDayStart(dateStamp);
@@ -7965,7 +7955,6 @@ var RecordingService = class {
7965
7955
  version: 1,
7966
7956
  dateStamp: numberValue$5(raw.dateStamp),
7967
7957
  content: content === "summary" || content === "timeline" ? content : "transcript",
7968
- ...content === "transcript" && (raw.transcriptSource === "system" || raw.transcriptSource === "doubao") ? { transcriptSource: raw.transcriptSource } : {},
7969
7958
  itemOffset: numberValue$5(raw.itemOffset),
7970
7959
  textOffset: numberValue$5(raw.textOffset),
7971
7960
  fingerprint: stringValue$1(raw.fingerprint),
@@ -7975,31 +7964,25 @@ var RecordingService = class {
7975
7964
  "transcript",
7976
7965
  "summary",
7977
7966
  "timeline"
7978
- ].includes(String(content)) || content === "transcript" && raw.transcriptSource !== void 0 && raw.transcriptSource !== "system" && raw.transcriptSource !== "doubao" || !Number.isSafeInteger(payload.dateStamp) || payload.dateStamp <= 0 || !Number.isSafeInteger(payload.itemOffset) || payload.itemOffset < 0 || !Number.isSafeInteger(payload.textOffset) || payload.textOffset < 0 || payload.fingerprint === "") throw new ArkmePluginError("recording-cursor-invalid", "录音分页游标无效", false);
7967
+ ].includes(String(content)) || !Number.isSafeInteger(payload.dateStamp) || payload.dateStamp <= 0 || !Number.isSafeInteger(payload.itemOffset) || payload.itemOffset < 0 || !Number.isSafeInteger(payload.textOffset) || payload.textOffset < 0 || payload.fingerprint === "") throw new ArkmePluginError("recording-cursor-invalid", "录音分页游标无效", false);
7979
7968
  return payload;
7980
7969
  }
7981
7970
  async recordingDay(dateStamp) {
7982
7971
  const date = this.recordingDayStart(dateStamp).getTime();
7983
7972
  const [transcriptResult, summaryResult, timelineResult] = await Promise.allSettled([
7984
- this.recordingTranscriptSections(date),
7973
+ this.recordingTranscript(date),
7985
7974
  this.recordingProjection(date, "summary"),
7986
7975
  this.recordingProjection(date, "timeline")
7987
7976
  ]);
7988
- const transcript = transcriptResult.status === "fulfilled" ? transcriptResult.value.system : {
7989
- state: "error",
7990
- items: [],
7991
- message: safeFailureMessage$2(transcriptResult.reason)
7992
- };
7993
- const doubaoTranscript = transcriptResult.status === "fulfilled" ? transcriptResult.value.doubao : {
7977
+ const transcript = transcriptResult.status === "fulfilled" ? transcriptResult.value : {
7994
7978
  state: "error",
7995
7979
  items: [],
7996
7980
  message: safeFailureMessage$2(transcriptResult.reason)
7997
7981
  };
7998
7982
  return {
7999
7983
  dateStamp: date,
8000
- totalDurationMillis: transcriptResult.status === "fulfilled" ? transcriptResult.value.system.totalDurationMillis : 0,
7984
+ totalDurationMillis: transcriptResult.status === "fulfilled" ? transcriptResult.value.totalDurationMillis : 0,
8001
7985
  transcript,
8002
- doubaoTranscript,
8003
7986
  summary: summaryResult.status === "fulfilled" ? summaryResult.value : {
8004
7987
  state: "error",
8005
7988
  items: [],
@@ -9427,6 +9410,12 @@ var WechatService = class {
9427
9410
  }
9428
9411
  };
9429
9412
  //#endregion
9413
+ //#region src/types.ts
9414
+ const ARKME_PROVIDER_CONTRACT_VERSION = 1;
9415
+ const ARKME_DEFAULT_SHARE_WEBSITE = "https://app.arkme.ai";
9416
+ const ARKME_WORLD_PUBLISH_MAX_IMAGES = 9;
9417
+ const ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES = 20 * 1024 * 1024;
9418
+ //#endregion
9430
9419
  //#region src/services/world-service.ts
9431
9420
  const ARKME_WORLD_IMAGE_REF_TTL_MILLIS = 900 * 1e3;
9432
9421
  const MAX_ARKME_WORLD_IMAGE_REFS = 2048;
@@ -9434,9 +9423,50 @@ const ARKME_WORLD_RECORD_REF_TTL_MILLIS = 900 * 1e3;
9434
9423
  const MAX_ARKME_WORLD_RECORD_REFS = 4096;
9435
9424
  const ARKME_VOICEPRINT_PLAY_SCOPE = 2;
9436
9425
  const ARKME_VOICEPRINT_INVITE_TOKEN_MAX_LENGTH = 2048;
9426
+ const ARKME_VOICEPRINT_SOCIAL_CACHE_MILLIS = 300 * 1e3;
9427
+ const ARKME_VOICEPRINT_SOCIAL_STALE_MILLIS = 1440 * 60 * 1e3;
9428
+ const ARKME_VOICEPRINT_SOCIAL_SOURCE_TIMEOUT_MILLIS = 4e3;
9429
+ const WORLD_VOICEPRINT_SOCIAL_RELATIONS = {
9430
+ reciprocal_expectation: {
9431
+ type: "reciprocal_expectation",
9432
+ displayLine: "TA也曾期待过你的声音",
9433
+ reasonCode: "relationship_reciprocal_expectation",
9434
+ reasonLabel: "因为TA也曾期待过我的声音"
9435
+ },
9436
+ call: {
9437
+ type: "call",
9438
+ displayLine: "你们曾经通过话",
9439
+ reasonCode: "relationship_call",
9440
+ reasonLabel: "因为我们曾经通过话"
9441
+ },
9442
+ world_interaction: {
9443
+ type: "world_interaction",
9444
+ displayLine: "你们曾在世界回应过彼此",
9445
+ reasonCode: "relationship_world",
9446
+ reasonLabel: "因为我们在世界里回应过彼此"
9447
+ },
9448
+ group_interaction: {
9449
+ type: "group_interaction",
9450
+ displayLine: "你们曾在同一个群里互动过",
9451
+ reasonCode: "relationship_group",
9452
+ reasonLabel: "因为我们在群里有过互动"
9453
+ },
9454
+ private_chat: {
9455
+ type: "private_chat",
9456
+ displayLine: "你们曾经聊过",
9457
+ reasonCode: "relationship_chat",
9458
+ reasonLabel: "因为我们以前聊过"
9459
+ }
9460
+ };
9437
9461
  function numberValue(value) {
9438
9462
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
9439
9463
  }
9464
+ function integerValue(value) {
9465
+ if (typeof value === "number" && Number.isFinite(value)) return Math.trunc(value);
9466
+ if (typeof value !== "string" || !/^-?\d+$/.test(value.trim())) return 0;
9467
+ const parsed = Number(value.trim());
9468
+ return Number.isSafeInteger(parsed) ? parsed : 0;
9469
+ }
9440
9470
  function listValue(value) {
9441
9471
  return Array.isArray(value) ? value : [];
9442
9472
  }
@@ -9472,6 +9502,26 @@ function worldVisibility(checkStatus) {
9472
9502
  if (checkStatus === 0 || checkStatus === 2 || checkStatus === 3) return "visible";
9473
9503
  return "unknown";
9474
9504
  }
9505
+ function worldPublicationResult(checkStatus) {
9506
+ const visibility = worldVisibility(checkStatus);
9507
+ if (visibility === "rejected") return {
9508
+ recordSaved: true,
9509
+ recordState: "synced",
9510
+ worldPublished: false,
9511
+ visibility,
9512
+ checkStatus,
9513
+ retryable: false,
9514
+ error: "内容未通过审核,请调整后重试"
9515
+ };
9516
+ return {
9517
+ recordSaved: true,
9518
+ recordState: "synced",
9519
+ worldPublished: true,
9520
+ visibility,
9521
+ checkStatus,
9522
+ retryable: false
9523
+ };
9524
+ }
9475
9525
  function worldTags(text) {
9476
9526
  return [...text.matchAll(/#(\S+)/gu)].map((match) => match[1] ?? "").filter((tag) => tag !== "");
9477
9527
  }
@@ -9479,6 +9529,10 @@ function stableWorldInteractionRecordUid(userId, targetRecordUid, clientMutation
9479
9529
  const hex = createHash("sha256").update(`dsh-arkme:world-interaction:${String(userId)}:${targetRecordUid}:${clientMutationId}`).digest("hex");
9480
9530
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-5${hex.slice(13, 16)}-a${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
9481
9531
  }
9532
+ function stableWorldPublishRecordUid(userId, clientMutationId) {
9533
+ const hex = createHash("sha256").update(`dsh-arkme:world-publish:${String(userId)}:${clientMutationId}`).digest("hex");
9534
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-5${hex.slice(13, 16)}-a${hex.slice(17, 20)}-${hex.slice(20, 32)}`;
9535
+ }
9482
9536
  function allowedSignedImageHost(environment, hostname) {
9483
9537
  return (environment === "prod" ? ["jotmo-userfiles.oss-cn-hangzhou.aliyuncs.com", "userfiles.jotmo.cc"] : ["jotmo-userfiles-test.oss-cn-hangzhou.aliyuncs.com", "jotmo-userfiles.senguo.me"]).includes(hostname.toLowerCase());
9484
9538
  }
@@ -9518,6 +9572,8 @@ var WorldService = class {
9518
9572
  record;
9519
9573
  worldImageRefs = /* @__PURE__ */ new Map();
9520
9574
  worldRecordRefs = /* @__PURE__ */ new Map();
9575
+ voiceprintSocialCache = /* @__PURE__ */ new Map();
9576
+ voiceprintSocialInFlight = /* @__PURE__ */ new Map();
9521
9577
  constructor(runtime, profile, media, record) {
9522
9578
  this.runtime = runtime;
9523
9579
  this.profile = profile;
@@ -9527,6 +9583,8 @@ var WorldService = class {
9527
9583
  dispose() {
9528
9584
  this.worldImageRefs.clear();
9529
9585
  this.worldRecordRefs.clear();
9586
+ this.voiceprintSocialCache.clear();
9587
+ this.voiceprintSocialInFlight.clear();
9530
9588
  }
9531
9589
  async listWorldRecords(options = {}) {
9532
9590
  const limit = Math.min(20, Math.max(1, Math.trunc(options.limit ?? 10)));
@@ -9589,6 +9647,37 @@ var WorldService = class {
9589
9647
  ...hasMore ? { nextOffset } : {}
9590
9648
  };
9591
9649
  }
9650
+ async listUserWorldFeed(userId, options = {}) {
9651
+ if (!Number.isSafeInteger(userId) || userId <= 0) throw new ArkmePluginError("world-user-id-invalid", "世界用户 ID 无效,请刷新后重试", false, 400);
9652
+ const session = await this.runtime.requireSession();
9653
+ const limit = Math.min(20, Math.max(1, Math.trunc(options.limit ?? 20)));
9654
+ let offset = Math.max(0, Math.trunc(options.offset ?? 0));
9655
+ let total = 0;
9656
+ let items = [];
9657
+ let hasMore = false;
9658
+ let attempts = 0;
9659
+ do {
9660
+ const data = await this.runtime.post(this.runtime.config.worldBaseUrl, "/api/public/v1/public-record/user-list", {
9661
+ user_id: userId,
9662
+ limit,
9663
+ offset
9664
+ }, void 0, [200], options.signal);
9665
+ const rawItems = listValue(data.list);
9666
+ total = Math.max(0, Math.trunc(numberValue(data.total)));
9667
+ const rootItems = rawItems.filter((raw) => stringValue$1(objectValue$1(raw).parent_record_uid).trim() === "");
9668
+ const resolvedAvatars = await this.resolveWorldAvatarUrls(rootItems, session, options.signal);
9669
+ items = (await Promise.all(rootItems.map((raw) => this.worldFeedItem(raw, session.userId, resolvedAvatars)))).filter((item) => item !== void 0);
9670
+ offset += rawItems.length;
9671
+ hasMore = rawItems.length > 0 && offset < total;
9672
+ attempts += 1;
9673
+ } while (items.length === 0 && hasMore && attempts < 4);
9674
+ return {
9675
+ items,
9676
+ total,
9677
+ hasMore,
9678
+ ...hasMore ? { nextOffset: offset } : {}
9679
+ };
9680
+ }
9592
9681
  async worldVoiceprintPlaybackAvailability(recordRefs, signal) {
9593
9682
  const session = await this.runtime.requireSession();
9594
9683
  const normalizedRefs = [...new Set(recordRefs.map((value) => value.trim()).filter((value) => value !== ""))].slice(0, 20);
@@ -9650,6 +9739,37 @@ var WorldService = class {
9650
9739
  chunkEndRune
9651
9740
  };
9652
9741
  }
9742
+ async worldVoiceprintSocialContext(recordRef, options = {}) {
9743
+ const session = await this.runtime.requireSession();
9744
+ const entry = this.openWorldRecordRef(recordRef, session.userId);
9745
+ const authorUserId = entry.ownerUserId ?? 0;
9746
+ if (!Number.isSafeInteger(authorUserId) || authorUserId <= 0 || authorUserId === session.userId) return { relations: [] };
9747
+ const cacheKey = `${String(session.userId)}:${String(authorUserId)}`;
9748
+ const cached = this.voiceprintSocialCache.get(cacheKey);
9749
+ const age = cached === void 0 ? Number.POSITIVE_INFINITY : Date.now() - cached.savedAtMillis;
9750
+ if (options.forceRefresh !== true && cached !== void 0 && cached.context.relations.length > 0 && age < ARKME_VOICEPRINT_SOCIAL_CACHE_MILLIS) return cached.context;
9751
+ if (options.forceRefresh !== true && cached !== void 0 && cached.context.relations.length > 0 && age < ARKME_VOICEPRINT_SOCIAL_STALE_MILLIS) {
9752
+ this.refreshWorldVoiceprintSocialContext({
9753
+ cacheKey,
9754
+ flightKey: `${cacheKey}:${entry.recordUid}`,
9755
+ viewerUserId: session.userId,
9756
+ authorUserId,
9757
+ recordUid: entry.recordUid,
9758
+ fallback: cached,
9759
+ ...options.signal === void 0 ? {} : { signal: options.signal }
9760
+ });
9761
+ return cached.context;
9762
+ }
9763
+ return await this.refreshWorldVoiceprintSocialContext({
9764
+ cacheKey,
9765
+ flightKey: `${cacheKey}:${entry.recordUid}`,
9766
+ viewerUserId: session.userId,
9767
+ authorUserId,
9768
+ recordUid: entry.recordUid,
9769
+ ...cached === void 0 ? {} : { fallback: cached },
9770
+ ...options.signal === void 0 ? {} : { signal: options.signal }
9771
+ });
9772
+ }
9653
9773
  async createWorldVoiceprintInviteIntent(recordRef, signal) {
9654
9774
  const session = await this.runtime.requireSession();
9655
9775
  const entry = this.openWorldRecordRef(recordRef, session.userId);
@@ -9672,6 +9792,183 @@ var WorldService = class {
9672
9792
  ...entry.textPreview === void 0 ? {} : { textPreview: entry.textPreview }
9673
9793
  };
9674
9794
  }
9795
+ refreshWorldVoiceprintSocialContext(input) {
9796
+ const existing = this.voiceprintSocialInFlight.get(input.flightKey);
9797
+ if (existing !== void 0) return existing;
9798
+ const refresh = this.loadWorldVoiceprintSocialContext(input).then((result) => {
9799
+ const context = this.mergeWorldVoiceprintSocialContexts(input.fallback?.context, result.context);
9800
+ if (context.relations.length > 0 || result.allSourcesSucceeded) this.voiceprintSocialCache.set(input.cacheKey, {
9801
+ context,
9802
+ savedAtMillis: Date.now()
9803
+ });
9804
+ return context;
9805
+ }).catch(() => input.fallback?.context.relations.length ? input.fallback.context : { relations: [] }).finally(() => {
9806
+ this.voiceprintSocialInFlight.delete(input.flightKey);
9807
+ });
9808
+ this.voiceprintSocialInFlight.set(input.flightKey, refresh);
9809
+ return refresh;
9810
+ }
9811
+ async loadWorldVoiceprintSocialContext(input) {
9812
+ const session = await this.runtime.requireSession();
9813
+ const directChat = this.loadWorldVoiceprintDirectChat(input.authorUserId, session, input.signal);
9814
+ const results = await Promise.all([
9815
+ this.guardWorldVoiceprintSocialSource(async () => await this.loadWorldVoiceprintReciprocalExpectation(input.authorUserId, session, input.signal)),
9816
+ this.guardWorldVoiceprintSocialSource(async () => await this.loadWorldVoiceprintInterwovenRelations(input.authorUserId, directChat, session, input.signal)),
9817
+ this.guardWorldVoiceprintSocialSource(async () => await this.loadWorldVoiceprintPrivateChatRelation(input.authorUserId, directChat)),
9818
+ this.guardWorldVoiceprintSocialSource(async () => await this.loadWorldVoiceprintCommentRelation(input.viewerUserId, input.recordUid, session, input.signal))
9819
+ ]);
9820
+ return {
9821
+ context: { relations: this.dedupeWorldVoiceprintRelations(results.flatMap((result) => result.relations)) },
9822
+ allSourcesSucceeded: results.every((result) => result.succeeded)
9823
+ };
9824
+ }
9825
+ async guardWorldVoiceprintSocialSource(loader) {
9826
+ let timeout;
9827
+ try {
9828
+ return await Promise.race([loader(), new Promise((resolve) => {
9829
+ timeout = setTimeout(() => {
9830
+ resolve({
9831
+ succeeded: false,
9832
+ relations: []
9833
+ });
9834
+ }, ARKME_VOICEPRINT_SOCIAL_SOURCE_TIMEOUT_MILLIS);
9835
+ })]);
9836
+ } catch {
9837
+ return {
9838
+ succeeded: false,
9839
+ relations: []
9840
+ };
9841
+ } finally {
9842
+ if (timeout !== void 0) clearTimeout(timeout);
9843
+ }
9844
+ }
9845
+ async loadWorldVoiceprintReciprocalExpectation(authorUserId, session, signal) {
9846
+ return {
9847
+ succeeded: true,
9848
+ relations: listValue(objectValue$1((await this.runtime.authenticatedAudioPost("/api/v1/audio/voiceprint/world-enrollment-interactions", {}, session, signal, {
9849
+ lane: "interactive-read",
9850
+ key: "world-enrollment-interactions",
9851
+ cacheMs: 5e3
9852
+ })).received).requesters).some((raw) => {
9853
+ const requester = objectValue$1(raw);
9854
+ return integerValue(requester.user_id ?? requester.userId) === authorUserId;
9855
+ }) ? [WORLD_VOICEPRINT_SOCIAL_RELATIONS.reciprocal_expectation] : []
9856
+ };
9857
+ }
9858
+ async loadWorldVoiceprintDirectChat(authorUserId, session, signal) {
9859
+ let pageCursor;
9860
+ const visited = /* @__PURE__ */ new Set();
9861
+ for (;;) {
9862
+ const data = await this.runtime.authenticatedChatPost("/api/v1/chats/list", {
9863
+ limit: 100,
9864
+ session_kind: 1,
9865
+ ...pageCursor === void 0 ? {} : { page_cursor: pageCursor }
9866
+ }, session, signal, {
9867
+ lane: "interactive-read",
9868
+ bypassCache: true
9869
+ });
9870
+ for (const raw of listValue(data.items)) {
9871
+ const bundle = objectValue$1(raw);
9872
+ const chatSession = objectValue$1(bundle.session);
9873
+ const counterpart = objectValue$1(bundle.private_counterpart);
9874
+ const sessionKind = integerValue(chatSession.session_kind);
9875
+ if (sessionKind !== 1 && sessionKind !== 3 || integerValue(counterpart.user_id ?? counterpart.userId) !== authorUserId) continue;
9876
+ const latestPreview = objectValue$1(bundle.latest_preview);
9877
+ const latestRecord = objectValue$1(latestPreview.record);
9878
+ const latestRelation = objectValue$1(latestPreview.relation);
9879
+ const unread = objectValue$1(bundle.unread_snapshot);
9880
+ const sessionUid = stringValue$1(chatSession.chat_session_uid).trim();
9881
+ if (sessionUid === "") continue;
9882
+ const sharedTopicId = [
9883
+ chatSession,
9884
+ objectValue$1(chatSession.extra),
9885
+ objectValue$1(chatSession.policy_snapshot)
9886
+ ].map((source) => integerValue(source.subject_id ?? source.subjectId ?? source.shared_topic_id ?? source.sharedTopicId)).find((value) => value > 0) ?? 0;
9887
+ const hasPrivateMessageEvidence = Object.keys(latestRecord).length > 0 || Object.keys(objectValue$1(latestRecord.payload)).length > 0 || stringValue$1(latestRecord.record_uid).trim() !== "" || stringValue$1(latestRelation.record_uid).trim() !== "" || integerValue(unread.session_last_seq ?? chatSession.last_seq) > 0;
9888
+ return {
9889
+ sessionUid,
9890
+ sharedTopicId: Math.max(0, sharedTopicId),
9891
+ hasPrivateMessageEvidence
9892
+ };
9893
+ }
9894
+ if (data.has_more !== true) return void 0;
9895
+ const nextCursor = objectValue$1(data.next_page_cursor);
9896
+ if (Object.keys(nextCursor).length === 0) throw new Error("voiceprint direct-chat pagination cursor missing");
9897
+ const identity = JSON.stringify(nextCursor);
9898
+ if (visited.has(identity)) throw new Error("voiceprint direct-chat pagination cursor repeated");
9899
+ visited.add(identity);
9900
+ pageCursor = nextCursor;
9901
+ }
9902
+ }
9903
+ async loadWorldVoiceprintInterwovenRelations(authorUserId, directChatFuture, session, signal) {
9904
+ const directChat = await directChatFuture;
9905
+ if (directChat === void 0 || authorUserId <= 0) return {
9906
+ succeeded: true,
9907
+ relations: []
9908
+ };
9909
+ const data = directChat.sharedTopicId > 0 ? await this.runtime.authenticatedWorldPost("/api/v1/interwoven-moments/summary", { subject_id: directChat.sharedTopicId }, session, signal, {
9910
+ lane: "interactive-read",
9911
+ bypassCache: true
9912
+ }) : await this.runtime.authenticatedChatPost("/api/v1/chats/interwoven/summary", {
9913
+ subject_id: 0,
9914
+ chat_session_uid: directChat.sessionUid
9915
+ }, session, signal, {
9916
+ lane: "interactive-read",
9917
+ bypassCache: true
9918
+ });
9919
+ const stats = listValue(objectValue$1(data.recent_card).total_stats);
9920
+ const countFor = (momentType) => {
9921
+ return integerValue(objectValue$1(stats.find((value) => integerValue(objectValue$1(value).moment_type) === momentType)).count);
9922
+ };
9923
+ const relations = [];
9924
+ const callSummary = data.call_summary;
9925
+ if ((callSummary !== null && typeof callSummary === "object" && !Array.isArray(callSummary) ? integerValue(objectValue$1(callSummary).total_call_count) : countFor(3)) > 0) relations.push(WORLD_VOICEPRINT_SOCIAL_RELATIONS.call);
9926
+ if (countFor(2) > 0) relations.push(WORLD_VOICEPRINT_SOCIAL_RELATIONS.world_interaction);
9927
+ const groupFromStatus = listValue(data.source_status).some((raw) => {
9928
+ const status = objectValue$1(raw);
9929
+ return integerValue(status.moment_type) === 1 && integerValue(status.item_count) > 0;
9930
+ });
9931
+ if (countFor(1) > 0 || groupFromStatus) relations.push(WORLD_VOICEPRINT_SOCIAL_RELATIONS.group_interaction);
9932
+ return {
9933
+ succeeded: true,
9934
+ relations
9935
+ };
9936
+ }
9937
+ async loadWorldVoiceprintPrivateChatRelation(authorUserId, directChatFuture) {
9938
+ const directChat = await directChatFuture;
9939
+ return {
9940
+ succeeded: true,
9941
+ relations: directChat !== void 0 && authorUserId > 0 && directChat.hasPrivateMessageEvidence ? [WORLD_VOICEPRINT_SOCIAL_RELATIONS.private_chat] : []
9942
+ };
9943
+ }
9944
+ async loadWorldVoiceprintCommentRelation(viewerUserId, recordUid, session, signal) {
9945
+ if (recordUid.trim() === "") return {
9946
+ succeeded: true,
9947
+ relations: []
9948
+ };
9949
+ return {
9950
+ succeeded: true,
9951
+ relations: listValue((await this.runtime.authenticatedWorldPost("/api/v1/public-record/extend-list", {
9952
+ record_uid: recordUid,
9953
+ limit: 100,
9954
+ offset: 0
9955
+ }, session, signal, {
9956
+ lane: "interactive-read",
9957
+ bypassCache: true
9958
+ })).list).some((raw) => {
9959
+ const item = objectValue$1(raw);
9960
+ return integerValue(item.user_id ?? item.userId) === viewerUserId;
9961
+ }) ? [WORLD_VOICEPRINT_SOCIAL_RELATIONS.world_interaction] : []
9962
+ };
9963
+ }
9964
+ dedupeWorldVoiceprintRelations(relations) {
9965
+ const seen = /* @__PURE__ */ new Set();
9966
+ return relations.filter((relation) => !seen.has(relation.type) && seen.add(relation.type));
9967
+ }
9968
+ mergeWorldVoiceprintSocialContexts(previous, current) {
9969
+ if (previous === void 0 || previous.relations.length === 0) return current;
9970
+ return { relations: this.dedupeWorldVoiceprintRelations([...previous.relations, ...current.relations]) };
9971
+ }
9675
9972
  async listWorldInteractions(recordRef, options = {}) {
9676
9973
  const session = await this.runtime.requireSession();
9677
9974
  const root = this.openWorldRecordRef(recordRef, session.userId);
@@ -9817,18 +10114,88 @@ var WorldService = class {
9817
10114
  avatar: profile.avatarRef,
9818
10115
  template_kind: 1
9819
10116
  }, void 0, signal);
9820
- const checkStatus = Math.trunc(numberValue(published.check_status));
9821
- return {
10117
+ return worldPublicationResult(Math.trunc(numberValue(published.check_status)));
10118
+ } catch (error) {
10119
+ try {
10120
+ if (await this.worldRecordIsPublic(normalizedUid, signal)) return {
10121
+ recordSaved: true,
10122
+ recordState: "synced",
10123
+ worldPublished: true,
10124
+ visibility: "unknown",
10125
+ checkStatus: 0,
10126
+ retryable: false
10127
+ };
10128
+ } catch {}
10129
+ return this.worldPublishFailure(true, error, "synced");
10130
+ }
10131
+ }
10132
+ async publishWorldText(input) {
10133
+ const session = await this.runtime.requireSession();
10134
+ const clientMutationId = input.clientMutationId.trim();
10135
+ if (!/^[A-Za-z0-9_-]{16,128}$/.test(clientMutationId)) throw new ArkmePluginError("world-publish-mutation-invalid", "发布请求标识无效,请重试", false);
10136
+ return await this.publishWorldTextForConversation(stableWorldPublishRecordUid(session.userId, clientMutationId), input.textContent);
10137
+ }
10138
+ async publishWorldFileAssets(input) {
10139
+ const session = await this.runtime.requireSession();
10140
+ const clientMutationId = input.clientMutationId.trim();
10141
+ const textContent = input.textContent.trim();
10142
+ if (!/^[A-Za-z0-9_-]{16,128}$/.test(clientMutationId)) throw new ArkmePluginError("world-publish-mutation-invalid", "发布请求标识无效,请重试", false);
10143
+ if (textContent === "" || textContent.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("world-text-invalid", "世界内容为空或过长", false);
10144
+ if (input.fileAssets.length === 0 || input.fileAssets.length > 9 || input.fileAssets.some((asset) => !/^[A-Za-z0-9._:-]{8,256}$/.test(asset.fileAssetUid) || asset.fileName.trim() === "" || !asset.mimeType.toLowerCase().startsWith("image/") || !Number.isSafeInteger(asset.size) || asset.size <= 0 || asset.size > 20971520 || asset.fileKind !== 1)) throw new ArkmePluginError("world-publish-assets-invalid", "世界图片参数无效", false);
10145
+ let profile;
10146
+ try {
10147
+ const snapshot = await this.profile.refreshProfile();
10148
+ if (snapshot.profile === null) throw new ArkmePluginError("profile-unavailable", "无法读取当前 Arkme 账号资料", true);
10149
+ profile = snapshot.profile;
10150
+ } catch (error) {
10151
+ return this.worldPublishFailure(false, error);
10152
+ }
10153
+ if (profile.contact.phoneMasked === void 0) return {
10154
+ recordSaved: false,
10155
+ recordState: "not_saved",
10156
+ worldPublished: false,
10157
+ visibility: "not_published",
10158
+ checkStatus: 0,
10159
+ retryable: false,
10160
+ error: "请先在 Arkme 客户端绑定手机号,再发到世界"
10161
+ };
10162
+ const recordUid = stableWorldPublishRecordUid(session.userId, clientMutationId);
10163
+ try {
10164
+ if (await this.worldRecordIsPublic(recordUid)) return {
9822
10165
  recordSaved: true,
9823
10166
  recordState: "synced",
9824
10167
  worldPublished: true,
9825
- visibility: worldVisibility(checkStatus),
9826
- checkStatus,
10168
+ visibility: "unknown",
10169
+ checkStatus: 0,
9827
10170
  retryable: false
9828
10171
  };
10172
+ } catch {}
10173
+ try {
10174
+ await this.record.createFileAssetsForConversation(recordUid, textContent, input.fileAssets);
10175
+ } catch (error) {
10176
+ return this.worldPublishFailure(false, error);
10177
+ }
10178
+ try {
10179
+ const published = await this.runtime.authenticatedWorldPost("/api/v1/public-record/publish-with-file-assets", {
10180
+ record_uid: recordUid,
10181
+ content: textContent,
10182
+ text_content: textContent,
10183
+ file_assets: input.fileAssets.map((asset, index) => ({
10184
+ file_asset_uid: asset.fileAssetUid,
10185
+ media_type: "image",
10186
+ file_kind: 1,
10187
+ sort_order: index
10188
+ })),
10189
+ tags: worldTags(textContent),
10190
+ original_topic_id: 0,
10191
+ created_at: Date.now(),
10192
+ nick_name: profile.nickname || profile.displayName,
10193
+ avatar: profile.avatarRef
10194
+ }, session);
10195
+ return worldPublicationResult(Math.trunc(numberValue(published.check_status)));
9829
10196
  } catch (error) {
9830
10197
  try {
9831
- if (await this.worldRecordIsPublic(normalizedUid, signal)) return {
10198
+ if (await this.worldRecordIsPublic(recordUid)) return {
9832
10199
  recordSaved: true,
9833
10200
  recordState: "synced",
9834
10201
  worldPublished: true,
@@ -10072,10 +10439,6 @@ var WorldService = class {
10072
10439
  }
10073
10440
  };
10074
10441
  //#endregion
10075
- //#region src/types.ts
10076
- const ARKME_PROVIDER_CONTRACT_VERSION = 1;
10077
- const ARKME_DEFAULT_SHARE_WEBSITE = "https://app.arkme.ai";
10078
- //#endregion
10079
10442
  //#region src/arkme-service.ts
10080
10443
  function worldVoiceprintInviteMessage(input) {
10081
10444
  return `${input.textPreview === void 0 ? "我想邀请你开启声纹。" : `我看到你在世界里发的「${input.textPreview}」,想邀请你开启声纹。`}\n以后看到你的世界动态时,可以直接听到你的声音。\n${input.inviteUrl}`;
@@ -10277,13 +10640,13 @@ var ArkmeService = class {
10277
10640
  extensionPreviews: true,
10278
10641
  worldFeed: true,
10279
10642
  worldInteractions: true,
10643
+ worldPublish: true,
10280
10644
  worldVoiceprintPlayback: true,
10281
10645
  worldVoiceprintInvite: true,
10646
+ worldVoiceprintSocialContext: true,
10282
10647
  arrangements: true,
10283
10648
  myExtensions: true,
10284
10649
  extensionPublish: true,
10285
- recordingTranscripts: true,
10286
- recordingDoubaoBackfill: true,
10287
10650
  extensionReviews: true,
10288
10651
  ...this.relatedRecording.isEnabled() ? { relatedRecordings: true } : {}
10289
10652
  },
@@ -10370,12 +10733,8 @@ var ArkmeService = class {
10370
10733
  return await this.recording.recordingCalendar(fromStamp, toStamp, signal);
10371
10734
  }
10372
10735
  /** Read-only Audio capability shared by the built-in UI and Arkme recording tools. */
10373
- async recordingTranscript(dateStamp, signal, source = "system") {
10374
- return await this.recording.recordingTranscript(dateStamp, signal, source);
10375
- }
10376
- /** Queue Doubao backfill only after an explicit UI, SDK, or Tool request. */
10377
- async startRecordingDoubaoBackfill(dateStamp, signal) {
10378
- return await this.recording.startRecordingDoubaoBackfill(dateStamp, signal);
10736
+ async recordingTranscript(dateStamp, signal) {
10737
+ return await this.recording.recordingTranscript(dateStamp, signal);
10379
10738
  }
10380
10739
  /** Read-only Audio capability shared by the built-in UI and Arkme recording tools. */
10381
10740
  async recordingProjection(dateStamp, kind, signal) {
@@ -10726,12 +11085,18 @@ var ArkmeService = class {
10726
11085
  async listMyWorldFeed(options = {}) {
10727
11086
  return await this.world.listMyWorldFeed(options);
10728
11087
  }
11088
+ async listUserWorldFeed(userId, options = {}) {
11089
+ return await this.world.listUserWorldFeed(userId, options);
11090
+ }
10729
11091
  async worldVoiceprintPlaybackAvailability(recordRefs, signal) {
10730
11092
  return await this.world.worldVoiceprintPlaybackAvailability(recordRefs, signal);
10731
11093
  }
10732
11094
  async generateWorldVoiceprintPlayback(input) {
10733
11095
  return await this.world.generateWorldVoiceprintPlayback(input);
10734
11096
  }
11097
+ async worldVoiceprintSocialContext(recordRef, options = {}) {
11098
+ return await this.world.worldVoiceprintSocialContext(recordRef, options);
11099
+ }
10735
11100
  async inviteWorldVoiceprint(recordRef, signal) {
10736
11101
  try {
10737
11102
  const intent = await this.world.createWorldVoiceprintInviteIntent(recordRef, signal);
@@ -10772,6 +11137,12 @@ var ArkmeService = class {
10772
11137
  async publishWorldTextForConversation(recordUid, textContent, signal) {
10773
11138
  return await this.world.publishWorldTextForConversation(recordUid, textContent, signal);
10774
11139
  }
11140
+ async publishWorldText(input) {
11141
+ return await this.world.publishWorldText(input);
11142
+ }
11143
+ async publishWorldFileAssets(input) {
11144
+ return await this.world.publishWorldFileAssets(input);
11145
+ }
10775
11146
  async createText(recordUid, textContent) {
10776
11147
  return await this.record.createText(recordUid, textContent);
10777
11148
  }
@@ -12156,4 +12527,4 @@ async function invokePersistentArkmeExtension(extensionId, method, args) {
12156
12527
  return jsonValue(await handler(jsonValue(args)));
12157
12528
  }
12158
12529
  //#endregion
12159
- export { unpackArkmeExtension as A, ArkmeOutgoingCallError as B, packBundleFiles as C, assertExtensionArtifactSize as D, renderArkmeSandboxHostEntry as E, ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE as F, ArkmeService as I, ARKME_DEFAULT_SHARE_WEBSITE as L, ARKME_EXTENSION_ICON_MAX_BYTES as M, ARKME_EXTENSION_MAX_BYTES as N, canonicalExtensionJson as O, ARKME_EXTENSION_PREVIEW_MAX_BYTES as P, ARKME_PROVIDER_CONTRACT_VERSION as R, inspectNativeBundleArtifactV3 as S, readNativeBundleTarballV3 as T, ArkmeBundleArtifactError as _, persistentArkmeExtensionActive as a, canonicalBundleJson as b, readPersistentExtensionActivation as c, verifyBundleResolutionSignature as d, verifyExtensionResolutionSignature as f, ARKME_NATIVE_BUNDLE_ARTIFACT_KIND as g, ARKME_BUNDLE_MAX_BYTES as h, invokePersistentArkmeExtension as i, ARKME_EXTENSION_FORMAT as j, sha256Hex as k, writePersistentExtensionActivation as l, ARKME_BUNDLE_ARTIFACT_KIND as m, applyPersistentArkmeHostExtension as n, persistentArkmeExtensionRuntimeState as o, verifyNativeBundleResolutionSignature as p, deactivatePersistentArkmeExtension as r, materializePersistentExtensionBundle as s, activatePersistentArkmeExtension as t, renderArkmeBundleClientBundle as u, arkmeSandboxEntryId as v, packLocalNativeBundleDirectoryV3 as w, inspectBundleArtifact as x, bundleSha256 as y, ArkmePluginError as z };
12530
+ export { unpackArkmeExtension as A, ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES as B, packBundleFiles as C, assertExtensionArtifactSize as D, renderArkmeSandboxHostEntry as E, ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE as F, ArkmePluginError as H, ArkmeService as I, ARKME_DEFAULT_SHARE_WEBSITE as L, ARKME_EXTENSION_ICON_MAX_BYTES as M, ARKME_EXTENSION_MAX_BYTES as N, canonicalExtensionJson as O, ARKME_EXTENSION_PREVIEW_MAX_BYTES as P, ARKME_PROVIDER_CONTRACT_VERSION as R, inspectNativeBundleArtifactV3 as S, readNativeBundleTarballV3 as T, ArkmeOutgoingCallError as U, isArkmeBotAvatarRef as V, ArkmeBundleArtifactError as _, persistentArkmeExtensionActive as a, canonicalBundleJson as b, readPersistentExtensionActivation as c, verifyBundleResolutionSignature as d, verifyExtensionResolutionSignature as f, ARKME_NATIVE_BUNDLE_ARTIFACT_KIND as g, ARKME_BUNDLE_MAX_BYTES as h, invokePersistentArkmeExtension as i, ARKME_EXTENSION_FORMAT as j, sha256Hex as k, writePersistentExtensionActivation as l, ARKME_BUNDLE_ARTIFACT_KIND as m, applyPersistentArkmeHostExtension as n, persistentArkmeExtensionRuntimeState as o, verifyNativeBundleResolutionSignature as p, deactivatePersistentArkmeExtension as r, materializePersistentExtensionBundle as s, activatePersistentArkmeExtension as t, renderArkmeBundleClientBundle as u, arkmeSandboxEntryId as v, packLocalNativeBundleDirectoryV3 as w, inspectBundleArtifact as x, bundleSha256 as y, ARKME_WORLD_PUBLISH_MAX_IMAGES as z };