@senguoyun/dsh-arkme 0.1.82 → 0.1.83
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/send-to-self-roles-cross-client-api-handoff-2026-09-27.md +9 -0
- package/lib/client.js +2181 -1710
- package/lib/client.js.map +1 -1
- package/lib/harness-model-client.js +123 -37
- package/lib/harness-native-selection-client.js +57 -1
- package/lib/harness-sidebar-client.js +11 -0
- package/lib/index.js +194 -56
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-DV9Hme-U.js → persistent-runtime-B6vPAaiG.js} +507 -42
- package/lib/sdk.js +11 -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 +10 -0
- 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/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/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/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 +4 -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/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/ports/profile.d.ts +3 -0
- package/lib/types/tools/ports/profile.d.ts.map +1 -1
- package/lib/types/types.d.ts +17 -3
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -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) {
|
|
@@ -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 = {
|
|
@@ -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);
|
|
@@ -51779,12 +52025,66 @@ var ChatService = class {
|
|
|
51779
52025
|
};
|
|
51780
52026
|
}
|
|
51781
52027
|
/** Personal and topic notes share the record-owned tree, including replies outside the original topic. */
|
|
52028
|
+
async ownedRecordParentFromTree(data, recordUid, session, signal) {
|
|
52029
|
+
const parent = projectOwnedRecordParent(data, recordUid);
|
|
52030
|
+
if (parent === void 0) return void 0;
|
|
52031
|
+
const owner = recordOwnerId(parent.record.owner_user_id);
|
|
52032
|
+
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 {
|
|
52033
|
+
itemUid: parent.recordUid,
|
|
52034
|
+
senderName: "",
|
|
52035
|
+
title: "",
|
|
52036
|
+
textContent: "该延展源暂不可用"
|
|
52037
|
+
};
|
|
52038
|
+
const hydration = await this.media.hydrateRecordMediaPage([parent.record], session, signal);
|
|
52039
|
+
const item = this.record.recordTimelineItemFromRaw(parent.record, session.userId, {
|
|
52040
|
+
displayItems: hydration.displayItemsByRecordUid.get(parent.recordUid) ?? [],
|
|
52041
|
+
mediaUnavailable: hydration.unavailableRecordUids.has(parent.recordUid)
|
|
52042
|
+
});
|
|
52043
|
+
return {
|
|
52044
|
+
itemUid: parent.recordUid,
|
|
52045
|
+
senderName: item.senderName,
|
|
52046
|
+
title: item.title,
|
|
52047
|
+
textContent: item.textContent,
|
|
52048
|
+
textFormat: item.textFormat ?? "plain",
|
|
52049
|
+
sendAtMillis: item.sendAtMillis,
|
|
52050
|
+
...owner === 0 ? {} : { recordOwnerUserId: owner },
|
|
52051
|
+
...item.contentBlocks === void 0 ? {} : { contentBlocks: item.contentBlocks }
|
|
52052
|
+
};
|
|
52053
|
+
}
|
|
52054
|
+
/** Lightweight visible-row enrichment; never reads an entire topic before showing it. */
|
|
52055
|
+
async sourceMessageExtensionParent(sourceRef, actionRef, options = {}) {
|
|
52056
|
+
const session = await this.runtime.requireSession();
|
|
52057
|
+
const source = await this.source.openSourceRef(sourceRef.trim(), session.userId);
|
|
52058
|
+
const reference = await this.openMessageActionRef(actionRef, session.userId, source);
|
|
52059
|
+
if (reference.sourceKind !== "record" || ![
|
|
52060
|
+
"send_to_self",
|
|
52061
|
+
"default_category",
|
|
52062
|
+
"topic"
|
|
52063
|
+
].includes(source.kind)) throw new ArkmePluginError("record-extension-source-invalid", "当前来源不支持读取个人延展源", false, 403);
|
|
52064
|
+
const data = await this.runtime.authenticatedPost("/api/v1/records/extensions/tree", { record_uid: reference.recordUid }, session, options.signal, {
|
|
52065
|
+
lane: "background-read",
|
|
52066
|
+
key: `record-extension-parent:${reference.recordUid}`,
|
|
52067
|
+
cacheMs: 5e3,
|
|
52068
|
+
failureCooldownMs: 2e3
|
|
52069
|
+
});
|
|
52070
|
+
const extensionParent = await this.ownedRecordParentFromTree(data, reference.recordUid, session, options.signal);
|
|
52071
|
+
return {
|
|
52072
|
+
recordUid: reference.recordUid,
|
|
52073
|
+
...extensionParent === void 0 ? {} : { extensionParent }
|
|
52074
|
+
};
|
|
52075
|
+
}
|
|
51782
52076
|
async loadOwnedRecordExtensions(recordUid, session, signal) {
|
|
51783
|
-
const
|
|
52077
|
+
const data = await this.runtime.authenticatedPost("/api/v1/records/extensions/tree", { record_uid: recordUid }, session, signal, {
|
|
51784
52078
|
lane: "interactive-read",
|
|
51785
52079
|
bypassCache: true
|
|
51786
|
-
})
|
|
51787
|
-
|
|
52080
|
+
});
|
|
52081
|
+
const nodes = projectOwnedRecordExtensions(data, recordUid);
|
|
52082
|
+
const extensionParent = await this.ownedRecordParentFromTree(data, recordUid, session, signal);
|
|
52083
|
+
if (nodes.length === 0) return extensionParent === void 0 ? void 0 : {
|
|
52084
|
+
extensionCount: 0,
|
|
52085
|
+
extensions: [],
|
|
52086
|
+
extensionParent
|
|
52087
|
+
};
|
|
51788
52088
|
const readable = nodes.filter((node) => !node.protectedContent);
|
|
51789
52089
|
const hydration = await this.media.hydrateRecordMediaPage(readable.map((node) => node.record), session, signal);
|
|
51790
52090
|
const extensions = nodes.map((node) => {
|
|
@@ -51838,7 +52138,8 @@ var ChatService = class {
|
|
|
51838
52138
|
extensions.sort((left, right) => right.sendAtMillis - left.sendAtMillis);
|
|
51839
52139
|
return {
|
|
51840
52140
|
extensionCount: extensions.length,
|
|
51841
|
-
extensions
|
|
52141
|
+
extensions,
|
|
52142
|
+
...extensionParent === void 0 ? {} : { extensionParent }
|
|
51842
52143
|
};
|
|
51843
52144
|
}
|
|
51844
52145
|
async recordEditHistoryTarget(sourceRef, messageActionRef) {
|
|
@@ -51911,7 +52212,8 @@ var ChatService = class {
|
|
|
51911
52212
|
return {
|
|
51912
52213
|
parentRecordUid: reference.recordUid,
|
|
51913
52214
|
extensionCount: recordContext?.extensionCount ?? 0,
|
|
51914
|
-
extensions: recordContext?.extensions ?? []
|
|
52215
|
+
extensions: recordContext?.extensions ?? [],
|
|
52216
|
+
...recordContext !== void 0 && "extensionParent" in recordContext ? { extensionParent: recordContext.extensionParent } : {}
|
|
51915
52217
|
};
|
|
51916
52218
|
}
|
|
51917
52219
|
async extendSourceMessage(sourceRef, messageActionRef, textContent, recordUid, assets = [], options = {}) {
|
|
@@ -86468,6 +86770,7 @@ var InterwovenService = class {
|
|
|
86468
86770
|
summary: stringValue$2(renderPayload.content ?? item.summary).trim().slice(0, 1e3),
|
|
86469
86771
|
degraded: booleanValue$4(item.is_degraded),
|
|
86470
86772
|
sourceChatSessionUid,
|
|
86773
|
+
...stringValue$2(jumpTarget.subject_uid).trim() === "" ? {} : { legacyGroupUid: stringValue$2(jumpTarget.subject_uid).trim() },
|
|
86471
86774
|
recordOwnerUserId,
|
|
86472
86775
|
recordUid,
|
|
86473
86776
|
relationUid,
|
|
@@ -86492,6 +86795,7 @@ var InterwovenService = class {
|
|
|
86492
86795
|
userId: session.userId,
|
|
86493
86796
|
sourceOwnerRef: source.ownerRef,
|
|
86494
86797
|
sourceChatSessionUid: descriptor.sourceChatSessionUid,
|
|
86798
|
+
...descriptor.legacyGroupUid === void 0 ? {} : { legacyGroupUid: descriptor.legacyGroupUid },
|
|
86495
86799
|
recordOwnerUserId: descriptor.recordOwnerUserId,
|
|
86496
86800
|
recordUid: descriptor.recordUid,
|
|
86497
86801
|
relationUid: descriptor.relationUid,
|
|
@@ -86536,6 +86840,154 @@ var InterwovenService = class {
|
|
|
86536
86840
|
...partial ? { message: "部分交织瞬间暂时不可用,可稍后重试" } : {}
|
|
86537
86841
|
};
|
|
86538
86842
|
}
|
|
86843
|
+
async interwovenReadReceipts(sourceRef, momentRefs, signal) {
|
|
86844
|
+
const epoch = this.interactionEpoch;
|
|
86845
|
+
const session = await this.runtime.requireSession();
|
|
86846
|
+
const source = await this.source.openSourceRef(sourceRef, session.userId);
|
|
86847
|
+
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);
|
|
86848
|
+
const references = await Promise.all(momentRefs.map((ref) => this.openInterwovenMomentRef(ref, session.userId, source.ownerRef)));
|
|
86849
|
+
const peerId = await this.assertInterwovenOperationAllowed(source, session, signal);
|
|
86850
|
+
await this.resolveReceiptBridgeReferences(sourceRef, source.ownerRef, references, signal);
|
|
86851
|
+
const groupReads = /* @__PURE__ */ new Map();
|
|
86852
|
+
const read = (path, body) => this.runtime.authenticatedChatPost(path, body, session, signal, {
|
|
86853
|
+
lane: "interactive-read",
|
|
86854
|
+
bypassCache: true
|
|
86855
|
+
});
|
|
86856
|
+
const groupDetail = (uid) => {
|
|
86857
|
+
let pending = groupReads.get(uid);
|
|
86858
|
+
if (!pending) {
|
|
86859
|
+
pending = read("/api/v1/chats/detail", { chat_session_uid: uid });
|
|
86860
|
+
groupReads.set(uid, pending);
|
|
86861
|
+
}
|
|
86862
|
+
return pending;
|
|
86863
|
+
};
|
|
86864
|
+
const items = new Array(references.length);
|
|
86865
|
+
let next = 0;
|
|
86866
|
+
const worker = async () => {
|
|
86867
|
+
while (next < references.length) {
|
|
86868
|
+
signal?.throwIfAborted();
|
|
86869
|
+
const index = next++;
|
|
86870
|
+
const ref = references[index];
|
|
86871
|
+
const reader = ref.senderUserId === session.userId ? "peer" : "self";
|
|
86872
|
+
const unknown = {
|
|
86873
|
+
momentId: ref.momentId,
|
|
86874
|
+
reader,
|
|
86875
|
+
status: "unknown"
|
|
86876
|
+
};
|
|
86877
|
+
items[index] = unknown;
|
|
86878
|
+
const groupUid = ref.sourceChatSessionUid || ref.legacyGroupUid || "";
|
|
86879
|
+
if (!groupUid || reader === "self" && ref.senderUserId !== peerId) continue;
|
|
86880
|
+
try {
|
|
86881
|
+
const group = await groupDetail(groupUid);
|
|
86882
|
+
const groupSession = objectValue$2(group.session);
|
|
86883
|
+
if (groupSession.chat_session_uid !== groupUid || groupSession.session_kind !== 2 || groupSession.status !== 1) continue;
|
|
86884
|
+
let sequence = ref.sequence || ref.receiptSequence || 0;
|
|
86885
|
+
const receiptRecordUid = ref.receiptRecordUid || ref.recordUid;
|
|
86886
|
+
if (sequence <= 0) {
|
|
86887
|
+
if (ref.recordUid.startsWith("chat_legacy_receive_")) continue;
|
|
86888
|
+
const around = await read("/api/v1/chat/timeline/around", {
|
|
86889
|
+
chat_session_uid: groupUid,
|
|
86890
|
+
record_uid: ref.recordUid,
|
|
86891
|
+
record_owner_user_id: ref.recordOwnerUserId,
|
|
86892
|
+
before_limit: 1,
|
|
86893
|
+
after_limit: 1
|
|
86894
|
+
});
|
|
86895
|
+
if (around.chat_session_uid !== groupUid) continue;
|
|
86896
|
+
const candidates = [...listValue$11(around.items), around.anchor].map(objectValue$2).filter((item) => {
|
|
86897
|
+
const relation = objectValue$2(item.relation ?? item);
|
|
86898
|
+
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;
|
|
86899
|
+
});
|
|
86900
|
+
const sequences = new Set(candidates.map((item) => numberValue$13(objectValue$2(item.relation ?? item).seq)));
|
|
86901
|
+
if (sequences.size !== 1) continue;
|
|
86902
|
+
sequence = [...sequences][0];
|
|
86903
|
+
ref.receiptSequence = sequence;
|
|
86904
|
+
}
|
|
86905
|
+
if (reader === "self") {
|
|
86906
|
+
const cursor = objectValue$2(group.current_cursor);
|
|
86907
|
+
const snapshot = objectValue$2(group.unread_snapshot);
|
|
86908
|
+
if (cursor.user_id !== session.userId || cursor.chat_session_uid !== groupUid || cursor.status !== 1) continue;
|
|
86909
|
+
const readSeq = snapshot.read_seq ?? cursor.read_seq;
|
|
86910
|
+
const lastSeq = snapshot.session_last_seq ?? groupSession.last_seq;
|
|
86911
|
+
if (typeof readSeq !== "number" || !Number.isSafeInteger(readSeq) || readSeq < 0 || typeof lastSeq !== "number" || !Number.isSafeInteger(lastSeq) || lastSeq < sequence) continue;
|
|
86912
|
+
items[index] = {
|
|
86913
|
+
...unknown,
|
|
86914
|
+
status: readSeq >= sequence ? "read" : "unread"
|
|
86915
|
+
};
|
|
86916
|
+
} else {
|
|
86917
|
+
const detail = await read("/api/v1/chats/read-receipts/detail", {
|
|
86918
|
+
chat_session_uid: groupUid,
|
|
86919
|
+
record_uid: receiptRecordUid,
|
|
86920
|
+
seq: sequence
|
|
86921
|
+
});
|
|
86922
|
+
if (detail.chat_session_uid !== groupUid || detail.record_uid !== receiptRecordUid || detail.seq !== sequence || !Array.isArray(detail.items)) continue;
|
|
86923
|
+
const peers = detail.items.map(objectValue$2).filter((member) => member.user_id === peerId);
|
|
86924
|
+
if (peers.length !== 1) continue;
|
|
86925
|
+
const peer = peers[0];
|
|
86926
|
+
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;
|
|
86927
|
+
items[index] = {
|
|
86928
|
+
...unknown,
|
|
86929
|
+
status: peer.read_status,
|
|
86930
|
+
...peer.read_status === "read" && peer.read_at > 0 ? { readAtMillis: peer.read_at } : {}
|
|
86931
|
+
};
|
|
86932
|
+
}
|
|
86933
|
+
} catch {
|
|
86934
|
+
signal?.throwIfAborted();
|
|
86935
|
+
}
|
|
86936
|
+
}
|
|
86937
|
+
};
|
|
86938
|
+
await Promise.all(Array.from({ length: Math.min(3, references.length) }, worker));
|
|
86939
|
+
await this.assertInteractionAccount(session.userId, epoch, signal);
|
|
86940
|
+
return { items };
|
|
86941
|
+
}
|
|
86942
|
+
async resolveReceiptBridgeReferences(sourceRef, privateUid, references, signal) {
|
|
86943
|
+
const pending = references.filter((ref) => !ref.sequence && !ref.receiptSequence && /^chat_legacy_receive_[a-f0-9]{32}$/.test(ref.recordUid));
|
|
86944
|
+
if (!pending.length) return;
|
|
86945
|
+
const matches = /* @__PURE__ */ new Map();
|
|
86946
|
+
let cursor;
|
|
86947
|
+
let expectedVersion;
|
|
86948
|
+
try {
|
|
86949
|
+
for (let page = 0; page < 3; page++) {
|
|
86950
|
+
const { data, userId } = await this.readPrivateInteractions("occurrences/query", {
|
|
86951
|
+
sourceRef,
|
|
86952
|
+
limit: 50,
|
|
86953
|
+
...cursor === void 0 ? {} : { cursor },
|
|
86954
|
+
...expectedVersion === void 0 ? {} : { expectedVersion },
|
|
86955
|
+
...signal === void 0 ? {} : { signal }
|
|
86956
|
+
});
|
|
86957
|
+
const coverage = this.interactionCoverage(data);
|
|
86958
|
+
if (expectedVersion && coverage.version !== expectedVersion) return;
|
|
86959
|
+
expectedVersion = coverage.version;
|
|
86960
|
+
if (!Array.isArray(data.items) || data.items.length > 50 || typeof data.has_more !== "boolean") return;
|
|
86961
|
+
for (const raw of data.items) {
|
|
86962
|
+
const item = objectValue$2(raw);
|
|
86963
|
+
if (this.interactionCount(item.seq) === 0) return;
|
|
86964
|
+
const groupUid = stringValue$2(item.source_chat_session_uid).trim();
|
|
86965
|
+
const relationUid = stringValue$2(item.rel_uid).trim();
|
|
86966
|
+
const recordUid = stringValue$2(item.record_uid).trim();
|
|
86967
|
+
if (!relationUid || !recordUid || item.private_chat_session_uid !== privateUid) continue;
|
|
86968
|
+
const alias = `chat_legacy_receive_${createHash("sha256").update(`${groupUid}:${relationUid}`).digest("hex").slice(0, 32)}`;
|
|
86969
|
+
for (const ref of pending) {
|
|
86970
|
+
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;
|
|
86971
|
+
const next = {
|
|
86972
|
+
recordUid,
|
|
86973
|
+
sequence: item.seq
|
|
86974
|
+
};
|
|
86975
|
+
const previous = matches.get(ref);
|
|
86976
|
+
matches.set(ref, previous === null || previous && (previous.recordUid !== recordUid || previous.sequence !== next.sequence) ? null : next);
|
|
86977
|
+
}
|
|
86978
|
+
}
|
|
86979
|
+
if (!data.has_more || pending.every((ref) => matches.has(ref))) break;
|
|
86980
|
+
if (typeof data.next_cursor !== "string" || !data.next_cursor || data.next_cursor.length > 2048) return;
|
|
86981
|
+
cursor = data.next_cursor;
|
|
86982
|
+
}
|
|
86983
|
+
for (const [ref, match] of matches) if (match) {
|
|
86984
|
+
ref.receiptRecordUid = match.recordUid;
|
|
86985
|
+
ref.receiptSequence = match.sequence;
|
|
86986
|
+
}
|
|
86987
|
+
} catch {
|
|
86988
|
+
signal?.throwIfAborted();
|
|
86989
|
+
}
|
|
86990
|
+
}
|
|
86539
86991
|
async interwovenMomentDetail(sourceRef, momentRef, signal) {
|
|
86540
86992
|
const session = await this.runtime.requireSession();
|
|
86541
86993
|
const source = await this.source.openSourceRef(sourceRef, session.userId);
|
|
@@ -86603,7 +87055,7 @@ var InterwovenService = class {
|
|
|
86603
87055
|
if (source.kind !== "private_chat") throw new ArkmePluginError("interwoven-source-invalid", "交织瞬间仅支持普通私聊", false, 400);
|
|
86604
87056
|
if (!this.runtime.config.interwovenMomentsEnabled) throw new ArkmePluginError("interwoven-disabled", "交织瞬间能力当前未开启", false, 403);
|
|
86605
87057
|
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);
|
|
87058
|
+
return await this.assertHumanPrivateSource(source, session, signal);
|
|
86607
87059
|
}
|
|
86608
87060
|
async assertHumanPrivateSource(source, session, signal) {
|
|
86609
87061
|
const detail = await this.runtime.authenticatedChatPost("/api/v1/chats/detail", { chat_session_uid: source.ownerRef }, session, signal);
|
|
@@ -98026,6 +98478,12 @@ var ArkmeService = class {
|
|
|
98026
98478
|
async membershipCatalog(expectedUserId) {
|
|
98027
98479
|
return await this.membershipOwner.catalog(expectedUserId);
|
|
98028
98480
|
}
|
|
98481
|
+
async aiPointsAccount(expectedScope, signal) {
|
|
98482
|
+
return await new AiPointsService(this.runtime).account(expectedScope, signal);
|
|
98483
|
+
}
|
|
98484
|
+
async aiPointsConsumption(query, expectedScope, signal) {
|
|
98485
|
+
return await new AiPointsService(this.runtime).consumption(query, expectedScope, signal);
|
|
98486
|
+
}
|
|
98029
98487
|
async accountTokenUsage(expectedScope) {
|
|
98030
98488
|
return await new AccountUsageService(this.runtime).tokens(expectedScope);
|
|
98031
98489
|
}
|
|
@@ -98260,6 +98718,7 @@ var ArkmeService = class {
|
|
|
98260
98718
|
revisionPolling: true,
|
|
98261
98719
|
userProfile: true,
|
|
98262
98720
|
accountSettings: true,
|
|
98721
|
+
aiPoints: true,
|
|
98263
98722
|
imageRead: true,
|
|
98264
98723
|
recordCalendar: true,
|
|
98265
98724
|
imageLibrary: true,
|
|
@@ -98775,6 +99234,9 @@ var ArkmeService = class {
|
|
|
98775
99234
|
async interwovenMomentDetail(sourceRef, momentRef, signal) {
|
|
98776
99235
|
return await this.interwoven.interwovenMomentDetail(sourceRef, momentRef, signal);
|
|
98777
99236
|
}
|
|
99237
|
+
async interwovenReadReceipts(sourceRef, momentRefs, signal) {
|
|
99238
|
+
return await this.interwoven.interwovenReadReceipts(sourceRef, momentRefs, signal);
|
|
99239
|
+
}
|
|
98778
99240
|
async recordEditHistoryPage(sourceRef, messageActionRef, cursorEditAt = 0, signal) {
|
|
98779
99241
|
return await this.recordEditHistory.page(await this.chat.recordEditHistoryTarget(sourceRef, messageActionRef), cursorEditAt, signal);
|
|
98780
99242
|
}
|
|
@@ -99212,6 +99674,9 @@ var ArkmeService = class {
|
|
|
99212
99674
|
})
|
|
99213
99675
|
};
|
|
99214
99676
|
}
|
|
99677
|
+
async sourceMessageExtensionParent(sourceRef, messageActionRef, options = {}) {
|
|
99678
|
+
return this.chat.sourceMessageExtensionParent(sourceRef, messageActionRef, options);
|
|
99679
|
+
}
|
|
99215
99680
|
async extendSourceMessage(sourceRef, messageActionRef, textContent, recordUid, fileRefs = [], options = {}) {
|
|
99216
99681
|
if (options.textFormat === "markdown" && this.config.markdownQuickNotesEnabled !== true) throw new ArkmePluginError("markdown-send-disabled", "Markdown 发送尚未开放,请稍后重试", false, 403);
|
|
99217
99682
|
const context = await this.chat.sourceMessageExtensionContext(sourceRef, messageActionRef, options);
|