@senguoyun/dsh-arkme 0.1.82 → 0.1.84
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/ai-points-implementation.md +43 -0
- package/docs/interwoven-compact-summary-regression-2026-09-28.md +35 -0
- package/docs/interwoven-original-read-receipt-regression-2026-09-28.md +50 -0
- package/docs/personal-detail-consistency-regression-2026-09-28.md +40 -0
- package/docs/recognized-speaker-directory-backend-handoff-2026-09-28.md +157 -0
- package/docs/recognized-speaker-entry-and-visits.md +47 -0
- package/docs/recognized-speaker-presence-delivery.md +51 -0
- package/docs/recognized-speaker-sorting.md +30 -0
- package/docs/send-to-self-roles-cross-client-api-handoff-2026-09-27.md +9 -0
- package/lib/client.js +3358 -1946
- package/lib/client.js.map +1 -1
- package/lib/harness-model-client.js +168 -38
- package/lib/harness-native-selection-client.js +92 -1
- package/lib/harness-sidebar-client.js +31 -0
- package/lib/index.js +347 -132
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-DV9Hme-U.js → persistent-runtime-CuKplHIv.js} +607 -303
- package/lib/sdk.js +31 -0
- package/lib/types/ai-points.d.ts +61 -0
- package/lib/types/ai-points.d.ts.map +1 -0
- package/lib/types/arkme-service.d.ts +11 -1
- package/lib/types/arkme-service.d.ts.map +1 -1
- package/lib/types/billing-gateway.d.ts.map +1 -1
- package/lib/types/client/ArkmeAccountUsage.d.ts +1 -3
- package/lib/types/client/ArkmeAccountUsage.d.ts.map +1 -1
- package/lib/types/client/ArkmeArkoSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeBillingSettings.d.ts +3 -2
- package/lib/types/client/ArkmeBillingSettings.d.ts.map +1 -1
- package/lib/types/client/ArkmeDataManagementSettings.d.ts.map +1 -1
- package/lib/types/client/ArkmeDocumentComposerInput.d.ts.map +1 -1
- package/lib/types/client/ArkmeEmojiPicker.d.ts.map +1 -1
- package/lib/types/client/ArkmeInterwovenReadReceipt.d.ts +12 -0
- package/lib/types/client/ArkmeInterwovenReadReceipt.d.ts.map +1 -0
- package/lib/types/client/ArkmeModelPricing.d.ts +9 -0
- package/lib/types/client/ArkmeModelPricing.d.ts.map +1 -0
- package/lib/types/client/ArkmeModelSelect.d.ts.map +1 -1
- package/lib/types/client/ArkmeNoteDetails.d.ts.map +1 -1
- package/lib/types/client/ArkmePointsConsumption.d.ts +5 -0
- package/lib/types/client/ArkmePointsConsumption.d.ts.map +1 -0
- package/lib/types/client/ArkmeRecognizedSpeakersSurface.d.ts +6 -2
- package/lib/types/client/ArkmeRecognizedSpeakersSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeRecordingSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeRelatedQuickNotes.d.ts.map +1 -1
- package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
- package/lib/types/client/ArkoModelMenu.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/interwoven-moments.d.ts.map +1 -1
- package/lib/types/client/interwoven-read-receipt-store.d.ts +32 -0
- package/lib/types/client/interwoven-read-receipt-store.d.ts.map +1 -0
- package/lib/types/client/locales/actions-en.d.ts.map +1 -1
- package/lib/types/client/locales/dynamic-en.d.ts.map +1 -1
- package/lib/types/client/locales/en.d.ts.map +1 -1
- package/lib/types/client/reaction-preview-store.d.ts +1 -0
- package/lib/types/client/reaction-preview-store.d.ts.map +1 -1
- package/lib/types/client/recognized-speaker-directory.d.ts +36 -0
- package/lib/types/client/recognized-speaker-directory.d.ts.map +1 -0
- package/lib/types/client/recognized-speaker-order.d.ts +28 -0
- package/lib/types/client/recognized-speaker-order.d.ts.map +1 -0
- package/lib/types/client/recognized-speaker-tracker.d.ts +33 -0
- package/lib/types/client/recognized-speaker-tracker.d.ts.map +1 -0
- package/lib/types/client/recordings/RecognizedSpeakerEntry.d.ts +12 -0
- package/lib/types/client/recordings/RecognizedSpeakerEntry.d.ts.map +1 -0
- package/lib/types/client/recordings/SpeakerSelfGuide.d.ts +8 -0
- package/lib/types/client/recordings/SpeakerSelfGuide.d.ts.map +1 -0
- package/lib/types/client/recordings/recording-speaker-options-store.d.ts.map +1 -1
- package/lib/types/client/self-role-presentation.d.ts +6 -1
- package/lib/types/client/self-role-presentation.d.ts.map +1 -1
- package/lib/types/client/use-personal-extension-parents.d.ts +4 -0
- package/lib/types/client/use-personal-extension-parents.d.ts.map +1 -0
- package/lib/types/host-api.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/managed-ai/adapter.d.ts +2 -1
- package/lib/types/managed-ai/adapter.d.ts.map +1 -1
- package/lib/types/managed-ai/operation.d.ts +17 -0
- package/lib/types/managed-ai/operation.d.ts.map +1 -0
- package/lib/types/managed-ai/transport.d.ts +1 -0
- package/lib/types/managed-ai/transport.d.ts.map +1 -1
- package/lib/types/record-extension-tree.d.ts +2 -0
- package/lib/types/record-extension-tree.d.ts.map +1 -1
- package/lib/types/sdk/index.d.ts +14 -0
- package/lib/types/sdk/index.d.ts.map +1 -1
- package/lib/types/services/ai-points-service.d.ts +13 -0
- package/lib/types/services/ai-points-service.d.ts.map +1 -0
- package/lib/types/services/arko-service.d.ts.map +1 -1
- package/lib/types/services/chat-service.d.ts +9 -1
- package/lib/types/services/chat-service.d.ts.map +1 -1
- package/lib/types/services/interwoven-service.d.ts +3 -1
- package/lib/types/services/interwoven-service.d.ts.map +1 -1
- package/lib/types/services/recording-service.d.ts +2 -5
- package/lib/types/services/recording-service.d.ts.map +1 -1
- package/lib/types/services/unmarked-speaker-service.d.ts.map +1 -1
- package/lib/types/tools/business/account/ai-points.d.ts +4 -0
- package/lib/types/tools/business/account/ai-points.d.ts.map +1 -0
- package/lib/types/tools/business/account/index.d.ts.map +1 -1
- package/lib/types/tools/business/recordings/index.d.ts +1 -1
- package/lib/types/tools/business/recordings/index.d.ts.map +1 -1
- package/lib/types/tools/business/recordings/speaker-presence.d.ts +2 -0
- package/lib/types/tools/business/recordings/speaker-presence.d.ts.map +1 -0
- package/lib/types/tools/ports/profile.d.ts +3 -0
- package/lib/types/tools/ports/profile.d.ts.map +1 -1
- package/lib/types/tools/ports/recordings.d.ts +4 -0
- package/lib/types/tools/ports/recordings.d.ts.map +1 -1
- package/lib/types/types.d.ts +33 -8
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/lib/types/recording-speaker-presence.d.ts +0 -28
- package/lib/types/recording-speaker-presence.d.ts.map +0 -1
|
@@ -389,7 +389,7 @@ function object$8(value) {
|
|
|
389
389
|
function keys(value, allowed) {
|
|
390
390
|
if (Object.keys(value).some((key) => !allowed.includes(key))) fail$1();
|
|
391
391
|
}
|
|
392
|
-
function text$
|
|
392
|
+
function text$12(value, max) {
|
|
393
393
|
if (typeof value !== "string" || value.length > max) fail$1();
|
|
394
394
|
}
|
|
395
395
|
function integer$6(value) {
|
|
@@ -415,7 +415,7 @@ function parseArrangementBoardCachePages(value) {
|
|
|
415
415
|
const board = object$8(page.board);
|
|
416
416
|
keys(board, ["supported", "version"]);
|
|
417
417
|
if (typeof board.supported !== "boolean") fail$1();
|
|
418
|
-
text$
|
|
418
|
+
text$12(board.version, 1024);
|
|
419
419
|
}
|
|
420
420
|
const refs = /* @__PURE__ */ new Set();
|
|
421
421
|
for (const rawItem of page.items) {
|
|
@@ -436,13 +436,13 @@ function parseArrangementBoardCachePages(value) {
|
|
|
436
436
|
]);
|
|
437
437
|
if (item.status !== column || typeof item.reminderEnabled !== "boolean" || typeof item.arrangementRef !== "string" || !/^arkme-arrangement-v1\.[A-Za-z0-9_-]{43}$/.test(item.arrangementRef) || refs.has(item.arrangementRef)) fail$1();
|
|
438
438
|
refs.add(item.arrangementRef);
|
|
439
|
-
text$
|
|
440
|
-
text$
|
|
441
|
-
text$
|
|
439
|
+
text$12(item.title, 2e4);
|
|
440
|
+
text$12(item.description, 2e5);
|
|
441
|
+
text$12(item.reminderState, 256);
|
|
442
442
|
integer$6(item.createdAtMillis);
|
|
443
443
|
integer$6(item.updatedAtMillis);
|
|
444
444
|
for (const key of ["dueAtMillis", "remindAtMillis"]) if (item[key] !== void 0) integer$6(item[key]);
|
|
445
|
-
if (item.recognitionState !== void 0) text$
|
|
445
|
+
if (item.recognitionState !== void 0) text$12(item.recognitionState, 256);
|
|
446
446
|
if (item.creationSource !== void 0) {
|
|
447
447
|
const source = object$8(item.creationSource);
|
|
448
448
|
keys(source, [
|
|
@@ -459,7 +459,7 @@ function parseArrangementBoardCachePages(value) {
|
|
|
459
459
|
for (const rawSource of source.items) {
|
|
460
460
|
const entry = object$8(rawSource);
|
|
461
461
|
keys(entry, ["text", "createdAtMillis"]);
|
|
462
|
-
text$
|
|
462
|
+
text$12(entry.text, 2e5);
|
|
463
463
|
if (entry.createdAtMillis !== void 0) integer$6(entry.createdAtMillis);
|
|
464
464
|
}
|
|
465
465
|
}
|
|
@@ -2024,7 +2024,11 @@ var ServiceRuntime = class {
|
|
|
2024
2024
|
try {
|
|
2025
2025
|
return await this.post(this.config.intelligentBaseUrl, path, body, session.accessToken, [200], signal, true, requestOptions());
|
|
2026
2026
|
} catch (error) {
|
|
2027
|
-
if (!(error instanceof ArkmePluginError) || ![
|
|
2027
|
+
if (!(error instanceof ArkmePluginError) || ![
|
|
2028
|
+
"auth-http-401",
|
|
2029
|
+
"auth-http-403",
|
|
2030
|
+
"invalid_access_token"
|
|
2031
|
+
].includes(error.code)) throw error;
|
|
2028
2032
|
session = await this.refreshAccessToken(session);
|
|
2029
2033
|
return await this.post(this.config.intelligentBaseUrl, path, body, session.accessToken, [200], signal, true, requestOptions());
|
|
2030
2034
|
}
|
|
@@ -2049,6 +2053,180 @@ var ServiceRuntime = class {
|
|
|
2049
2053
|
}
|
|
2050
2054
|
};
|
|
2051
2055
|
//#endregion
|
|
2056
|
+
//#region src/ai-points.ts
|
|
2057
|
+
function pointsUnits(value) {
|
|
2058
|
+
if (!/^(?:0|[1-9]\d*)(?:\.\d{1,7})?$/.test(value)) throw new TypeError("Invalid exact AI points");
|
|
2059
|
+
const [whole = "0", fraction = ""] = value.split(".");
|
|
2060
|
+
const units = BigInt(whole) * 10000000n + BigInt(fraction.padEnd(7, "0"));
|
|
2061
|
+
if (units > 9223372036854775807n) throw new TypeError("AI points exceed accounting range");
|
|
2062
|
+
return units;
|
|
2063
|
+
}
|
|
2064
|
+
/** Existing recharge values retain their nano-CNY meaning: ¥1 = 100 points. */
|
|
2065
|
+
function nanoCnyToPoints(value) {
|
|
2066
|
+
if (!/^(?:0|[1-9]\d*)$/.test(value)) throw new TypeError("Invalid nano-CNY");
|
|
2067
|
+
const units = BigInt(value);
|
|
2068
|
+
const whole = units / 10000000n;
|
|
2069
|
+
const fraction = (units % 10000000n).toString().padStart(7, "0").replace(/0+$/, "");
|
|
2070
|
+
return fraction ? `${whole}.${fraction}` : whole.toString();
|
|
2071
|
+
}
|
|
2072
|
+
/** The server pages whole operations. Call-level charges remain the only facts. */
|
|
2073
|
+
function groupPointsConsumption(items) {
|
|
2074
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2075
|
+
for (const item of items) {
|
|
2076
|
+
const key = item.businessCode === "agent" && item.operationUid ? `agent:${item.operationUid}` : `request:${item.requestUid}`;
|
|
2077
|
+
const calls = groups.get(key) ?? [];
|
|
2078
|
+
calls.push(item);
|
|
2079
|
+
groups.set(key, calls);
|
|
2080
|
+
}
|
|
2081
|
+
return [...groups].map(([key, calls]) => ({
|
|
2082
|
+
key,
|
|
2083
|
+
calls,
|
|
2084
|
+
chargedPoints: nanoCnyToPoints(calls.reduce((sum, call) => sum + pointsUnits(call.chargedPoints), 0n).toString())
|
|
2085
|
+
}));
|
|
2086
|
+
}
|
|
2087
|
+
//#endregion
|
|
2088
|
+
//#region src/services/ai-points-service.ts
|
|
2089
|
+
function invalid$12() {
|
|
2090
|
+
throw new ArkmePluginError("ai-points-contract-invalid", "积分数据暂时无法确认,请重试", true, 502);
|
|
2091
|
+
}
|
|
2092
|
+
function points(value) {
|
|
2093
|
+
if (typeof value !== "string") return invalid$12();
|
|
2094
|
+
try {
|
|
2095
|
+
pointsUnits(value);
|
|
2096
|
+
} catch {
|
|
2097
|
+
return invalid$12();
|
|
2098
|
+
}
|
|
2099
|
+
return value;
|
|
2100
|
+
}
|
|
2101
|
+
function timestamp$1(value) {
|
|
2102
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) return invalid$12();
|
|
2103
|
+
return value;
|
|
2104
|
+
}
|
|
2105
|
+
function text$11(value) {
|
|
2106
|
+
if (typeof value !== "string" || !value.trim()) return invalid$12();
|
|
2107
|
+
return value;
|
|
2108
|
+
}
|
|
2109
|
+
function integerString(value) {
|
|
2110
|
+
if (typeof value !== "string" || !/^(?:0|[1-9]\d*)$/.test(value)) return invalid$12();
|
|
2111
|
+
return value;
|
|
2112
|
+
}
|
|
2113
|
+
function unit(raw) {
|
|
2114
|
+
if (raw.unit !== "ai_points") invalid$12();
|
|
2115
|
+
}
|
|
2116
|
+
function parseAiPointsAccount(raw, accountScope) {
|
|
2117
|
+
unit(raw);
|
|
2118
|
+
if (raw.points_per_cny !== 100 || !Array.isArray(raw.grants)) return invalid$12();
|
|
2119
|
+
const result = {
|
|
2120
|
+
accountScope,
|
|
2121
|
+
unit: "ai_points",
|
|
2122
|
+
availablePoints: points(raw.available_points),
|
|
2123
|
+
reservedPoints: points(raw.reserved_points),
|
|
2124
|
+
grantedPoints: points(raw.granted_points),
|
|
2125
|
+
purchasedPoints: points(raw.purchased_points),
|
|
2126
|
+
observedAt: timestamp$1(raw.observed_at),
|
|
2127
|
+
grants: raw.grants.map((value) => {
|
|
2128
|
+
const row = objectValue$2(value);
|
|
2129
|
+
return {
|
|
2130
|
+
source: text$11(row.source),
|
|
2131
|
+
availablePoints: points(row.available_points),
|
|
2132
|
+
expiresAt: timestamp$1(row.expires_at)
|
|
2133
|
+
};
|
|
2134
|
+
})
|
|
2135
|
+
};
|
|
2136
|
+
if (pointsUnits(result.availablePoints) !== pointsUnits(result.grantedPoints) + pointsUnits(result.purchasedPoints) || result.grants.reduce((total, grant) => total + pointsUnits(grant.availablePoints), 0n) !== pointsUnits(result.grantedPoints)) return invalid$12();
|
|
2137
|
+
return result;
|
|
2138
|
+
}
|
|
2139
|
+
function parseAiPointsPage(raw, accountScope, month) {
|
|
2140
|
+
unit(raw);
|
|
2141
|
+
if (raw.month !== month || !Array.isArray(raw.items)) return invalid$12();
|
|
2142
|
+
const nextBeforeId = raw.next_before_id === "" ? "" : integerString(raw.next_before_id);
|
|
2143
|
+
const result = {
|
|
2144
|
+
accountScope,
|
|
2145
|
+
unit: "ai_points",
|
|
2146
|
+
month,
|
|
2147
|
+
chargedPoints: points(raw.charged_points),
|
|
2148
|
+
nextBeforeId,
|
|
2149
|
+
items: raw.items.map((value) => {
|
|
2150
|
+
const row = objectValue$2(value), tokens = objectValue$2(row.tokens);
|
|
2151
|
+
const chargedPoints = points(row.charged_points), grantedPoints = points(row.granted_points), purchasedPoints = points(row.purchased_points);
|
|
2152
|
+
if (pointsUnits(chargedPoints) <= 0n || pointsUnits(chargedPoints) !== pointsUnits(grantedPoints) + pointsUnits(purchasedPoints)) return invalid$12();
|
|
2153
|
+
const modelPoints = points(row.model_points);
|
|
2154
|
+
if (!Array.isArray(row.services) || row.services.length > 16) return invalid$12();
|
|
2155
|
+
const services = row.services.map((value) => {
|
|
2156
|
+
const service = objectValue$2(value);
|
|
2157
|
+
const quantity = integerString(service.quantity), chargedPoints = points(service.charged_points);
|
|
2158
|
+
if (quantity === "0" || pointsUnits(chargedPoints) === 0n) return invalid$12();
|
|
2159
|
+
return {
|
|
2160
|
+
code: text$11(service.code),
|
|
2161
|
+
quantity,
|
|
2162
|
+
chargedPoints
|
|
2163
|
+
};
|
|
2164
|
+
});
|
|
2165
|
+
if (new Set(services.map((service) => service.code)).size !== services.length || pointsUnits(modelPoints) + services.reduce((sum, service) => sum + pointsUnits(service.chargedPoints), 0n) !== pointsUnits(chargedPoints)) return invalid$12();
|
|
2166
|
+
if (typeof row.business_code !== "string") return invalid$12();
|
|
2167
|
+
return {
|
|
2168
|
+
operationUid: typeof row.operation_uid === "string" ? row.operation_uid : "",
|
|
2169
|
+
requestUid: text$11(row.request_uid),
|
|
2170
|
+
businessCode: row.business_code,
|
|
2171
|
+
model: text$11(row.model),
|
|
2172
|
+
chargedPoints,
|
|
2173
|
+
modelPoints,
|
|
2174
|
+
services,
|
|
2175
|
+
grantedPoints,
|
|
2176
|
+
purchasedPoints,
|
|
2177
|
+
createdAt: timestamp$1(row.created_at),
|
|
2178
|
+
completedAt: timestamp$1(row.completed_at),
|
|
2179
|
+
tokens: {
|
|
2180
|
+
cacheHitInput: integerString(tokens.cache_hit_input),
|
|
2181
|
+
cacheMissInput: integerString(tokens.cache_miss_input),
|
|
2182
|
+
output: integerString(tokens.output)
|
|
2183
|
+
}
|
|
2184
|
+
};
|
|
2185
|
+
})
|
|
2186
|
+
};
|
|
2187
|
+
if (new Set(result.items.map((item) => item.requestUid)).size !== result.items.length || groupPointsConsumption(result.items).length > 20) return invalid$12();
|
|
2188
|
+
return result;
|
|
2189
|
+
}
|
|
2190
|
+
/** One owner for UI, SDK and Tools. It never reads raw usage telemetry. */
|
|
2191
|
+
var AiPointsService = class {
|
|
2192
|
+
runtime;
|
|
2193
|
+
constructor(runtime) {
|
|
2194
|
+
this.runtime = runtime;
|
|
2195
|
+
}
|
|
2196
|
+
async session(expectedScope) {
|
|
2197
|
+
const session = await this.runtime.requireSession();
|
|
2198
|
+
const scope = `${this.runtime.config.environment}:${session.userId}`;
|
|
2199
|
+
if (expectedScope !== void 0 && expectedScope !== scope) throw new ArkmePluginError("ai-points-account-changed", "账号已切换,请重新读取积分", false, 409);
|
|
2200
|
+
return {
|
|
2201
|
+
session,
|
|
2202
|
+
scope
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
async account(expectedScope, signal) {
|
|
2206
|
+
const { session, scope } = await this.session(expectedScope);
|
|
2207
|
+
const raw = await this.runtime.authenticatedIntelligentPost("/api/v1/managed-ai/points/query", {}, session, signal, {
|
|
2208
|
+
lane: "interactive-read",
|
|
2209
|
+
bypassCache: true
|
|
2210
|
+
});
|
|
2211
|
+
await this.session(scope);
|
|
2212
|
+
return parseAiPointsAccount(raw, scope);
|
|
2213
|
+
}
|
|
2214
|
+
async consumption(query, expectedScope, signal) {
|
|
2215
|
+
if (!/^\d{4}-(?:0[1-9]|1[0-2])$/.test(query.month) || query.beforeId !== void 0 && !/^[1-9]\d*$/.test(query.beforeId)) throw new ArkmePluginError("ai-points-query-invalid", "请选择有效月份", false, 400);
|
|
2216
|
+
const { session, scope } = await this.session(expectedScope);
|
|
2217
|
+
const raw = await this.runtime.authenticatedIntelligentPost("/api/v1/managed-ai/points/consumption/query", {
|
|
2218
|
+
month: query.month,
|
|
2219
|
+
before_id: query.beforeId ?? "",
|
|
2220
|
+
limit: 20
|
|
2221
|
+
}, session, signal, {
|
|
2222
|
+
lane: "interactive-read",
|
|
2223
|
+
bypassCache: true
|
|
2224
|
+
});
|
|
2225
|
+
await this.session(scope);
|
|
2226
|
+
return parseAiPointsPage(raw, scope, query.month);
|
|
2227
|
+
}
|
|
2228
|
+
};
|
|
2229
|
+
//#endregion
|
|
2052
2230
|
//#region src/self-role-avatar-store.ts
|
|
2053
2231
|
const MAX_SELF_ROLE_AVATAR_BYTES = 8 * 1024 * 1024;
|
|
2054
2232
|
const PREFIX = "arkme-self-role-image-v1.";
|
|
@@ -3147,6 +3325,13 @@ function errorCode$1(status, body) {
|
|
|
3147
3325
|
const providerCode = typeof providerError?.code === "string" ? providerError.code.toLowerCase() : "";
|
|
3148
3326
|
if (status === 401 || status === 403) return "AUTH";
|
|
3149
3327
|
if (status === 402 || providerCode.includes("balance") || providerCode.includes("quota")) return "QUOTA";
|
|
3328
|
+
if (status === 409 && [
|
|
3329
|
+
"operation_closed",
|
|
3330
|
+
"operation_limit",
|
|
3331
|
+
"operation_conflict"
|
|
3332
|
+
].includes(providerCode)) return "OPERATION_ENDED";
|
|
3333
|
+
if (providerCode === "unsupported_model") return "UNKNOWN_MODEL";
|
|
3334
|
+
if (status === 409 && providerCode === "request_in_progress") return "REQUEST_IN_PROGRESS";
|
|
3150
3335
|
if (status === 408 || status === 504) return "TIMEOUT";
|
|
3151
3336
|
if (status === 429) return "RATE_LIMIT";
|
|
3152
3337
|
if (status === 400 || status === 413 || status === 422) return "INVALID_REQUEST";
|
|
@@ -3618,6 +3803,7 @@ var ManagedAiTransport = class {
|
|
|
3618
3803
|
const imageAttachments = requestImageAttachments(request);
|
|
3619
3804
|
assertImageRequestWithinCapability(imageAttachments, capability);
|
|
3620
3805
|
const bearer = await this.options.resolveBearer();
|
|
3806
|
+
const operationUid = this.options.prepareOperation?.(request, bearer);
|
|
3621
3807
|
const imageCapability = capability.image;
|
|
3622
3808
|
for (let dispatchAttempt = 0;; dispatchAttempt++) {
|
|
3623
3809
|
let resolvedImageBytes = 0;
|
|
@@ -3634,6 +3820,7 @@ var ManagedAiTransport = class {
|
|
|
3634
3820
|
method: "POST",
|
|
3635
3821
|
headers: {
|
|
3636
3822
|
Authorization: `Bearer ${bearer}`,
|
|
3823
|
+
...operationUid === void 0 ? {} : { "X-Arkme-Turn-ID": operationUid },
|
|
3637
3824
|
Accept: "text/event-stream",
|
|
3638
3825
|
"Content-Type": "application/json",
|
|
3639
3826
|
...attributionHeaders(),
|
|
@@ -3893,7 +4080,7 @@ const ARKME_MANAGED_CATALOG_MAX_STALE_MS = 5 * ARKME_MANAGED_CATALOG_TTL_MS;
|
|
|
3893
4080
|
const ARKME_MANAGED_CATALOG_TIMEOUT_MS = 1e4;
|
|
3894
4081
|
const ARKME_MANAGED_MAXIMUM_IMAGE_PIXELS = 4e7;
|
|
3895
4082
|
const ARKME_MANAGED_MAXIMUM_REQUEST_IMAGE_BYTES = 1 << 30;
|
|
3896
|
-
const ARKME_INSUFFICIENT_BALANCE_MESSAGE = "
|
|
4083
|
+
const ARKME_INSUFFICIENT_BALANCE_MESSAGE = "AI 额度不足,请充值后继续";
|
|
3897
4084
|
const ARKME_LOGIN_MESSAGE = "请先登录或重新登录 Arkme 后再使用托管模型";
|
|
3898
4085
|
const ARKME_AUTH_FAILURE_CODES = /* @__PURE__ */ new Set([
|
|
3899
4086
|
"login-required",
|
|
@@ -3928,6 +4115,14 @@ function managedAiFailureFacts(error) {
|
|
|
3928
4115
|
};
|
|
3929
4116
|
}
|
|
3930
4117
|
function managedAiLocalizedFailure(facts) {
|
|
4118
|
+
if (facts.code === "OPERATION_ENDED") return {
|
|
4119
|
+
code: facts.code,
|
|
4120
|
+
message: "本轮任务已结束,请发送新消息继续"
|
|
4121
|
+
};
|
|
4122
|
+
if (facts.code === "REQUEST_IN_PROGRESS") return {
|
|
4123
|
+
code: facts.code,
|
|
4124
|
+
message: "已有 AI 请求正在完成,请等待结果后重试"
|
|
4125
|
+
};
|
|
3931
4126
|
if (facts.status === 402 || ["QUOTA", "INSUFFICIENT_BALANCE"].includes(facts.code)) return {
|
|
3932
4127
|
code: "INSUFFICIENT_BALANCE",
|
|
3933
4128
|
message: ARKME_INSUFFICIENT_BALANCE_MESSAGE
|
|
@@ -4271,6 +4466,21 @@ function parseReasoning(value) {
|
|
|
4271
4466
|
defaultEffort: ReasoningEffortId(defaultEffort)
|
|
4272
4467
|
};
|
|
4273
4468
|
}
|
|
4469
|
+
function modelPointPriceDescription(value) {
|
|
4470
|
+
const price = asRecord(value);
|
|
4471
|
+
if (!price) return "计费信息暂时无法读取,实际按用量扣积分";
|
|
4472
|
+
const read = (key) => {
|
|
4473
|
+
const v = price[key];
|
|
4474
|
+
if (typeof v !== "string") throw new LlmError("模型积分报价无效", "MALFORMED_RESPONSE");
|
|
4475
|
+
try {
|
|
4476
|
+
pointsUnits(v);
|
|
4477
|
+
} catch {
|
|
4478
|
+
throw new LlmError("模型积分报价无效", "MALFORMED_RESPONSE");
|
|
4479
|
+
}
|
|
4480
|
+
return v;
|
|
4481
|
+
};
|
|
4482
|
+
return `每 1,000 Token:输入 ${read("cache_miss_input_per_thousand")} 积分,缓存输入 ${read("cache_hit_input_per_thousand")} 积分,输出 ${read("output_per_thousand")} 积分。`;
|
|
4483
|
+
}
|
|
4274
4484
|
function parseManagedCatalog(payload) {
|
|
4275
4485
|
const envelope = asRecord(payload);
|
|
4276
4486
|
if (envelope?.code !== 200) {
|
|
@@ -4298,6 +4508,7 @@ function parseManagedCatalog(payload) {
|
|
|
4298
4508
|
return {
|
|
4299
4509
|
id,
|
|
4300
4510
|
name: requiredCatalogText(item, "display_name", "显示名称"),
|
|
4511
|
+
description: modelPointPriceDescription(item.point_pricing),
|
|
4301
4512
|
contextWindow,
|
|
4302
4513
|
maxTokens: defaultMaxTokens
|
|
4303
4514
|
};
|
|
@@ -4358,7 +4569,7 @@ var ManagedModelCatalog = class {
|
|
|
4358
4569
|
canUseLastGood() {
|
|
4359
4570
|
return this.hasRemoteSnapshot && Date.now() - this.refreshedAt < ARKME_MANAGED_CATALOG_MAX_STALE_MS;
|
|
4360
4571
|
}
|
|
4361
|
-
async fetchCatalog(signal) {
|
|
4572
|
+
async fetchCatalog(signal, resolveModel) {
|
|
4362
4573
|
const controller = new AbortController();
|
|
4363
4574
|
let timedOut = false;
|
|
4364
4575
|
const abortFromCaller = () => {
|
|
@@ -4380,7 +4591,7 @@ var ManagedModelCatalog = class {
|
|
|
4380
4591
|
Authorization: `Bearer ${bearer}`,
|
|
4381
4592
|
"Content-Type": "application/json"
|
|
4382
4593
|
},
|
|
4383
|
-
body:
|
|
4594
|
+
body: JSON.stringify(resolveModel === void 0 ? {} : { resolve_model: resolveModel }),
|
|
4384
4595
|
signal: controller.signal
|
|
4385
4596
|
});
|
|
4386
4597
|
if (!response.ok) {
|
|
@@ -4398,12 +4609,19 @@ var ManagedModelCatalog = class {
|
|
|
4398
4609
|
throw new LlmError("Arkme 模型目录返回异常", "MALFORMED_RESPONSE", { cause: error });
|
|
4399
4610
|
}
|
|
4400
4611
|
const snapshot = parseManagedCatalog(payload);
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4612
|
+
if (resolveModel !== void 0) {
|
|
4613
|
+
if (snapshot.models.length !== 1 || snapshot.models[0]?.id !== resolveModel) throw new LlmError("原回合模型信息无效", "UNKNOWN_MODEL");
|
|
4614
|
+
this.connectionSnapshot = managedConnection(this.baseUrl, [...this.connectionSnapshot.models.filter((item) => item.id !== resolveModel), ...snapshot.models]);
|
|
4615
|
+
for (const [key, value] of snapshot.capabilities) this.capabilitySnapshot.set(key, value);
|
|
4616
|
+
for (const [key, value] of snapshot.reasoning) this.reasoningSnapshot.set(key, value);
|
|
4617
|
+
} else {
|
|
4618
|
+
this.connectionSnapshot = managedConnection(this.baseUrl, snapshot.models);
|
|
4619
|
+
this.modelIds = new Set(snapshot.models.map((model) => model.id));
|
|
4620
|
+
this.capabilitySnapshot = snapshot.capabilities;
|
|
4621
|
+
this.reasoningSnapshot = snapshot.reasoning;
|
|
4622
|
+
this.hasRemoteSnapshot = true;
|
|
4623
|
+
this.refreshedAt = Date.now();
|
|
4624
|
+
}
|
|
4407
4625
|
} catch (error) {
|
|
4408
4626
|
if (signal?.aborted === true) throw localizeManagedAiError(new LlmError("Arkme 模型目录请求已取消", "ABORTED", { cause: error }));
|
|
4409
4627
|
if (timedOut) throw localizeManagedAiError(new LlmError("Arkme 模型目录请求超时", "TIMEOUT", { cause: error }));
|
|
@@ -4433,15 +4651,29 @@ var ManagedModelCatalog = class {
|
|
|
4433
4651
|
}
|
|
4434
4652
|
async ensureModel(model, signal) {
|
|
4435
4653
|
const known = this.modelIds.has(model);
|
|
4436
|
-
if (this.isFresh())
|
|
4437
|
-
try {
|
|
4654
|
+
if (!this.isFresh()) try {
|
|
4438
4655
|
await this.refresh(signal);
|
|
4439
4656
|
} catch (error) {
|
|
4440
4657
|
if (signal?.aborted === true || !this.canUseLastGood() || !known) throw error;
|
|
4441
4658
|
}
|
|
4659
|
+
if (!this.modelIds.has(model)) try {
|
|
4660
|
+
await this.fetchCatalog(signal, model);
|
|
4661
|
+
} catch (error) {
|
|
4662
|
+
if (signal?.aborted === true) throw error;
|
|
4663
|
+
const facts = managedAiFailureFacts(error);
|
|
4664
|
+
if ((facts.status ?? 0) >= 500 || [
|
|
4665
|
+
"TRANSPORT",
|
|
4666
|
+
"TIMEOUT",
|
|
4667
|
+
"AUTH"
|
|
4668
|
+
].includes(facts.code)) throw error;
|
|
4669
|
+
throw new LlmError("原回合模型已不可用,请重新选择模型", "UNKNOWN_MODEL", { cause: error });
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
isListed(model) {
|
|
4673
|
+
return this.modelIds.has(model);
|
|
4442
4674
|
}
|
|
4443
4675
|
assertModel(model) {
|
|
4444
|
-
if (!this.
|
|
4676
|
+
if (!this.capabilitySnapshot.has(model)) throw new LlmError(`当前 Arkme 托管服务不支持模型“${model}”,请重新选择模型`, "UNKNOWN_MODEL");
|
|
4445
4677
|
}
|
|
4446
4678
|
};
|
|
4447
4679
|
var ManagedAiLlmAdapter = class extends LlmAdapter {
|
|
@@ -4466,7 +4698,7 @@ var ManagedAiLlmAdapter = class extends LlmAdapter {
|
|
|
4466
4698
|
async listModels(provider) {
|
|
4467
4699
|
assertManagedProvider(provider);
|
|
4468
4700
|
await this.catalog.refreshForListing();
|
|
4469
|
-
return (await this.delegate.listModels(provider)).map((model) => ({
|
|
4701
|
+
return (await this.delegate.listModels(provider)).filter((model) => this.catalog.isListed(model.id)).map((model) => ({
|
|
4470
4702
|
...model,
|
|
4471
4703
|
inputModalities: this.catalog.capability(model.id).inputModalities
|
|
4472
4704
|
}));
|
|
@@ -4511,7 +4743,8 @@ function createManagedAiLlmAdapter(options) {
|
|
|
4511
4743
|
resolveAttachmentReader: options.resolveAttachmentReader ?? (() => void 0),
|
|
4512
4744
|
fetchImpl,
|
|
4513
4745
|
resolveBearer: async () => await resolveBearer(options.credentialOwner),
|
|
4514
|
-
resolveAnonymousUserId
|
|
4746
|
+
resolveAnonymousUserId,
|
|
4747
|
+
...options.prepareOperation === void 0 ? {} : { prepareOperation: options.prepareOperation }
|
|
4515
4748
|
}));
|
|
4516
4749
|
}
|
|
4517
4750
|
function registerManagedAiProvider(ctx, options) {
|
|
@@ -15364,7 +15597,7 @@ function tokenizeThematicBreak(effects, ok, nok) {
|
|
|
15364
15597
|
* } from 'micromark-util-types'
|
|
15365
15598
|
*/
|
|
15366
15599
|
/** @type {Construct} */
|
|
15367
|
-
const list$
|
|
15600
|
+
const list$4 = {
|
|
15368
15601
|
continuation: { tokenize: tokenizeListContinuation },
|
|
15369
15602
|
exit: tokenizeListEnd,
|
|
15370
15603
|
name: "list",
|
|
@@ -15484,7 +15717,7 @@ function tokenizeListContinuation(effects, ok, nok) {
|
|
|
15484
15717
|
function notInCurrentItem(code) {
|
|
15485
15718
|
self.containerState._closeFlow = true;
|
|
15486
15719
|
self.interrupt = void 0;
|
|
15487
|
-
return factorySpace(effects, effects.attempt(list$
|
|
15720
|
+
return factorySpace(effects, effects.attempt(list$4, ok, nok), "linePrefix", self.parser.constructs.disable.null.includes("codeIndented") ? void 0 : 4)(code);
|
|
15488
15721
|
}
|
|
15489
15722
|
}
|
|
15490
15723
|
/**
|
|
@@ -15735,7 +15968,7 @@ function initializeFlow(effects) {
|
|
|
15735
15968
|
* } from 'micromark-util-types'
|
|
15736
15969
|
*/
|
|
15737
15970
|
const resolver = { resolveAll: createResolver() };
|
|
15738
|
-
const string$
|
|
15971
|
+
const string$1 = initializeFactory("string");
|
|
15739
15972
|
const text$10 = initializeFactory("text");
|
|
15740
15973
|
/**
|
|
15741
15974
|
* @param {'string' | 'text'} field
|
|
@@ -15912,24 +16145,24 @@ var constructs_exports = /* @__PURE__ */ __exportAll({
|
|
|
15912
16145
|
flow: () => flow,
|
|
15913
16146
|
flowInitial: () => flowInitial,
|
|
15914
16147
|
insideSpan: () => insideSpan,
|
|
15915
|
-
string: () => string
|
|
16148
|
+
string: () => string,
|
|
15916
16149
|
text: () => text$9
|
|
15917
16150
|
});
|
|
15918
16151
|
/** @satisfies {Extension['document']} */
|
|
15919
16152
|
const document$1 = {
|
|
15920
|
-
[42]: list$
|
|
15921
|
-
[43]: list$
|
|
15922
|
-
[45]: list$
|
|
15923
|
-
[48]: list$
|
|
15924
|
-
[49]: list$
|
|
15925
|
-
[50]: list$
|
|
15926
|
-
[51]: list$
|
|
15927
|
-
[52]: list$
|
|
15928
|
-
[53]: list$
|
|
15929
|
-
[54]: list$
|
|
15930
|
-
[55]: list$
|
|
15931
|
-
[56]: list$
|
|
15932
|
-
[57]: list$
|
|
16153
|
+
[42]: list$4,
|
|
16154
|
+
[43]: list$4,
|
|
16155
|
+
[45]: list$4,
|
|
16156
|
+
[48]: list$4,
|
|
16157
|
+
[49]: list$4,
|
|
16158
|
+
[50]: list$4,
|
|
16159
|
+
[51]: list$4,
|
|
16160
|
+
[52]: list$4,
|
|
16161
|
+
[53]: list$4,
|
|
16162
|
+
[54]: list$4,
|
|
16163
|
+
[55]: list$4,
|
|
16164
|
+
[56]: list$4,
|
|
16165
|
+
[57]: list$4,
|
|
15933
16166
|
[62]: blockQuote
|
|
15934
16167
|
};
|
|
15935
16168
|
/** @satisfies {Extension['contentInitial']} */
|
|
@@ -15952,7 +16185,7 @@ const flow = {
|
|
|
15952
16185
|
[126]: codeFenced
|
|
15953
16186
|
};
|
|
15954
16187
|
/** @satisfies {Extension['string']} */
|
|
15955
|
-
const string
|
|
16188
|
+
const string = {
|
|
15956
16189
|
[38]: characterReference,
|
|
15957
16190
|
[92]: characterEscape
|
|
15958
16191
|
};
|
|
@@ -16472,7 +16705,7 @@ function parse(options) {
|
|
|
16472
16705
|
document: create(document$2),
|
|
16473
16706
|
flow: create(flow$1),
|
|
16474
16707
|
lazy: {},
|
|
16475
|
-
string: create(string$
|
|
16708
|
+
string: create(string$1),
|
|
16476
16709
|
text: create(text$10)
|
|
16477
16710
|
};
|
|
16478
16711
|
return parser;
|
|
@@ -20267,7 +20500,7 @@ function checkRule(state) {
|
|
|
20267
20500
|
* @param {Info} info
|
|
20268
20501
|
* @returns {string}
|
|
20269
20502
|
*/
|
|
20270
|
-
function list$
|
|
20503
|
+
function list$3(node, parent, state, info) {
|
|
20271
20504
|
const exit = state.enter("list");
|
|
20272
20505
|
const bulletCurrent = state.bulletCurrent;
|
|
20273
20506
|
/** @type {string} */
|
|
@@ -20542,7 +20775,7 @@ const handle = {
|
|
|
20542
20775
|
inlineCode,
|
|
20543
20776
|
link,
|
|
20544
20777
|
linkReference,
|
|
20545
|
-
list: list$
|
|
20778
|
+
list: list$3,
|
|
20546
20779
|
listItem,
|
|
20547
20780
|
paragraph,
|
|
20548
20781
|
root,
|
|
@@ -36218,18 +36451,14 @@ var HttpArkmeBillingGateway = class {
|
|
|
36218
36451
|
return new ArkmePluginError(error.code, error.message, retryable, error.httpStatus, { cause: error });
|
|
36219
36452
|
}
|
|
36220
36453
|
async quota(signal) {
|
|
36221
|
-
const
|
|
36222
|
-
const
|
|
36223
|
-
|
|
36224
|
-
const availableNanoCny = nanoCny(data.available_nano_cny, "available_nano_cny");
|
|
36225
|
-
const totalNanoCny = nanoCny(data.total_nano_cny, "total_nano_cny");
|
|
36226
|
-
const reservedNanoCny = nanoCny(data.reserved_nano_cny, "reserved_nano_cny");
|
|
36227
|
-
if (BigInt(availableNanoCny) + BigInt(reservedNanoCny) !== BigInt(totalNanoCny)) throw new ArkmePluginError("billing-contract-invalid", "余额接口金额不一致", true, 502);
|
|
36454
|
+
const account = parseAiPointsAccount(objectValue$2(await this.post("intelligent", "/api/v1/managed-ai/points/query", {}, "interactive-read", signal)), "");
|
|
36455
|
+
const availableNanoCny = pointsUnits(account.availablePoints);
|
|
36456
|
+
const reservedNanoCny = pointsUnits(account.reservedPoints);
|
|
36228
36457
|
return {
|
|
36229
|
-
availableNanoCny,
|
|
36230
|
-
totalNanoCny,
|
|
36231
|
-
reservedNanoCny,
|
|
36232
|
-
currency
|
|
36458
|
+
availableNanoCny: String(availableNanoCny),
|
|
36459
|
+
totalNanoCny: String(availableNanoCny + reservedNanoCny),
|
|
36460
|
+
reservedNanoCny: String(reservedNanoCny),
|
|
36461
|
+
currency: "CNY"
|
|
36233
36462
|
};
|
|
36234
36463
|
}
|
|
36235
36464
|
async products(signal) {
|
|
@@ -36855,6 +37084,7 @@ function arkoModelOptionFromData(value) {
|
|
|
36855
37084
|
displayName,
|
|
36856
37085
|
provider,
|
|
36857
37086
|
description,
|
|
37087
|
+
costDescription: stringValue$2(data.cost_description),
|
|
36858
37088
|
recommended: booleanValue$14(data.recommended),
|
|
36859
37089
|
selected: booleanValue$14(data.selected)
|
|
36860
37090
|
};
|
|
@@ -36866,7 +37096,7 @@ function arkoModelCatalogFromData(data) {
|
|
|
36866
37096
|
const options = listValue$26(data.items).map(arkoModelOptionFromData);
|
|
36867
37097
|
const routeKeys = new Set(options.map((option) => option.routeKey));
|
|
36868
37098
|
const selected = options.filter((option) => option.selected);
|
|
36869
|
-
if (selectionSource !== "default" && selectionSource !== "personal" || options.length === 0 || options.length >
|
|
37099
|
+
if (selectionSource !== "default" && selectionSource !== "personal" && selectionSource !== "unavailable" || options.length === 0 || options.length > 256 || routeKeys.size !== options.length || !routeKeys.has(defaultRouteKey) || (selectionSource === "unavailable" ? routeKeys.has(effectiveRouteKey) || selected.length !== 0 : !routeKeys.has(effectiveRouteKey) || selected.length !== 1 || selected[0]?.routeKey !== effectiveRouteKey)) throw new ArkmePluginError("arko-model-contract-invalid", "Arko 模型目录响应无效", true, 502);
|
|
36870
37100
|
return {
|
|
36871
37101
|
defaultRouteKey,
|
|
36872
37102
|
effectiveRouteKey,
|
|
@@ -37053,8 +37283,7 @@ var ArkoService = class {
|
|
|
37053
37283
|
let modelRouteKey = options.modelRouteKey?.trim() ?? "";
|
|
37054
37284
|
if (hasContinuationRun && modelRouteKey !== "") throw new ArkmePluginError("arko-continuation-model-invalid", "继续 Arko 任务时不能切换模型", false);
|
|
37055
37285
|
if (!hasContinuationRun && modelRouteKey === "") try {
|
|
37056
|
-
|
|
37057
|
-
if (catalog.options.length > 1) modelRouteKey = catalog.effectiveRouteKey;
|
|
37286
|
+
modelRouteKey = (await this.arkoModelCatalog(options.signal)).effectiveRouteKey;
|
|
37058
37287
|
} catch {}
|
|
37059
37288
|
if (modelRouteKey !== "" && (modelRouteKey.length > 128 || !ARKO_MODEL_ROUTE_PATTERN.test(modelRouteKey))) throw new ArkmePluginError("arko-model-route-invalid", "请选择有效的 Arko 模型", false);
|
|
37060
37289
|
const body = {
|
|
@@ -39359,7 +39588,7 @@ async function readTopicMetadata(runtime, session, topicUid, signal) {
|
|
|
39359
39588
|
}
|
|
39360
39589
|
//#endregion
|
|
39361
39590
|
//#region src/avatar-diagnostics.ts
|
|
39362
|
-
function record
|
|
39591
|
+
function record(value) {
|
|
39363
39592
|
return value !== null && typeof value === "object" ? value : {};
|
|
39364
39593
|
}
|
|
39365
39594
|
function positiveId(value) {
|
|
@@ -39375,7 +39604,7 @@ function avatarReferenceDiagnostic(imageRef) {
|
|
|
39375
39604
|
const encoded = parts[1] ?? "";
|
|
39376
39605
|
if (parts.length !== 3 || encoded.length > 1024 || !/^[A-Za-z0-9_-]+$/.test(encoded)) return context;
|
|
39377
39606
|
const base64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
39378
|
-
const payload = record
|
|
39607
|
+
const payload = record(JSON.parse(globalThis.atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "="))));
|
|
39379
39608
|
if (payload.version !== 1) return context;
|
|
39380
39609
|
const viewer = positiveId(payload.viewerUserId);
|
|
39381
39610
|
const target = positiveId(payload.targetUserId);
|
|
@@ -39397,8 +39626,8 @@ function imageDownloadStatus(error) {
|
|
|
39397
39626
|
}
|
|
39398
39627
|
function logArkmeAvatarDiagnostic(event, context, error) {
|
|
39399
39628
|
try {
|
|
39400
|
-
const source = record
|
|
39401
|
-
const body = record
|
|
39629
|
+
const source = record(error);
|
|
39630
|
+
const body = record(source.body);
|
|
39402
39631
|
const detail = source.name === "ArkmeClientError" ? body : source;
|
|
39403
39632
|
const errorName = [
|
|
39404
39633
|
"Error",
|
|
@@ -39418,7 +39647,7 @@ function logArkmeAvatarDiagnostic(event, context, error) {
|
|
|
39418
39647
|
retryable: typeof detail.retryable === "boolean" ? detail.retryable : void 0,
|
|
39419
39648
|
httpStatus: httpStatus(source.httpStatus),
|
|
39420
39649
|
upstreamStatus: httpStatus(source.upstreamStatus) ?? imageDownloadStatus(source),
|
|
39421
|
-
causeCode: safeErrorCode(record
|
|
39650
|
+
causeCode: safeErrorCode(record(source.cause).code)
|
|
39422
39651
|
} }
|
|
39423
39652
|
})}`);
|
|
39424
39653
|
} catch {}
|
|
@@ -46661,7 +46890,7 @@ function botDisplayName(profiles, uid) {
|
|
|
46661
46890
|
}
|
|
46662
46891
|
//#endregion
|
|
46663
46892
|
//#region src/services/chat-sender-display-reader.ts
|
|
46664
|
-
const list$
|
|
46893
|
+
const list$2 = (value) => Array.isArray(value) ? value : [];
|
|
46665
46894
|
const text$3 = (value) => stringValue$2(value).trim();
|
|
46666
46895
|
const first = (raw, keys) => keys.map((key) => text$3(raw[key])).find(Boolean) ?? "";
|
|
46667
46896
|
/** Normalize wire data once. Neither raw participants nor their extra fields escape this adapter. */
|
|
@@ -46671,7 +46900,7 @@ function botDisplaySnapshot(bundle) {
|
|
|
46671
46900
|
const extra = objectValue$2(session.extra);
|
|
46672
46901
|
const groupTarget = arkmeGroupBotBindingTargetFromBundle(bundle) ?? arkmeGroupBotBindingTargetFromBundle({ rm_subject_id: extra.subject_id ?? extra.legacy_subject_id });
|
|
46673
46902
|
const profiles = /* @__PURE__ */ new Map();
|
|
46674
|
-
for (const value of list$
|
|
46903
|
+
for (const value of list$2(bundle.bot_participants)) {
|
|
46675
46904
|
const participant = objectValue$2(value);
|
|
46676
46905
|
const uid = text$3(participant.bot_uid);
|
|
46677
46906
|
if (uid === "" || text$3(participant.chat_session_uid) !== chatSessionUid) continue;
|
|
@@ -46717,7 +46946,7 @@ var RuntimeBotDisplayProfilesReader = class {
|
|
|
46717
46946
|
let snapshot = input.snapshot;
|
|
46718
46947
|
if (snapshot === void 0) try {
|
|
46719
46948
|
const data = await this.runtime.authenticatedChatPost("/api/v1/chats/display-snapshots", { chat_session_uids: [input.chatSessionUid] }, session, identitySignal, { refreshOnUnauthorized: false });
|
|
46720
|
-
snapshot = list$
|
|
46949
|
+
snapshot = list$2(data.items).map((value) => botDisplaySnapshot(objectValue$2(value))).find((item) => item.chatSessionUid === input.chatSessionUid);
|
|
46721
46950
|
} catch (error) {
|
|
46722
46951
|
optionalFailure(error);
|
|
46723
46952
|
}
|
|
@@ -46748,7 +46977,7 @@ var RuntimeBotDisplayProfilesReader = class {
|
|
|
46748
46977
|
cancelWhenUnobserved: true
|
|
46749
46978
|
});
|
|
46750
46979
|
const profiles = /* @__PURE__ */ new Map();
|
|
46751
|
-
for (const value of list$
|
|
46980
|
+
for (const value of list$2(data.bots)) {
|
|
46752
46981
|
const raw = objectValue$2(value);
|
|
46753
46982
|
if (raw.installed === true && text$3(raw.bot_id) !== "" && text$3(raw.name) !== "") profiles.set(text$3(raw.bot_id), {
|
|
46754
46983
|
displayName: text$3(raw.name),
|
|
@@ -47108,6 +47337,23 @@ function integer$1(value) {
|
|
|
47108
47337
|
const parsed = typeof value === "number" ? value : Number(value);
|
|
47109
47338
|
return Number.isSafeInteger(parsed) ? parsed : 0;
|
|
47110
47339
|
}
|
|
47340
|
+
/** The tree can be centered on the child while its parent lives outside the topic. */
|
|
47341
|
+
function projectOwnedRecordParent(response, openedRecordUid) {
|
|
47342
|
+
const data = object$3(response);
|
|
47343
|
+
if (openedRecordUid === "" || text$2(data.record_uid) !== openedRecordUid || text$2(data.root_record_uid) === "") throw new Error("记录延展树与当前快记不匹配");
|
|
47344
|
+
let parentUid = text$2(data.parent_record_uid);
|
|
47345
|
+
if (data.parent_record_uid === void 0) parentUid = text$2((Array.isArray(data.edges) ? data.edges : []).map(object$3).find((edge) => text$2(edge.child_record_uid) === openedRecordUid && (edge.status === void 0 || integer$1(edge.status) === 1))?.parent_record_uid);
|
|
47346
|
+
if (parentUid === "" || parentUid === openedRecordUid) return void 0;
|
|
47347
|
+
const record = (Array.isArray(data.records) ? data.records : []).map(object$3).find((record) => text$2(record.record_uid) === parentUid);
|
|
47348
|
+
return {
|
|
47349
|
+
recordUid: parentUid,
|
|
47350
|
+
parentRecordUid: "",
|
|
47351
|
+
level: 0,
|
|
47352
|
+
record: record ?? {},
|
|
47353
|
+
createdAtMillis: 0,
|
|
47354
|
+
protectedContent: record === void 0 || integer$1(record.content_access_state) !== 1 || record.status !== void 0 && integer$1(record.status) !== 1
|
|
47355
|
+
};
|
|
47356
|
+
}
|
|
47111
47357
|
function parseNode(value, visiting, budget) {
|
|
47112
47358
|
const raw = object$3(value);
|
|
47113
47359
|
const recordUid = text$2(raw.record_uid);
|
|
@@ -51760,13 +52006,22 @@ var ChatService = class {
|
|
|
51760
52006
|
for (const child of listValue$16(data.children)) {
|
|
51761
52007
|
const extension = chatExtensionTreeItemFromData(child, parentRecordUid);
|
|
51762
52008
|
if (extension === void 0) continue;
|
|
51763
|
-
const
|
|
52009
|
+
const childItem = objectValue$2(objectValue$2(child).item);
|
|
52010
|
+
const relation = objectValue$2(childItem.relation);
|
|
52011
|
+
const record = objectValue$2(childItem.record);
|
|
51764
52012
|
const payload = objectValue$2(record.payload);
|
|
51765
52013
|
const mentions = await this.timelineMentionTargets(record, payload, session.userId, chatSessionUid);
|
|
52014
|
+
const senderUserId = integerLikeValue(relation.sender_user_id ?? relation.senderUserId);
|
|
52015
|
+
const humanSender = senderUserId > 0 && !timelineSenderIsBot(relation);
|
|
52016
|
+
const senderMemberRef = humanSender ? await this.sealChatMemberRef(session.userId, chatSessionUid, senderUserId) : void 0;
|
|
52017
|
+
const currentAvatarRef = humanSender ? await this.profile.sealProfileImageRef(session.userId, senderUserId).catch(() => void 0) : void 0;
|
|
51766
52018
|
projections.push({
|
|
51767
|
-
extension:
|
|
52019
|
+
extension: {
|
|
51768
52020
|
...extension,
|
|
51769
|
-
mentions
|
|
52021
|
+
...mentions === void 0 ? {} : { mentions },
|
|
52022
|
+
...senderMemberRef === void 0 ? {} : { senderMemberRef },
|
|
52023
|
+
...humanSender ? { senderIsMe: senderUserId === session.userId } : {},
|
|
52024
|
+
...currentAvatarRef === void 0 ? {} : { senderAvatarUrl: currentAvatarRef }
|
|
51770
52025
|
},
|
|
51771
52026
|
mediaRecord: chatExtensionMediaRecord(child, extension.recordUid)
|
|
51772
52027
|
});
|
|
@@ -51779,12 +52034,66 @@ var ChatService = class {
|
|
|
51779
52034
|
};
|
|
51780
52035
|
}
|
|
51781
52036
|
/** Personal and topic notes share the record-owned tree, including replies outside the original topic. */
|
|
52037
|
+
async ownedRecordParentFromTree(data, recordUid, session, signal) {
|
|
52038
|
+
const parent = projectOwnedRecordParent(data, recordUid);
|
|
52039
|
+
if (parent === void 0) return void 0;
|
|
52040
|
+
const owner = recordOwnerId(parent.record.owner_user_id);
|
|
52041
|
+
if (parent.protectedContent || owner !== 0 && owner !== session.userId || arkmePrivacyLockedRecord(parent.record) || this.privacy !== void 0 && (await this.privacy.lockedRecordUids(session, signal)).has(parent.recordUid)) return {
|
|
52042
|
+
itemUid: parent.recordUid,
|
|
52043
|
+
senderName: "",
|
|
52044
|
+
title: "",
|
|
52045
|
+
textContent: "该延展源暂不可用"
|
|
52046
|
+
};
|
|
52047
|
+
const hydration = await this.media.hydrateRecordMediaPage([parent.record], session, signal);
|
|
52048
|
+
const item = this.record.recordTimelineItemFromRaw(parent.record, session.userId, {
|
|
52049
|
+
displayItems: hydration.displayItemsByRecordUid.get(parent.recordUid) ?? [],
|
|
52050
|
+
mediaUnavailable: hydration.unavailableRecordUids.has(parent.recordUid)
|
|
52051
|
+
});
|
|
52052
|
+
return {
|
|
52053
|
+
itemUid: parent.recordUid,
|
|
52054
|
+
senderName: item.senderName,
|
|
52055
|
+
title: item.title,
|
|
52056
|
+
textContent: item.textContent,
|
|
52057
|
+
textFormat: item.textFormat ?? "plain",
|
|
52058
|
+
sendAtMillis: item.sendAtMillis,
|
|
52059
|
+
...owner === 0 ? {} : { recordOwnerUserId: owner },
|
|
52060
|
+
...item.contentBlocks === void 0 ? {} : { contentBlocks: item.contentBlocks }
|
|
52061
|
+
};
|
|
52062
|
+
}
|
|
52063
|
+
/** Lightweight visible-row enrichment; never reads an entire topic before showing it. */
|
|
52064
|
+
async sourceMessageExtensionParent(sourceRef, actionRef, options = {}) {
|
|
52065
|
+
const session = await this.runtime.requireSession();
|
|
52066
|
+
const source = await this.source.openSourceRef(sourceRef.trim(), session.userId);
|
|
52067
|
+
const reference = await this.openMessageActionRef(actionRef, session.userId, source);
|
|
52068
|
+
if (reference.sourceKind !== "record" || ![
|
|
52069
|
+
"send_to_self",
|
|
52070
|
+
"default_category",
|
|
52071
|
+
"topic"
|
|
52072
|
+
].includes(source.kind)) throw new ArkmePluginError("record-extension-source-invalid", "当前来源不支持读取个人延展源", false, 403);
|
|
52073
|
+
const data = await this.runtime.authenticatedPost("/api/v1/records/extensions/tree", { record_uid: reference.recordUid }, session, options.signal, {
|
|
52074
|
+
lane: "background-read",
|
|
52075
|
+
key: `record-extension-parent:${reference.recordUid}`,
|
|
52076
|
+
cacheMs: 5e3,
|
|
52077
|
+
failureCooldownMs: 2e3
|
|
52078
|
+
});
|
|
52079
|
+
const extensionParent = await this.ownedRecordParentFromTree(data, reference.recordUid, session, options.signal);
|
|
52080
|
+
return {
|
|
52081
|
+
recordUid: reference.recordUid,
|
|
52082
|
+
...extensionParent === void 0 ? {} : { extensionParent }
|
|
52083
|
+
};
|
|
52084
|
+
}
|
|
51782
52085
|
async loadOwnedRecordExtensions(recordUid, session, signal) {
|
|
51783
|
-
const
|
|
52086
|
+
const data = await this.runtime.authenticatedPost("/api/v1/records/extensions/tree", { record_uid: recordUid }, session, signal, {
|
|
51784
52087
|
lane: "interactive-read",
|
|
51785
52088
|
bypassCache: true
|
|
51786
|
-
})
|
|
51787
|
-
|
|
52089
|
+
});
|
|
52090
|
+
const nodes = projectOwnedRecordExtensions(data, recordUid);
|
|
52091
|
+
const extensionParent = await this.ownedRecordParentFromTree(data, recordUid, session, signal);
|
|
52092
|
+
if (nodes.length === 0) return extensionParent === void 0 ? void 0 : {
|
|
52093
|
+
extensionCount: 0,
|
|
52094
|
+
extensions: [],
|
|
52095
|
+
extensionParent
|
|
52096
|
+
};
|
|
51788
52097
|
const readable = nodes.filter((node) => !node.protectedContent);
|
|
51789
52098
|
const hydration = await this.media.hydrateRecordMediaPage(readable.map((node) => node.record), session, signal);
|
|
51790
52099
|
const extensions = nodes.map((node) => {
|
|
@@ -51838,7 +52147,8 @@ var ChatService = class {
|
|
|
51838
52147
|
extensions.sort((left, right) => right.sendAtMillis - left.sendAtMillis);
|
|
51839
52148
|
return {
|
|
51840
52149
|
extensionCount: extensions.length,
|
|
51841
|
-
extensions
|
|
52150
|
+
extensions,
|
|
52151
|
+
...extensionParent === void 0 ? {} : { extensionParent }
|
|
51842
52152
|
};
|
|
51843
52153
|
}
|
|
51844
52154
|
async recordEditHistoryTarget(sourceRef, messageActionRef) {
|
|
@@ -51911,7 +52221,8 @@ var ChatService = class {
|
|
|
51911
52221
|
return {
|
|
51912
52222
|
parentRecordUid: reference.recordUid,
|
|
51913
52223
|
extensionCount: recordContext?.extensionCount ?? 0,
|
|
51914
|
-
extensions: recordContext?.extensions ?? []
|
|
52224
|
+
extensions: recordContext?.extensions ?? [],
|
|
52225
|
+
...recordContext !== void 0 && "extensionParent" in recordContext ? { extensionParent: recordContext.extensionParent } : {}
|
|
51915
52226
|
};
|
|
51916
52227
|
}
|
|
51917
52228
|
async extendSourceMessage(sourceRef, messageActionRef, textContent, recordUid, assets = [], options = {}) {
|
|
@@ -85947,7 +86258,7 @@ function sharePreviewIsOwnMessage(raw, viewerUserId) {
|
|
|
85947
86258
|
const matching = typeof uid === "string" && uid ? anchors.filter((anchor) => anchor.record_uid === uid) : anchors.length === 1 ? anchors : [];
|
|
85948
86259
|
return matching.length === 1 && String(matching[0].record_owner_user_id) === String(viewerUserId);
|
|
85949
86260
|
}
|
|
85950
|
-
const list$
|
|
86261
|
+
const list$1 = (value) => Array.isArray(value) ? value.slice(0, 150).map(previewObject) : [];
|
|
85951
86262
|
function previewText(value, max = 200) {
|
|
85952
86263
|
if (typeof value !== "string") return "";
|
|
85953
86264
|
const plain = value.slice(0, 12e3).replace(/[\u0000-\u001f\u007f\s]+/gu, " ").trim();
|
|
@@ -85978,9 +86289,9 @@ function state(data) {
|
|
|
85978
86289
|
function sourceSummary(item) {
|
|
85979
86290
|
if (typeof item.availability === "string" && item.availability !== "available") return "";
|
|
85980
86291
|
const structure = previewObject(item.structured_content);
|
|
85981
|
-
const segments = list$
|
|
86292
|
+
const segments = list$1(structure.long_recording_segments);
|
|
85982
86293
|
const body = item.text_content ?? item.text ?? item.content;
|
|
85983
|
-
return previewText(item.text_format === "markdown" && typeof body === "string" ? arkmeMarkdownPlainText(body.slice(0, 12e3)) : body) || segments.slice(0, 3).map((s) => [previewText(s.speaker_label, 30), previewText(s.text, 100)].filter(Boolean).join(":")).join(" · ") || list$
|
|
86294
|
+
return previewText(item.text_format === "markdown" && typeof body === "string" ? arkmeMarkdownPlainText(body.slice(0, 12e3)) : body) || segments.slice(0, 3).map((s) => [previewText(s.speaker_label, 30), previewText(s.text, 100)].filter(Boolean).join(":")).join(" · ") || list$1(item.media_items ?? item.files).map((m) => previewText(m.file_name, 80)).filter(Boolean).slice(0, 2).join(" · ");
|
|
85984
86295
|
}
|
|
85985
86296
|
/** Pure projection: no private lookup, recursive resolution, AI, or media download. */
|
|
85986
86297
|
function projectSharePreview(target, raw) {
|
|
@@ -86003,8 +86314,8 @@ function projectSharePreview(target, raw) {
|
|
|
86003
86314
|
});
|
|
86004
86315
|
if (target.kind === "message" || target.kind === "conversation") {
|
|
86005
86316
|
const forward = previewObject(data.forward_records);
|
|
86006
|
-
const items = list$
|
|
86007
|
-
const bundle = list$
|
|
86317
|
+
const items = list$1(target.kind === "conversation" ? forward.items : data.items);
|
|
86318
|
+
const bundle = list$1(data.presentation).find((n) => n.kind === "forward_bundle");
|
|
86008
86319
|
if (target.kind === "conversation" || items.length > 1 || bundle) {
|
|
86009
86320
|
const lines = items.filter((item) => !item.availability || item.availability === "available").slice(0, 3).map((item) => [previewText(item.sender_display_name ?? item.owner_name, 40), sourceSummary(item) || previewText(item.title)].filter(Boolean).join(":")).filter(Boolean);
|
|
86010
86321
|
const fallbackLines = Array.isArray(forward.summary_lines) ? forward.summary_lines.slice(0, 3).map((v) => previewText(v, 100)) : [];
|
|
@@ -86021,7 +86332,7 @@ function projectSharePreview(target, raw) {
|
|
|
86021
86332
|
state: "unavailable"
|
|
86022
86333
|
};
|
|
86023
86334
|
const structure = previewObject(item.structured_content);
|
|
86024
|
-
const media = list$
|
|
86335
|
+
const media = list$1(item.media_items);
|
|
86025
86336
|
const first = media[0];
|
|
86026
86337
|
const kind = item.display_kind === 1 || item.template_kind === 8 ? "article" : structure.structured_kind === 1 || Array.isArray(structure.long_recording_segments) ? "recording" : [
|
|
86027
86338
|
"agent_message",
|
|
@@ -86043,7 +86354,7 @@ function projectSharePreview(target, raw) {
|
|
|
86043
86354
|
};
|
|
86044
86355
|
}
|
|
86045
86356
|
if (target.kind === "world") {
|
|
86046
|
-
const user = list$
|
|
86357
|
+
const user = list$1(data.items)[0] ?? {};
|
|
86047
86358
|
return Object.keys(user).length ? assign(user.nick_name, void 0, user.head_img, user.jotmo_id) : {
|
|
86048
86359
|
...base,
|
|
86049
86360
|
state: "unavailable"
|
|
@@ -86468,6 +86779,7 @@ var InterwovenService = class {
|
|
|
86468
86779
|
summary: stringValue$2(renderPayload.content ?? item.summary).trim().slice(0, 1e3),
|
|
86469
86780
|
degraded: booleanValue$4(item.is_degraded),
|
|
86470
86781
|
sourceChatSessionUid,
|
|
86782
|
+
...stringValue$2(jumpTarget.subject_uid).trim() === "" ? {} : { legacyGroupUid: stringValue$2(jumpTarget.subject_uid).trim() },
|
|
86471
86783
|
recordOwnerUserId,
|
|
86472
86784
|
recordUid,
|
|
86473
86785
|
relationUid,
|
|
@@ -86492,6 +86804,7 @@ var InterwovenService = class {
|
|
|
86492
86804
|
userId: session.userId,
|
|
86493
86805
|
sourceOwnerRef: source.ownerRef,
|
|
86494
86806
|
sourceChatSessionUid: descriptor.sourceChatSessionUid,
|
|
86807
|
+
...descriptor.legacyGroupUid === void 0 ? {} : { legacyGroupUid: descriptor.legacyGroupUid },
|
|
86495
86808
|
recordOwnerUserId: descriptor.recordOwnerUserId,
|
|
86496
86809
|
recordUid: descriptor.recordUid,
|
|
86497
86810
|
relationUid: descriptor.relationUid,
|
|
@@ -86536,6 +86849,154 @@ var InterwovenService = class {
|
|
|
86536
86849
|
...partial ? { message: "部分交织瞬间暂时不可用,可稍后重试" } : {}
|
|
86537
86850
|
};
|
|
86538
86851
|
}
|
|
86852
|
+
async interwovenReadReceipts(sourceRef, momentRefs, signal) {
|
|
86853
|
+
const epoch = this.interactionEpoch;
|
|
86854
|
+
const session = await this.runtime.requireSession();
|
|
86855
|
+
const source = await this.source.openSourceRef(sourceRef, session.userId);
|
|
86856
|
+
if (source.kind !== "private_chat" || momentRefs.length < 1 || momentRefs.length > 20 || momentRefs.some((ref) => typeof ref !== "string" || !ref.trim() || ref.length > 4096) || new Set(momentRefs).size !== momentRefs.length) throw new ArkmePluginError("interwoven-param-invalid", "群互动已读查询参数无效", false, 400);
|
|
86857
|
+
const references = await Promise.all(momentRefs.map((ref) => this.openInterwovenMomentRef(ref, session.userId, source.ownerRef)));
|
|
86858
|
+
const peerId = await this.assertInterwovenOperationAllowed(source, session, signal);
|
|
86859
|
+
await this.resolveReceiptBridgeReferences(sourceRef, source.ownerRef, references, signal);
|
|
86860
|
+
const groupReads = /* @__PURE__ */ new Map();
|
|
86861
|
+
const read = (path, body) => this.runtime.authenticatedChatPost(path, body, session, signal, {
|
|
86862
|
+
lane: "interactive-read",
|
|
86863
|
+
bypassCache: true
|
|
86864
|
+
});
|
|
86865
|
+
const groupDetail = (uid) => {
|
|
86866
|
+
let pending = groupReads.get(uid);
|
|
86867
|
+
if (!pending) {
|
|
86868
|
+
pending = read("/api/v1/chats/detail", { chat_session_uid: uid });
|
|
86869
|
+
groupReads.set(uid, pending);
|
|
86870
|
+
}
|
|
86871
|
+
return pending;
|
|
86872
|
+
};
|
|
86873
|
+
const items = new Array(references.length);
|
|
86874
|
+
let next = 0;
|
|
86875
|
+
const worker = async () => {
|
|
86876
|
+
while (next < references.length) {
|
|
86877
|
+
signal?.throwIfAborted();
|
|
86878
|
+
const index = next++;
|
|
86879
|
+
const ref = references[index];
|
|
86880
|
+
const reader = ref.senderUserId === session.userId ? "peer" : "self";
|
|
86881
|
+
const unknown = {
|
|
86882
|
+
momentId: ref.momentId,
|
|
86883
|
+
reader,
|
|
86884
|
+
status: "unknown"
|
|
86885
|
+
};
|
|
86886
|
+
items[index] = unknown;
|
|
86887
|
+
const groupUid = ref.sourceChatSessionUid || ref.legacyGroupUid || "";
|
|
86888
|
+
if (!groupUid || reader === "self" && ref.senderUserId !== peerId) continue;
|
|
86889
|
+
try {
|
|
86890
|
+
const group = await groupDetail(groupUid);
|
|
86891
|
+
const groupSession = objectValue$2(group.session);
|
|
86892
|
+
if (groupSession.chat_session_uid !== groupUid || groupSession.session_kind !== 2 || groupSession.status !== 1) continue;
|
|
86893
|
+
let sequence = ref.sequence || ref.receiptSequence || 0;
|
|
86894
|
+
const receiptRecordUid = ref.receiptRecordUid || ref.recordUid;
|
|
86895
|
+
if (sequence <= 0) {
|
|
86896
|
+
if (ref.recordUid.startsWith("chat_legacy_receive_")) continue;
|
|
86897
|
+
const around = await read("/api/v1/chat/timeline/around", {
|
|
86898
|
+
chat_session_uid: groupUid,
|
|
86899
|
+
record_uid: ref.recordUid,
|
|
86900
|
+
record_owner_user_id: ref.recordOwnerUserId,
|
|
86901
|
+
before_limit: 1,
|
|
86902
|
+
after_limit: 1
|
|
86903
|
+
});
|
|
86904
|
+
if (around.chat_session_uid !== groupUid) continue;
|
|
86905
|
+
const candidates = [...listValue$11(around.items), around.anchor].map(objectValue$2).filter((item) => {
|
|
86906
|
+
const relation = objectValue$2(item.relation ?? item);
|
|
86907
|
+
return relation.chat_session_uid === groupUid && relation.record_uid === ref.recordUid && relation.record_owner_user_id === ref.recordOwnerUserId && relation.sender_user_id === ref.senderUserId && Number.isSafeInteger(relation.seq) && numberValue$13(relation.seq) > 0 && objectValue$2(item.record).status === 1;
|
|
86908
|
+
});
|
|
86909
|
+
const sequences = new Set(candidates.map((item) => numberValue$13(objectValue$2(item.relation ?? item).seq)));
|
|
86910
|
+
if (sequences.size !== 1) continue;
|
|
86911
|
+
sequence = [...sequences][0];
|
|
86912
|
+
ref.receiptSequence = sequence;
|
|
86913
|
+
}
|
|
86914
|
+
if (reader === "self") {
|
|
86915
|
+
const cursor = objectValue$2(group.current_cursor);
|
|
86916
|
+
const snapshot = objectValue$2(group.unread_snapshot);
|
|
86917
|
+
if (cursor.user_id !== session.userId || cursor.chat_session_uid !== groupUid || cursor.status !== 1) continue;
|
|
86918
|
+
const readSeq = snapshot.read_seq ?? cursor.read_seq;
|
|
86919
|
+
const lastSeq = snapshot.session_last_seq ?? groupSession.last_seq;
|
|
86920
|
+
if (typeof readSeq !== "number" || !Number.isSafeInteger(readSeq) || readSeq < 0 || typeof lastSeq !== "number" || !Number.isSafeInteger(lastSeq) || lastSeq < sequence) continue;
|
|
86921
|
+
items[index] = {
|
|
86922
|
+
...unknown,
|
|
86923
|
+
status: readSeq >= sequence ? "read" : "unread"
|
|
86924
|
+
};
|
|
86925
|
+
} else {
|
|
86926
|
+
const detail = await read("/api/v1/chats/read-receipts/detail", {
|
|
86927
|
+
chat_session_uid: groupUid,
|
|
86928
|
+
record_uid: receiptRecordUid,
|
|
86929
|
+
seq: sequence
|
|
86930
|
+
});
|
|
86931
|
+
if (detail.chat_session_uid !== groupUid || detail.record_uid !== receiptRecordUid || detail.seq !== sequence || !Array.isArray(detail.items)) continue;
|
|
86932
|
+
const peers = detail.items.map(objectValue$2).filter((member) => member.user_id === peerId);
|
|
86933
|
+
if (peers.length !== 1) continue;
|
|
86934
|
+
const peer = peers[0];
|
|
86935
|
+
if (peer.read_status !== "read" && peer.read_status !== "unread" || typeof peer.read_at !== "number" || !Number.isSafeInteger(peer.read_at) || peer.read_at < 0 || peer.read_status === "unread" && peer.read_at !== 0) continue;
|
|
86936
|
+
items[index] = {
|
|
86937
|
+
...unknown,
|
|
86938
|
+
status: peer.read_status,
|
|
86939
|
+
...peer.read_status === "read" && peer.read_at > 0 ? { readAtMillis: peer.read_at } : {}
|
|
86940
|
+
};
|
|
86941
|
+
}
|
|
86942
|
+
} catch {
|
|
86943
|
+
signal?.throwIfAborted();
|
|
86944
|
+
}
|
|
86945
|
+
}
|
|
86946
|
+
};
|
|
86947
|
+
await Promise.all(Array.from({ length: Math.min(3, references.length) }, worker));
|
|
86948
|
+
await this.assertInteractionAccount(session.userId, epoch, signal);
|
|
86949
|
+
return { items };
|
|
86950
|
+
}
|
|
86951
|
+
async resolveReceiptBridgeReferences(sourceRef, privateUid, references, signal) {
|
|
86952
|
+
const pending = references.filter((ref) => !ref.sequence && !ref.receiptSequence && /^chat_legacy_receive_[a-f0-9]{32}$/.test(ref.recordUid));
|
|
86953
|
+
if (!pending.length) return;
|
|
86954
|
+
const matches = /* @__PURE__ */ new Map();
|
|
86955
|
+
let cursor;
|
|
86956
|
+
let expectedVersion;
|
|
86957
|
+
try {
|
|
86958
|
+
for (let page = 0; page < 3; page++) {
|
|
86959
|
+
const { data, userId } = await this.readPrivateInteractions("occurrences/query", {
|
|
86960
|
+
sourceRef,
|
|
86961
|
+
limit: 50,
|
|
86962
|
+
...cursor === void 0 ? {} : { cursor },
|
|
86963
|
+
...expectedVersion === void 0 ? {} : { expectedVersion },
|
|
86964
|
+
...signal === void 0 ? {} : { signal }
|
|
86965
|
+
});
|
|
86966
|
+
const coverage = this.interactionCoverage(data);
|
|
86967
|
+
if (expectedVersion && coverage.version !== expectedVersion) return;
|
|
86968
|
+
expectedVersion = coverage.version;
|
|
86969
|
+
if (!Array.isArray(data.items) || data.items.length > 50 || typeof data.has_more !== "boolean") return;
|
|
86970
|
+
for (const raw of data.items) {
|
|
86971
|
+
const item = objectValue$2(raw);
|
|
86972
|
+
if (this.interactionCount(item.seq) === 0) return;
|
|
86973
|
+
const groupUid = stringValue$2(item.source_chat_session_uid).trim();
|
|
86974
|
+
const relationUid = stringValue$2(item.rel_uid).trim();
|
|
86975
|
+
const recordUid = stringValue$2(item.record_uid).trim();
|
|
86976
|
+
if (!relationUid || !recordUid || item.private_chat_session_uid !== privateUid) continue;
|
|
86977
|
+
const alias = `chat_legacy_receive_${createHash("sha256").update(`${groupUid}:${relationUid}`).digest("hex").slice(0, 32)}`;
|
|
86978
|
+
for (const ref of pending) {
|
|
86979
|
+
if (ref.recordUid !== alias || (ref.sourceChatSessionUid || ref.legacyGroupUid) !== groupUid || ref.recordOwnerUserId !== item.record_owner_user_id || ref.senderUserId !== item.sender_user_id || item.sender_is_me !== (ref.senderUserId === userId)) continue;
|
|
86980
|
+
const next = {
|
|
86981
|
+
recordUid,
|
|
86982
|
+
sequence: item.seq
|
|
86983
|
+
};
|
|
86984
|
+
const previous = matches.get(ref);
|
|
86985
|
+
matches.set(ref, previous === null || previous && (previous.recordUid !== recordUid || previous.sequence !== next.sequence) ? null : next);
|
|
86986
|
+
}
|
|
86987
|
+
}
|
|
86988
|
+
if (!data.has_more || pending.every((ref) => matches.has(ref))) break;
|
|
86989
|
+
if (typeof data.next_cursor !== "string" || !data.next_cursor || data.next_cursor.length > 2048) return;
|
|
86990
|
+
cursor = data.next_cursor;
|
|
86991
|
+
}
|
|
86992
|
+
for (const [ref, match] of matches) if (match) {
|
|
86993
|
+
ref.receiptRecordUid = match.recordUid;
|
|
86994
|
+
ref.receiptSequence = match.sequence;
|
|
86995
|
+
}
|
|
86996
|
+
} catch {
|
|
86997
|
+
signal?.throwIfAborted();
|
|
86998
|
+
}
|
|
86999
|
+
}
|
|
86539
87000
|
async interwovenMomentDetail(sourceRef, momentRef, signal) {
|
|
86540
87001
|
const session = await this.runtime.requireSession();
|
|
86541
87002
|
const source = await this.source.openSourceRef(sourceRef, session.userId);
|
|
@@ -86603,7 +87064,7 @@ var InterwovenService = class {
|
|
|
86603
87064
|
if (source.kind !== "private_chat") throw new ArkmePluginError("interwoven-source-invalid", "交织瞬间仅支持普通私聊", false, 400);
|
|
86604
87065
|
if (!this.runtime.config.interwovenMomentsEnabled) throw new ArkmePluginError("interwoven-disabled", "交织瞬间能力当前未开启", false, 403);
|
|
86605
87066
|
if (!booleanValue$4((await this.runtime.authenticatedAuthPost("/api/v1/auth/able-func", { func_type: 12 }, session, signal)).able)) throw new ArkmePluginError("interwoven-disabled", "交织瞬间能力当前未开放", false, 403);
|
|
86606
|
-
await this.assertHumanPrivateSource(source, session, signal);
|
|
87067
|
+
return await this.assertHumanPrivateSource(source, session, signal);
|
|
86607
87068
|
}
|
|
86608
87069
|
async assertHumanPrivateSource(source, session, signal) {
|
|
86609
87070
|
const detail = await this.runtime.authenticatedChatPost("/api/v1/chats/detail", { chat_session_uid: source.ownerRef }, session, signal);
|
|
@@ -90178,123 +90639,6 @@ function recordingSearchIdentityHash(item) {
|
|
|
90178
90639
|
]), "utf8").digest("hex");
|
|
90179
90640
|
}
|
|
90180
90641
|
//#endregion
|
|
90181
|
-
//#region src/recording-speaker-presence.ts
|
|
90182
|
-
const record = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
90183
|
-
const list$1 = (value) => Array.isArray(value) ? value : [];
|
|
90184
|
-
const string = (value) => typeof value === "string" ? value.trim() : "";
|
|
90185
|
-
const number$1 = (value) => typeof value === "number" && Number.isFinite(value) ? value : NaN;
|
|
90186
|
-
/**
|
|
90187
|
-
* Count positive-duration ASR facts, including a segment whose text is empty.
|
|
90188
|
-
* The day endpoint already scopes visible recordings; user_id additionally
|
|
90189
|
-
* prevents a shared or unrelated session from entering this owner's estimate.
|
|
90190
|
-
*/
|
|
90191
|
-
function projectRecentSpeakerDetails(speakers, days, ownerUserId) {
|
|
90192
|
-
const personBySpeaker = /* @__PURE__ */ new Map();
|
|
90193
|
-
for (const raw of list$1(speakers)) {
|
|
90194
|
-
const speaker = record(raw);
|
|
90195
|
-
const id = string(speaker.speaker_id ?? speaker.id ?? speaker.spk_id);
|
|
90196
|
-
if (id === "") continue;
|
|
90197
|
-
const userId = number$1(speaker.ref_usr_id ?? speaker.ref_user_id ?? speaker.user_id);
|
|
90198
|
-
personBySpeaker.set(id, Number.isSafeInteger(userId) && userId > 0 ? `user:${userId}` : `speaker:${id}`);
|
|
90199
|
-
}
|
|
90200
|
-
const presenceByPerson = /* @__PURE__ */ new Map();
|
|
90201
|
-
for (const day of days) {
|
|
90202
|
-
const dayEnd = new Date(day.dateStamp);
|
|
90203
|
-
dayEnd.setDate(dayEnd.getDate() + 1);
|
|
90204
|
-
const sessions = /* @__PURE__ */ new Map();
|
|
90205
|
-
const response = record(day.response);
|
|
90206
|
-
for (const raw of list$1(response.session_ls ?? response.sessions)) {
|
|
90207
|
-
const session = record(raw);
|
|
90208
|
-
const sessionId = string(session.id ?? session.session_id);
|
|
90209
|
-
if (sessionId === "" || number$1(session.user_id) !== ownerUserId) continue;
|
|
90210
|
-
const speakerByNumber = /* @__PURE__ */ new Map();
|
|
90211
|
-
for (const rawSpeaker of list$1(session.spk_ls ?? session.speakers)) {
|
|
90212
|
-
const speaker = record(rawSpeaker);
|
|
90213
|
-
const speakerNumber = number$1(speaker.num ?? speaker.speaker_num);
|
|
90214
|
-
if (!Number.isSafeInteger(speakerNumber)) continue;
|
|
90215
|
-
const displayNumber = number$1(speaker.speaker_display_number);
|
|
90216
|
-
const innerId = string(speaker.inner_spk_id);
|
|
90217
|
-
const dayId = string(speaker.day_spk_id);
|
|
90218
|
-
const legacyToken = string(speaker.inner_display ?? speaker.label);
|
|
90219
|
-
const identityKey = Number.isSafeInteger(displayNumber) && displayNumber > 0 ? `number:${displayNumber}` : innerId !== "" ? `inner:${innerId}` : dayId !== "" ? `day:${dayId}` : "";
|
|
90220
|
-
const token = Number.isSafeInteger(displayNumber) && displayNumber > 0 ? String(displayNumber) : legacyToken;
|
|
90221
|
-
speakerByNumber.set(speakerNumber, {
|
|
90222
|
-
speakerId: string(speaker.spk_id ?? speaker.speaker_id),
|
|
90223
|
-
identityKey: identityKey !== "" && token !== "" ? identityKey : "",
|
|
90224
|
-
token
|
|
90225
|
-
});
|
|
90226
|
-
}
|
|
90227
|
-
sessions.set(sessionId, {
|
|
90228
|
-
startAt: number$1(session.start_at),
|
|
90229
|
-
speakerByNumber
|
|
90230
|
-
});
|
|
90231
|
-
}
|
|
90232
|
-
for (const raw of list$1(response.child_ls ?? response.children)) {
|
|
90233
|
-
const child = record(raw);
|
|
90234
|
-
const session = sessions.get(string(child.session_id));
|
|
90235
|
-
if (session === void 0 || !Number.isFinite(session.startAt)) continue;
|
|
90236
|
-
const offset = number$1(child.start_at);
|
|
90237
|
-
if (!Number.isFinite(offset)) continue;
|
|
90238
|
-
const childStart = offset >= 1e11 ? offset : session.startAt + offset;
|
|
90239
|
-
for (const rawItem of list$1(child.asr)) {
|
|
90240
|
-
const item = record(rawItem);
|
|
90241
|
-
const startOffset = number$1(item.s ?? item.start_at);
|
|
90242
|
-
const endOffset = number$1(item.e ?? item.end_at);
|
|
90243
|
-
const seenAt = childStart + startOffset;
|
|
90244
|
-
const seenEndAt = childStart + endOffset;
|
|
90245
|
-
if (!Number.isFinite(seenAt) || !Number.isFinite(seenEndAt) || seenEndAt <= seenAt || seenAt < day.dateStamp || seenAt >= dayEnd.getTime()) continue;
|
|
90246
|
-
if (string(item.speaker_identity_source) === "system") continue;
|
|
90247
|
-
const recognized = session.speakerByNumber.get(number$1(item.n ?? item.speaker_num));
|
|
90248
|
-
const sessionSpeakerId = recognized?.speakerId ?? "";
|
|
90249
|
-
const effectiveId = string(item.effective_spk_id);
|
|
90250
|
-
const directId = string(item.q);
|
|
90251
|
-
const explicitlyUnassigned = directId === "" && sessionSpeakerId !== "" && string(item.q_unassigned_spk_id) === sessionSpeakerId;
|
|
90252
|
-
const speakerId = effectiveId || (explicitlyUnassigned ? "" : directId || sessionSpeakerId);
|
|
90253
|
-
const personKey = personBySpeaker.get(speakerId);
|
|
90254
|
-
if (personKey === void 0) continue;
|
|
90255
|
-
let presence = presenceByPerson.get(personKey);
|
|
90256
|
-
if (presence === void 0) {
|
|
90257
|
-
presence = {
|
|
90258
|
-
days: /* @__PURE__ */ new Set(),
|
|
90259
|
-
lastSeenAt: 0,
|
|
90260
|
-
members: /* @__PURE__ */ new Map()
|
|
90261
|
-
};
|
|
90262
|
-
presenceByPerson.set(personKey, presence);
|
|
90263
|
-
}
|
|
90264
|
-
presence.days.add(day.dateStamp);
|
|
90265
|
-
presence.lastSeenAt = Math.max(presence.lastSeenAt, seenEndAt);
|
|
90266
|
-
if (recognized?.identityKey) {
|
|
90267
|
-
let member = presence.members.get(recognized.identityKey);
|
|
90268
|
-
if (member === void 0) {
|
|
90269
|
-
member = {
|
|
90270
|
-
token: recognized.token,
|
|
90271
|
-
days: /* @__PURE__ */ new Set(),
|
|
90272
|
-
lastSeenAt: 0
|
|
90273
|
-
};
|
|
90274
|
-
presence.members.set(recognized.identityKey, member);
|
|
90275
|
-
}
|
|
90276
|
-
member.days.add(day.dateStamp);
|
|
90277
|
-
member.lastSeenAt = Math.max(member.lastSeenAt, seenEndAt);
|
|
90278
|
-
}
|
|
90279
|
-
}
|
|
90280
|
-
}
|
|
90281
|
-
}
|
|
90282
|
-
return [...personBySpeaker].flatMap(([speakerId, personKey]) => {
|
|
90283
|
-
const presence = presenceByPerson.get(personKey);
|
|
90284
|
-
return presence === void 0 ? [] : [{
|
|
90285
|
-
speakerId,
|
|
90286
|
-
dayCount: presence.days.size,
|
|
90287
|
-
lastSeenAt: presence.lastSeenAt,
|
|
90288
|
-
members: [...presence.members].map(([identityKey, member]) => ({
|
|
90289
|
-
identityKey,
|
|
90290
|
-
token: member.token,
|
|
90291
|
-
dayCount: member.days.size,
|
|
90292
|
-
lastSeenAt: member.lastSeenAt
|
|
90293
|
-
})).sort((left, right) => right.lastSeenAt - left.lastSeenAt || left.token.localeCompare(right.token))
|
|
90294
|
-
}];
|
|
90295
|
-
});
|
|
90296
|
-
}
|
|
90297
|
-
//#endregion
|
|
90298
90642
|
//#region src/recording-import-coordinator.ts
|
|
90299
90643
|
function importFailure(error) {
|
|
90300
90644
|
if (error instanceof RecordingImportContractError) return {
|
|
@@ -91213,7 +91557,6 @@ var RecordingService = class {
|
|
|
91213
91557
|
recordingImportSource;
|
|
91214
91558
|
recordingImportOwnerGateway;
|
|
91215
91559
|
speakerCacheRevision = 0;
|
|
91216
|
-
recentSpeakerDetailsCache;
|
|
91217
91560
|
unsubscribeSpeakerAccount;
|
|
91218
91561
|
forwardGateway;
|
|
91219
91562
|
constructor(runtime, dependencies) {
|
|
@@ -91385,22 +91728,17 @@ var RecordingService = class {
|
|
|
91385
91728
|
this.assertWorkbenchEnabled();
|
|
91386
91729
|
const session = await this.runtime.requireSession();
|
|
91387
91730
|
const revision = this.speakerCacheRevision;
|
|
91388
|
-
|
|
91389
|
-
try {
|
|
91390
|
-
data = await this.runtime.authenticatedAudioPost("/api/v1/audio/speaker-presence/list", {}, session, signal);
|
|
91391
|
-
} catch (error) {
|
|
91392
|
-
if (!(error instanceof ArkmePluginError) || error.upstreamStatus !== 404 && error.httpStatus !== 404 && error.code !== "arkme-code-404") throw error;
|
|
91393
|
-
return await this.recordingSpeakerPresenceRecent(session, revision, signal);
|
|
91394
|
-
}
|
|
91731
|
+
const data = await this.runtime.authenticatedAudioPost("/api/v1/audio/speaker-presence/list", {}, session, signal);
|
|
91395
91732
|
const rawState = stringValue$2(data.state);
|
|
91396
91733
|
if (rawState !== "building" && rawState !== "fresh" && rawState !== "stale" && rawState !== "failed") throw new ArkmePluginError("recording-speaker-presence-invalid", "说话人出现统计响应无效", true, 502);
|
|
91734
|
+
if (!Array.isArray(data.items) || rawState === "fresh" && stringValue$2(data.version) === "") throw new ArkmePluginError("recording-speaker-presence-invalid", "说话人出现统计响应无效", true, 502);
|
|
91397
91735
|
const speakerRefKey = await this.recordingRefKey("arkme-recording-speaker-v1");
|
|
91398
91736
|
const items = listValue$5(data.items).flatMap((raw) => {
|
|
91399
91737
|
const item = objectValue$2(raw);
|
|
91400
91738
|
const speakerId = stringValue$2(item.speaker_id).trim();
|
|
91401
91739
|
const dayCount = numberValue$5(item.day_count);
|
|
91402
91740
|
const lastSeenAt = numberValue$5(item.last_seen_at);
|
|
91403
|
-
if (speakerId === "" || !Number.isSafeInteger(dayCount) || dayCount <= 0 || !Number.isSafeInteger(lastSeenAt) || lastSeenAt <= 0)
|
|
91741
|
+
if (speakerId === "" || !Number.isSafeInteger(dayCount) || dayCount <= 0 || !Number.isSafeInteger(lastSeenAt) || lastSeenAt <= 0) throw new ArkmePluginError("recording-speaker-presence-invalid", "说话人出现统计响应无效", true, 502);
|
|
91404
91742
|
return [{
|
|
91405
91743
|
optionKey: this.recordingSpeakerOptionKey(speakerRefKey, session.userId, "speaker", speakerId),
|
|
91406
91744
|
dayCount,
|
|
@@ -91411,115 +91749,58 @@ var RecordingService = class {
|
|
|
91411
91749
|
return {
|
|
91412
91750
|
state: rawState,
|
|
91413
91751
|
scope: "all-history",
|
|
91414
|
-
items,
|
|
91752
|
+
items: rawState === "fresh" ? items : [],
|
|
91753
|
+
...stringValue$2(data.version) === "" ? {} : { version: stringValue$2(data.version) },
|
|
91415
91754
|
...numberValue$5(data.updated_at) > 0 ? { updatedAt: numberValue$5(data.updated_at) } : {},
|
|
91416
91755
|
...numberValue$5(data.retry_after_ms) > 0 ? { retryAfterMs: numberValue$5(data.retry_after_ms) } : {}
|
|
91417
91756
|
};
|
|
91418
91757
|
}
|
|
91419
|
-
|
|
91420
|
-
|
|
91421
|
-
const speakerRefKey = await this.recordingRefKey("arkme-recording-speaker-v1");
|
|
91422
|
-
await this.assertSpeakerReadCurrent(session, revision, signal);
|
|
91423
|
-
return {
|
|
91424
|
-
state: "fresh",
|
|
91425
|
-
scope: "recent-seven-days",
|
|
91426
|
-
items: snapshot.details.map((stat) => ({
|
|
91427
|
-
optionKey: this.recordingSpeakerOptionKey(speakerRefKey, session.userId, "speaker", stat.speakerId),
|
|
91428
|
-
dayCount: stat.dayCount,
|
|
91429
|
-
lastSeenAt: stat.lastSeenAt
|
|
91430
|
-
})),
|
|
91431
|
-
updatedAt: snapshot.updatedAt
|
|
91432
|
-
};
|
|
91433
|
-
}
|
|
91434
|
-
/** Read a selected marked person's verifiable source voices, not a guessed all-history mapping. */
|
|
91435
|
-
async recordingSpeakerMembers(speakerRef, signal) {
|
|
91758
|
+
/** All-history source identities, authorized by the same account-bound speaker reference as the UI. */
|
|
91759
|
+
async recordingSpeakerMembers(speakerRef, signal, expectedVersion) {
|
|
91436
91760
|
this.assertWorkbenchEnabled();
|
|
91437
91761
|
const session = await this.runtime.requireSession();
|
|
91438
91762
|
const revision = this.speakerCacheRevision;
|
|
91439
91763
|
const reference = await this.openRecordingSpeakerRef(speakerRef);
|
|
91440
91764
|
if (reference.viewerUserId !== session.userId || reference.target.kind !== "speaker") throw new ArkmePluginError("recording-speaker-ref-account-mismatch", "说话人引用与当前账号不匹配", false, 403);
|
|
91765
|
+
const data = await this.runtime.authenticatedAudioPost("/api/v1/audio/speaker-presence/detail", {
|
|
91766
|
+
speaker_id: reference.target.speakerId,
|
|
91767
|
+
...expectedVersion === void 0 ? {} : { expected_version: expectedVersion }
|
|
91768
|
+
}, session, signal);
|
|
91769
|
+
const state = stringValue$2(data.state);
|
|
91770
|
+
if (![
|
|
91771
|
+
"building",
|
|
91772
|
+
"fresh",
|
|
91773
|
+
"stale",
|
|
91774
|
+
"failed"
|
|
91775
|
+
].includes(state)) throw new ArkmePluginError("recording-speaker-presence-invalid", "说话人出现统计响应无效", true, 502);
|
|
91776
|
+
if (state === "fresh" && (stringValue$2(data.version) === "" || !Array.isArray(data.items) || data.members !== void 0 && !Array.isArray(data.members))) throw new ArkmePluginError("recording-speaker-presence-invalid", "说话人出现统计响应无效", true, 502);
|
|
91777
|
+
const key = await this.recordingRefKey("arkme-recording-speaker-v1");
|
|
91441
91778
|
const targetSpeakerId = reference.target.speakerId;
|
|
91442
|
-
const
|
|
91443
|
-
if (!
|
|
91444
|
-
const
|
|
91445
|
-
|
|
91446
|
-
|
|
91447
|
-
|
|
91448
|
-
|
|
91449
|
-
|
|
91450
|
-
|
|
91779
|
+
const stat = listValue$5(data.items).map(objectValue$2).find((item) => item.speaker_id === targetSpeakerId);
|
|
91780
|
+
if (state === "fresh" && stat !== void 0 && (!Number.isSafeInteger(stat.day_count) || numberValue$5(stat.day_count) <= 0 || !Number.isSafeInteger(stat.last_seen_at) || numberValue$5(stat.last_seen_at) <= 0)) throw new ArkmePluginError("recording-speaker-presence-invalid", "说话人出现统计响应无效", true, 502);
|
|
91781
|
+
const items = state !== "fresh" ? [] : listValue$5(data.members).map((raw) => {
|
|
91782
|
+
const item = objectValue$2(raw);
|
|
91783
|
+
const identity = stringValue$2(item.identity_key);
|
|
91784
|
+
const token = stringValue$2(item.token);
|
|
91785
|
+
const dayCount = numberValue$5(item.day_count);
|
|
91786
|
+
const lastSeenAt = numberValue$5(item.last_seen_at);
|
|
91787
|
+
if (stat === void 0 || dayCount > numberValue$5(stat.day_count) || lastSeenAt > numberValue$5(stat.last_seen_at) || identity === "" || token === "" || !Number.isSafeInteger(dayCount) || dayCount <= 0 || !Number.isSafeInteger(lastSeenAt) || lastSeenAt <= 0) throw new ArkmePluginError("recording-speaker-members-invalid", "关联说话人响应无效", true, 502);
|
|
91788
|
+
return {
|
|
91789
|
+
identityKey: this.recordingSpeakerOptionKey(key, session.userId, "speaker", `presence:${identity}`),
|
|
91451
91790
|
token,
|
|
91452
91791
|
dayCount,
|
|
91453
91792
|
lastSeenAt
|
|
91454
|
-
})) ?? []
|
|
91455
|
-
};
|
|
91456
|
-
}
|
|
91457
|
-
async loadRecentSpeakerDetails(session, revision, signal) {
|
|
91458
|
-
const today = /* @__PURE__ */ new Date();
|
|
91459
|
-
today.setHours(0, 0, 0, 0);
|
|
91460
|
-
const firstDay = new Date(today);
|
|
91461
|
-
firstDay.setDate(firstDay.getDate() - 6);
|
|
91462
|
-
const cached = this.recentSpeakerDetailsCache;
|
|
91463
|
-
if (cached?.ownerUserId === session.userId && cached.revision === revision && cached.firstDay === firstDay.getTime() && Date.now() - cached.updatedAt < 15e3) {
|
|
91464
|
-
await this.assertSpeakerReadCurrent(session, revision, signal);
|
|
91465
|
-
return {
|
|
91466
|
-
speakerIds: cached.speakerIds,
|
|
91467
|
-
details: cached.details,
|
|
91468
|
-
updatedAt: cached.updatedAt
|
|
91469
91793
|
};
|
|
91470
|
-
}
|
|
91471
|
-
const afterLastDay = new Date(today);
|
|
91472
|
-
afterLastDay.setDate(afterLastDay.getDate() + 1);
|
|
91473
|
-
const [speakerData, calendar] = await Promise.all([this.runtime.authenticatedAudioPost("/api/v1/audio/get-speaker-ls", {}, session, signal), this.runtime.authenticatedAudioPost("/api/v1/audio/get-calender-summary", {
|
|
91474
|
-
from_stamp: firstDay.getTime(),
|
|
91475
|
-
to_stamp: afterLastDay.getTime()
|
|
91476
|
-
}, session, signal)]);
|
|
91477
|
-
const durations = calendar.duration_ls;
|
|
91478
|
-
const unreviewed = calendar.un_click_session_ids_per_day;
|
|
91479
|
-
if (!Array.isArray(speakerData.spk_ls) || !Array.isArray(durations) || durations.length < 7 || !Array.isArray(unreviewed) || unreviewed.length < 7) throw new ArkmePluginError("recording-speaker-recent-invalid", "近 7 天录音统计响应无效", true, 502);
|
|
91480
|
-
const days = [];
|
|
91481
|
-
const cursor = new Date(firstDay);
|
|
91482
|
-
for (let index = 0; index < 7; index += 1) {
|
|
91483
|
-
if (numberValue$5(durations[index]) > 0 || listValue$5(unreviewed[index]).length > 0) days.push(cursor.getTime());
|
|
91484
|
-
cursor.setDate(cursor.getDate() + 1);
|
|
91485
|
-
}
|
|
91486
|
-
const transcripts = [];
|
|
91487
|
-
let nextDay = 0;
|
|
91488
|
-
const readDay = async () => {
|
|
91489
|
-
while (nextDay < days.length) {
|
|
91490
|
-
const dateStamp = days[nextDay++];
|
|
91491
|
-
signal?.throwIfAborted();
|
|
91492
|
-
const day = new Date(dateStamp);
|
|
91493
|
-
const response = await this.runtime.authenticatedAudioPost("/api/v1/audio/one-day-trans", {
|
|
91494
|
-
start_at: dateStamp,
|
|
91495
|
-
tz_offset: -day.getTimezoneOffset() * 6e4
|
|
91496
|
-
}, session, signal);
|
|
91497
|
-
transcripts.push({
|
|
91498
|
-
dateStamp,
|
|
91499
|
-
response
|
|
91500
|
-
});
|
|
91501
|
-
}
|
|
91502
|
-
};
|
|
91503
|
-
await Promise.all(Array.from({ length: Math.min(2, days.length) }, readDay));
|
|
91504
|
-
const details = projectRecentSpeakerDetails(speakerData.spk_ls, transcripts, session.userId);
|
|
91505
|
-
const speakerIds = new Set(listValue$5(speakerData.spk_ls).map((raw) => {
|
|
91506
|
-
const speaker = objectValue$2(raw);
|
|
91507
|
-
return stringValue$2(speaker.speaker_id ?? speaker.id ?? speaker.spk_id).trim();
|
|
91508
|
-
}).filter(Boolean));
|
|
91794
|
+
});
|
|
91509
91795
|
await this.assertSpeakerReadCurrent(session, revision, signal);
|
|
91510
|
-
const updatedAt = Date.now();
|
|
91511
|
-
this.recentSpeakerDetailsCache = {
|
|
91512
|
-
ownerUserId: session.userId,
|
|
91513
|
-
revision,
|
|
91514
|
-
firstDay: firstDay.getTime(),
|
|
91515
|
-
updatedAt,
|
|
91516
|
-
speakerIds,
|
|
91517
|
-
details
|
|
91518
|
-
};
|
|
91519
91796
|
return {
|
|
91520
|
-
|
|
91521
|
-
|
|
91522
|
-
|
|
91797
|
+
state,
|
|
91798
|
+
scope: "all-history",
|
|
91799
|
+
dayCount: state === "fresh" ? numberValue$5(stat?.day_count) : 0,
|
|
91800
|
+
lastSeenAt: state === "fresh" ? numberValue$5(stat?.last_seen_at) : 0,
|
|
91801
|
+
items,
|
|
91802
|
+
...stringValue$2(data.version) === "" ? {} : { version: stringValue$2(data.version) },
|
|
91803
|
+
...numberValue$5(data.retry_after_ms) > 0 ? { retryAfterMs: numberValue$5(data.retry_after_ms) } : {}
|
|
91523
91804
|
};
|
|
91524
91805
|
}
|
|
91525
91806
|
async recordingSpeakerRecommendation(itemRef, signal) {
|
|
@@ -95065,6 +95346,7 @@ var UnmarkedSpeakerService = class {
|
|
|
95065
95346
|
const projectionState = data.projection_state === void 0 ? void 0 : knownStringValue(data.projection_state, PROJECTION_STATES);
|
|
95066
95347
|
if (data.projection_state !== void 0 && projectionState === void 0) throw new ArkmePluginError("unmarked-list-contract-invalid", "未标记说话人列表投影状态无效", true, 502);
|
|
95067
95348
|
const items = [];
|
|
95349
|
+
const identitySecret = await this.runtime.stateStore.uniqueCode();
|
|
95068
95350
|
for (const value of listValue$2(data.items).slice(0, LIST_CAP)) {
|
|
95069
95351
|
const raw = objectValue$2(value);
|
|
95070
95352
|
const candidateId = stringValue$2(raw.candidate_id).trim();
|
|
@@ -95092,6 +95374,14 @@ var UnmarkedSpeakerService = class {
|
|
|
95092
95374
|
kind: "unmarked-speaker",
|
|
95093
95375
|
candidateRef,
|
|
95094
95376
|
speakerToken,
|
|
95377
|
+
appearanceDays,
|
|
95378
|
+
latestAtMillis,
|
|
95379
|
+
identityKey: createHmac("sha256", identitySecret).update(JSON.stringify([
|
|
95380
|
+
"unmarked-speaker-identity-v1",
|
|
95381
|
+
this.runtime.config.environment,
|
|
95382
|
+
session.userId,
|
|
95383
|
+
candidateId
|
|
95384
|
+
])).digest("base64url"),
|
|
95095
95385
|
displayName: unmarkedSpeakerDisplayName({
|
|
95096
95386
|
speakerToken,
|
|
95097
95387
|
firstSeenDate: localDate(status === "single_day" ? latestAtMillis : firstSeenAtMillis),
|
|
@@ -98026,6 +98316,12 @@ var ArkmeService = class {
|
|
|
98026
98316
|
async membershipCatalog(expectedUserId) {
|
|
98027
98317
|
return await this.membershipOwner.catalog(expectedUserId);
|
|
98028
98318
|
}
|
|
98319
|
+
async aiPointsAccount(expectedScope, signal) {
|
|
98320
|
+
return await new AiPointsService(this.runtime).account(expectedScope, signal);
|
|
98321
|
+
}
|
|
98322
|
+
async aiPointsConsumption(query, expectedScope, signal) {
|
|
98323
|
+
return await new AiPointsService(this.runtime).consumption(query, expectedScope, signal);
|
|
98324
|
+
}
|
|
98029
98325
|
async accountTokenUsage(expectedScope) {
|
|
98030
98326
|
return await new AccountUsageService(this.runtime).tokens(expectedScope);
|
|
98031
98327
|
}
|
|
@@ -98260,6 +98556,7 @@ var ArkmeService = class {
|
|
|
98260
98556
|
revisionPolling: true,
|
|
98261
98557
|
userProfile: true,
|
|
98262
98558
|
accountSettings: true,
|
|
98559
|
+
aiPoints: true,
|
|
98263
98560
|
imageRead: true,
|
|
98264
98561
|
recordCalendar: true,
|
|
98265
98562
|
imageLibrary: true,
|
|
@@ -98271,6 +98568,7 @@ var ArkmeService = class {
|
|
|
98271
98568
|
...this.runtime.stateStore.commonGroups ? { commonGroups: true } : {},
|
|
98272
98569
|
remoteRecordSearch: true,
|
|
98273
98570
|
contactDirectoryReads: true,
|
|
98571
|
+
speakerPresence: true,
|
|
98274
98572
|
sourceTimeline: true,
|
|
98275
98573
|
forwardContent: true,
|
|
98276
98574
|
sourceTextSend: true,
|
|
@@ -98535,8 +98833,8 @@ var ArkmeService = class {
|
|
|
98535
98833
|
async recordingSpeakerPresence(signal) {
|
|
98536
98834
|
return await this.recording.recordingSpeakerPresence(signal);
|
|
98537
98835
|
}
|
|
98538
|
-
async recordingSpeakerMembers(speakerRef, signal) {
|
|
98539
|
-
return await this.recording.recordingSpeakerMembers(speakerRef, signal);
|
|
98836
|
+
async recordingSpeakerMembers(speakerRef, signal, expectedVersion) {
|
|
98837
|
+
return await this.recording.recordingSpeakerMembers(speakerRef, signal, expectedVersion);
|
|
98540
98838
|
}
|
|
98541
98839
|
async recordingSpeakerRecommendation(itemRef, signal) {
|
|
98542
98840
|
return await this.recording.recordingSpeakerRecommendation(itemRef, signal);
|
|
@@ -98775,6 +99073,9 @@ var ArkmeService = class {
|
|
|
98775
99073
|
async interwovenMomentDetail(sourceRef, momentRef, signal) {
|
|
98776
99074
|
return await this.interwoven.interwovenMomentDetail(sourceRef, momentRef, signal);
|
|
98777
99075
|
}
|
|
99076
|
+
async interwovenReadReceipts(sourceRef, momentRefs, signal) {
|
|
99077
|
+
return await this.interwoven.interwovenReadReceipts(sourceRef, momentRefs, signal);
|
|
99078
|
+
}
|
|
98778
99079
|
async recordEditHistoryPage(sourceRef, messageActionRef, cursorEditAt = 0, signal) {
|
|
98779
99080
|
return await this.recordEditHistory.page(await this.chat.recordEditHistoryTarget(sourceRef, messageActionRef), cursorEditAt, signal);
|
|
98780
99081
|
}
|
|
@@ -99212,6 +99513,9 @@ var ArkmeService = class {
|
|
|
99212
99513
|
})
|
|
99213
99514
|
};
|
|
99214
99515
|
}
|
|
99516
|
+
async sourceMessageExtensionParent(sourceRef, messageActionRef, options = {}) {
|
|
99517
|
+
return this.chat.sourceMessageExtensionParent(sourceRef, messageActionRef, options);
|
|
99518
|
+
}
|
|
99215
99519
|
async extendSourceMessage(sourceRef, messageActionRef, textContent, recordUid, fileRefs = [], options = {}) {
|
|
99216
99520
|
if (options.textFormat === "markdown" && this.config.markdownQuickNotesEnabled !== true) throw new ArkmePluginError("markdown-send-disabled", "Markdown 发送尚未开放,请稍后重试", false, 403);
|
|
99217
99521
|
const context = await this.chat.sourceMessageExtensionContext(sourceRef, messageActionRef, options);
|