@senguoyun/dsh-arkme 0.1.72 → 0.1.74
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/quick-add-hover-regression-2026-09-21.md +11 -0
- package/lib/client.js +678 -1843
- package/lib/client.js.map +1 -1
- package/lib/harness-native-selection-client.js +5 -3
- package/lib/index.js +6 -43
- package/lib/types/client/ArkmeArkoSurface.d.ts +31 -4
- package/lib/types/client/ArkmeArkoSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeDshMenu.d.ts.map +1 -1
- package/lib/types/client/ArkmePersistentShell.d.ts.map +1 -1
- package/lib/types/client/ArkmeQuickAdd.d.ts.map +1 -1
- package/lib/types/harness-embed-route.d.ts +0 -1
- package/lib/types/harness-embed-route.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/package.json +5 -5
- package/lib/arko-native-client.js +0 -6077
- package/lib/types/client/ArkmeArkoPanel.d.ts +0 -5
- package/lib/types/client/ArkmeArkoPanel.d.ts.map +0 -1
- package/lib/types/client/ArkoNativeSurface.d.ts +0 -27
- package/lib/types/client/ArkoNativeSurface.d.ts.map +0 -1
- package/lib/types/client/arko-conversation-contract.d.ts +0 -47
- package/lib/types/client/arko-conversation-contract.d.ts.map +0 -1
- package/lib/types/client/arko-native-client.d.ts +0 -19
- package/lib/types/client/arko-native-client.d.ts.map +0 -1
- package/lib/types/client/arko-native-composer.d.ts +0 -31
- package/lib/types/client/arko-native-composer.d.ts.map +0 -1
- package/lib/types/client/arko-native-emoji-picker.d.ts +0 -17
- package/lib/types/client/arko-native-emoji-picker.d.ts.map +0 -1
- package/lib/types/client/arko-native-frame.d.ts +0 -3
- package/lib/types/client/arko-native-frame.d.ts.map +0 -1
- package/lib/types/client/arko-native-transport.d.ts +0 -20
- package/lib/types/client/arko-native-transport.d.ts.map +0 -1
- package/lib/types/client/useArkoConversationController.d.ts +0 -57
- package/lib/types/client/useArkoConversationController.d.ts.map +0 -1
package/lib/client.js
CHANGED
|
@@ -1979,7 +1979,7 @@ window.__ModuleLoader__.load({
|
|
|
1979
1979
|
}
|
|
1980
1980
|
//#endregion
|
|
1981
1981
|
//#region src/avatar-diagnostics.ts
|
|
1982
|
-
function record
|
|
1982
|
+
function record(value) {
|
|
1983
1983
|
return value !== null && typeof value === "object" ? value : {};
|
|
1984
1984
|
}
|
|
1985
1985
|
function positiveId(value) {
|
|
@@ -1995,7 +1995,7 @@ window.__ModuleLoader__.load({
|
|
|
1995
1995
|
const encoded = parts[1] ?? "";
|
|
1996
1996
|
if (parts.length !== 3 || encoded.length > 1024 || !/^[A-Za-z0-9_-]+$/.test(encoded)) return context;
|
|
1997
1997
|
const base64 = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
1998
|
-
const payload = record
|
|
1998
|
+
const payload = record(JSON.parse(globalThis.atob(base64.padEnd(Math.ceil(base64.length / 4) * 4, "="))));
|
|
1999
1999
|
if (payload.version !== 1) return context;
|
|
2000
2000
|
const viewer = positiveId(payload.viewerUserId);
|
|
2001
2001
|
const target = positiveId(payload.targetUserId);
|
|
@@ -2025,8 +2025,8 @@ window.__ModuleLoader__.load({
|
|
|
2025
2025
|
}
|
|
2026
2026
|
function logArkmeAvatarDiagnostic(event, context, error) {
|
|
2027
2027
|
try {
|
|
2028
|
-
const source = record
|
|
2029
|
-
const body = record
|
|
2028
|
+
const source = record(error);
|
|
2029
|
+
const body = record(source.body);
|
|
2030
2030
|
const detail = source.name === "ArkmeClientError" ? body : source;
|
|
2031
2031
|
const errorName = [
|
|
2032
2032
|
"Error",
|
|
@@ -2046,7 +2046,7 @@ window.__ModuleLoader__.load({
|
|
|
2046
2046
|
retryable: typeof detail.retryable === "boolean" ? detail.retryable : void 0,
|
|
2047
2047
|
httpStatus: httpStatus(source.httpStatus),
|
|
2048
2048
|
upstreamStatus: httpStatus(source.upstreamStatus) ?? imageDownloadStatus(source),
|
|
2049
|
-
causeCode: safeErrorCode(record
|
|
2049
|
+
causeCode: safeErrorCode(record(source.cause).code)
|
|
2050
2050
|
} }
|
|
2051
2051
|
})}`);
|
|
2052
2052
|
} catch {}
|
|
@@ -15537,7 +15537,7 @@ function(property) {
|
|
|
15537
15537
|
* @returns {Check}
|
|
15538
15538
|
*/
|
|
15539
15539
|
function(test) {
|
|
15540
|
-
if (test === null || test === void 0) return ok
|
|
15540
|
+
if (test === null || test === void 0) return ok;
|
|
15541
15541
|
if (typeof test === "function") return castFactory(test);
|
|
15542
15542
|
if (typeof test === "object") return Array.isArray(test) ? anyFactory(test) : propertiesFactory(test);
|
|
15543
15543
|
if (typeof test === "string") return typeFactory(test);
|
|
@@ -15615,7 +15615,7 @@ function(test) {
|
|
|
15615
15615
|
return Boolean(looksLikeANode(value) && testFunction.call(this, value, typeof index === "number" ? index : void 0, parent || void 0));
|
|
15616
15616
|
}
|
|
15617
15617
|
}
|
|
15618
|
-
function ok
|
|
15618
|
+
function ok() {
|
|
15619
15619
|
return true;
|
|
15620
15620
|
}
|
|
15621
15621
|
/**
|
|
@@ -110836,7 +110836,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
110836
110836
|
else scheduleClose();
|
|
110837
110837
|
};
|
|
110838
110838
|
const leave = (event) => {
|
|
110839
|
-
if (event.relatedTarget === null)
|
|
110839
|
+
if (event.relatedTarget === null) scheduleClose();
|
|
110840
110840
|
};
|
|
110841
110841
|
const observer = new MutationObserver(() => {
|
|
110842
110842
|
if (!anchor.isConnected) close();
|
|
@@ -110846,14 +110846,16 @@ Please report this to https://github.com/markedjs/marked.`, e) {
|
|
|
110846
110846
|
subtree: true
|
|
110847
110847
|
});
|
|
110848
110848
|
doc.addEventListener("pointermove", move, true);
|
|
110849
|
+
doc.addEventListener("pointerover", move, true);
|
|
110849
110850
|
doc.addEventListener("pointerout", leave, true);
|
|
110850
|
-
doc.defaultView?.addEventListener("blur",
|
|
110851
|
+
doc.defaultView?.addEventListener("blur", scheduleClose);
|
|
110851
110852
|
return () => {
|
|
110852
110853
|
cancel();
|
|
110853
110854
|
observer.disconnect();
|
|
110854
110855
|
doc.removeEventListener("pointermove", move, true);
|
|
110856
|
+
doc.removeEventListener("pointerover", move, true);
|
|
110855
110857
|
doc.removeEventListener("pointerout", leave, true);
|
|
110856
|
-
doc.defaultView?.removeEventListener("blur",
|
|
110858
|
+
doc.defaultView?.removeEventListener("blur", scheduleClose);
|
|
110857
110859
|
};
|
|
110858
110860
|
}, [
|
|
110859
110861
|
open,
|
|
@@ -146351,7 +146353,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
146351
146353
|
* Wrap `React.useLayoutEffect` which will not throw warning message in test env
|
|
146352
146354
|
*/
|
|
146353
146355
|
const useInternalLayoutEffect = canUseDom() ? react.useLayoutEffect : react.useEffect;
|
|
146354
|
-
const useLayoutEffect$
|
|
146356
|
+
const useLayoutEffect$21 = (callback, deps) => {
|
|
146355
146357
|
const firstMountRef = react.useRef(true);
|
|
146356
146358
|
useInternalLayoutEffect(() => {
|
|
146357
146359
|
return callback(firstMountRef.current);
|
|
@@ -146395,7 +146397,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
146395
146397
|
function useControlledState(defaultStateValue, value) {
|
|
146396
146398
|
const [innerValue, setInnerValue] = (0, react.useState)(defaultStateValue);
|
|
146397
146399
|
const mergedValue = value !== void 0 ? value : innerValue;
|
|
146398
|
-
useLayoutEffect$
|
|
146400
|
+
useLayoutEffect$21((mount) => {
|
|
146399
146401
|
if (!mount) setInnerValue(value);
|
|
146400
146402
|
}, [value]);
|
|
146401
146403
|
return [mergedValue, setInnerValue];
|
|
@@ -146458,7 +146460,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
146458
146460
|
};
|
|
146459
146461
|
//#endregion
|
|
146460
146462
|
//#region node_modules/@rc-component/util/es/hooks/useMemo.js
|
|
146461
|
-
function useMemo$
|
|
146463
|
+
function useMemo$31(getValue, condition, shouldUpdate) {
|
|
146462
146464
|
const cacheRef = react.useRef({});
|
|
146463
146465
|
if (!("value" in cacheRef.current) || shouldUpdate(cacheRef.current.condition, condition)) {
|
|
146464
146466
|
cacheRef.current.value = getValue();
|
|
@@ -146571,7 +146573,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
146571
146573
|
};
|
|
146572
146574
|
};
|
|
146573
146575
|
const useComposeRef = (...refs) => {
|
|
146574
|
-
return useMemo$
|
|
146576
|
+
return useMemo$31(() => composeRef(...refs), refs, (prev, next) => prev.length !== next.length || prev.every((ref, i) => ref !== next[i]));
|
|
146575
146577
|
};
|
|
146576
146578
|
const supportRef = (nodeOrComponent) => {
|
|
146577
146579
|
if (!nodeOrComponent) return false;
|
|
@@ -147461,13 +147463,13 @@ ${height ? `height: ${webkitScrollbarStyle.height};` : ""}
|
|
|
147461
147463
|
ele.parentElement?.removeChild(ele);
|
|
147462
147464
|
appendedRef.current = false;
|
|
147463
147465
|
}
|
|
147464
|
-
useLayoutEffect$
|
|
147466
|
+
useLayoutEffect$21(() => {
|
|
147465
147467
|
if (render) if (queueCreate) queueCreate(append);
|
|
147466
147468
|
else append();
|
|
147467
147469
|
else cleanup();
|
|
147468
147470
|
return cleanup;
|
|
147469
147471
|
}, [render]);
|
|
147470
|
-
useLayoutEffect$
|
|
147472
|
+
useLayoutEffect$21(() => {
|
|
147471
147473
|
if (queue.length) {
|
|
147472
147474
|
queue.forEach((appendFn) => appendFn());
|
|
147473
147475
|
setQueue(EMPTY_LIST);
|
|
@@ -147493,7 +147495,7 @@ ${height ? `height: ${webkitScrollbarStyle.height};` : ""}
|
|
|
147493
147495
|
uuid$1 += 1;
|
|
147494
147496
|
return `${UNIQUE_ID}_${uuid$1}`;
|
|
147495
147497
|
});
|
|
147496
|
-
useLayoutEffect$
|
|
147498
|
+
useLayoutEffect$21(() => {
|
|
147497
147499
|
if (mergedLock) {
|
|
147498
147500
|
const scrollbarSize = getTargetScrollBarSize(document.body).width;
|
|
147499
147501
|
updateCSS(`
|
|
@@ -148436,7 +148438,7 @@ html body {
|
|
|
148436
148438
|
]);
|
|
148437
148439
|
const getPopupContainerNeedParams = getPopupContainer?.length > 0;
|
|
148438
148440
|
const [show, setShow] = react.useState(!getPopupContainer || !getPopupContainerNeedParams);
|
|
148439
|
-
useLayoutEffect$
|
|
148441
|
+
useLayoutEffect$21(() => {
|
|
148440
148442
|
if (!show && getPopupContainerNeedParams && target) setShow(true);
|
|
148441
148443
|
}, [
|
|
148442
148444
|
show,
|
|
@@ -148988,8 +148990,8 @@ html body {
|
|
|
148988
148990
|
ready: false
|
|
148989
148991
|
}));
|
|
148990
148992
|
};
|
|
148991
|
-
useLayoutEffect$
|
|
148992
|
-
useLayoutEffect$
|
|
148993
|
+
useLayoutEffect$21(resetReady, [placement]);
|
|
148994
|
+
useLayoutEffect$21(() => {
|
|
148993
148995
|
if (!open) resetReady();
|
|
148994
148996
|
}, [open]);
|
|
148995
148997
|
return [
|
|
@@ -149033,7 +149035,7 @@ html body {
|
|
|
149033
149035
|
//#endregion
|
|
149034
149036
|
//#region node_modules/@rc-component/trigger/es/hooks/useWatch.js
|
|
149035
149037
|
function useWatch(open, target, popup, onAlign, onScroll) {
|
|
149036
|
-
useLayoutEffect$
|
|
149038
|
+
useLayoutEffect$21(() => {
|
|
149037
149039
|
if (open && target && popup) {
|
|
149038
149040
|
const targetElement = target;
|
|
149039
149041
|
const popupElement = popup;
|
|
@@ -149188,7 +149190,7 @@ html body {
|
|
|
149188
149190
|
id,
|
|
149189
149191
|
onEsc
|
|
149190
149192
|
}));
|
|
149191
|
-
useLayoutEffect$
|
|
149193
|
+
useLayoutEffect$21(() => {
|
|
149192
149194
|
if (uniqueContext && unique && targetEle && !openUncontrolled && !parentContext) if (mergedOpen) uniqueContext.show(getUniqueOptions(mouseEnterDelay), isOpen);
|
|
149193
149195
|
else uniqueContext.hide(mouseLeaveDelay);
|
|
149194
149196
|
}, [mergedOpen, targetEle]);
|
|
@@ -149224,7 +149226,7 @@ html body {
|
|
|
149224
149226
|
if (top) triggerOpen(false);
|
|
149225
149227
|
}
|
|
149226
149228
|
const [inMotion, setInMotion] = react.useState(false);
|
|
149227
|
-
useLayoutEffect$
|
|
149229
|
+
useLayoutEffect$21((firstMount) => {
|
|
149228
149230
|
if (!firstMount || mergedOpen) setInMotion(true);
|
|
149229
149231
|
}, [mergedOpen]);
|
|
149230
149232
|
const [motionPrepareResolve, setMotionPrepareResolve] = react.useState(null);
|
|
@@ -149243,10 +149245,10 @@ html body {
|
|
|
149243
149245
|
if (openRef.current && alignPoint && clickToHide) triggerOpen(false);
|
|
149244
149246
|
};
|
|
149245
149247
|
useWatch(mergedOpen, targetEle, popupEle, triggerAlign, onScroll);
|
|
149246
|
-
useLayoutEffect$
|
|
149248
|
+
useLayoutEffect$21(() => {
|
|
149247
149249
|
triggerAlign();
|
|
149248
149250
|
}, [mousePos, popupPlacement]);
|
|
149249
|
-
useLayoutEffect$
|
|
149251
|
+
useLayoutEffect$21(() => {
|
|
149250
149252
|
if (mergedOpen && !builtinPlacements?.[popupPlacement]) triggerAlign();
|
|
149251
149253
|
}, [JSON.stringify(popupAlign)]);
|
|
149252
149254
|
const alignedClassName = react.useMemo(() => {
|
|
@@ -149286,7 +149288,7 @@ html body {
|
|
|
149286
149288
|
syncTargetSize();
|
|
149287
149289
|
setMotionPrepareResolve(() => resolve);
|
|
149288
149290
|
});
|
|
149289
|
-
useLayoutEffect$
|
|
149291
|
+
useLayoutEffect$21(() => {
|
|
149290
149292
|
if (motionPrepareResolve) {
|
|
149291
149293
|
onAlign();
|
|
149292
149294
|
motionPrepareResolve();
|
|
@@ -149493,7 +149495,7 @@ html body {
|
|
|
149493
149495
|
}
|
|
149494
149496
|
function useTarget(target, open, gap, scrollIntoViewOptions, inlineMode, placeholderRef) {
|
|
149495
149497
|
const [targetElement, setTargetElement] = (0, react.useState)(void 0);
|
|
149496
|
-
useLayoutEffect$
|
|
149498
|
+
useLayoutEffect$21(() => {
|
|
149497
149499
|
const nextElement = typeof target === "function" ? target() : target;
|
|
149498
149500
|
setTargetElement(nextElement || null);
|
|
149499
149501
|
});
|
|
@@ -149523,7 +149525,7 @@ html body {
|
|
|
149523
149525
|
} else setPosInfo(null);
|
|
149524
149526
|
});
|
|
149525
149527
|
const getGapOffset = (index) => (Array.isArray(gap?.offset) ? gap?.offset[index] : gap?.offset) ?? 6;
|
|
149526
|
-
useLayoutEffect$
|
|
149528
|
+
useLayoutEffect$21(() => {
|
|
149527
149529
|
updatePos();
|
|
149528
149530
|
window.addEventListener("resize", updatePos);
|
|
149529
149531
|
window.addEventListener("scroll", updatePos);
|
|
@@ -149813,7 +149815,7 @@ html body {
|
|
|
149813
149815
|
const mergedOpen = mergedCurrent < 0 || mergedCurrent >= steps.length ? false : internalOpen ?? true;
|
|
149814
149816
|
const [hasOpened, setHasOpened] = react.useState(mergedOpen);
|
|
149815
149817
|
const openRef = react.useRef(mergedOpen);
|
|
149816
|
-
useLayoutEffect$
|
|
149818
|
+
useLayoutEffect$21(() => {
|
|
149817
149819
|
if (mergedOpen) {
|
|
149818
149820
|
if (!openRef.current) setMergedCurrent(0);
|
|
149819
149821
|
setHasOpened(true);
|
|
@@ -149830,7 +149832,7 @@ html body {
|
|
|
149830
149832
|
const mergedPlacement = getPlacement(targetElement, placement, stepPlacement);
|
|
149831
149833
|
const mergedArrow = targetElement ? typeof stepArrow === "undefined" ? arrow : stepArrow : false;
|
|
149832
149834
|
const arrowPointAtCenter = typeof mergedArrow === "object" ? mergedArrow.pointAtCenter : false;
|
|
149833
|
-
useLayoutEffect$
|
|
149835
|
+
useLayoutEffect$21(() => {
|
|
149834
149836
|
triggerRef.current?.forceAlign();
|
|
149835
149837
|
}, [arrowPointAtCenter, mergedCurrent]);
|
|
149836
149838
|
const onInternalChange = (nextCurrent) => {
|
|
@@ -149868,7 +149870,7 @@ html body {
|
|
|
149868
149870
|
return;
|
|
149869
149871
|
}
|
|
149870
149872
|
});
|
|
149871
|
-
useLayoutEffect$
|
|
149873
|
+
useLayoutEffect$21(() => {
|
|
149872
149874
|
if (!mergedOpen) return;
|
|
149873
149875
|
window.addEventListener("keydown", keyboardHandler);
|
|
149874
149876
|
return () => {
|
|
@@ -153135,7 +153137,7 @@ html body {
|
|
|
153135
153137
|
anchor,
|
|
153136
153138
|
align: "end",
|
|
153137
153139
|
onClose,
|
|
153138
|
-
hoverCloseDelayMs:
|
|
153140
|
+
hoverCloseDelayMs: 500,
|
|
153139
153141
|
...getAnchorRect === void 0 ? {} : { getAnchorRect },
|
|
153140
153142
|
...hoverAnchor === void 0 ? {} : { hoverAnchor },
|
|
153141
153143
|
actions: [
|
|
@@ -153184,7 +153186,9 @@ html body {
|
|
|
153184
153186
|
}
|
|
153185
153187
|
function ArkmeQuickAddButton({ onContactAdd, onSourceCreated, onBotCreated, onNewDshSession, notificationActivationRevision = 0, onBlockingOverlayChange }) {
|
|
153186
153188
|
useArkmeLocale();
|
|
153187
|
-
const [
|
|
153189
|
+
const [menuMode, setMenuMode] = (0, react$1.useState)();
|
|
153190
|
+
const menuOpen = menuMode !== void 0;
|
|
153191
|
+
const closeMenu = () => setMenuMode(void 0);
|
|
153188
153192
|
const [menuError, setMenuError] = (0, react$1.useState)("");
|
|
153189
153193
|
const [dialogKind, setDialogKind] = (0, react$1.useState)();
|
|
153190
153194
|
const [dialogBusy, setDialogBusy] = (0, react$1.useState)(false);
|
|
@@ -153207,7 +153211,7 @@ html body {
|
|
|
153207
153211
|
if (notificationRevisionRef.current === notificationActivationRevision) return;
|
|
153208
153212
|
notificationRevisionRef.current = notificationActivationRevision;
|
|
153209
153213
|
pendingNotificationDismissRef.current = true;
|
|
153210
|
-
|
|
153214
|
+
closeMenu();
|
|
153211
153215
|
if (!dialogBusy) {
|
|
153212
153216
|
pendingNotificationDismissRef.current = false;
|
|
153213
153217
|
setDialogKind(void 0);
|
|
@@ -153219,18 +153223,18 @@ html body {
|
|
|
153219
153223
|
setDialogKind(void 0);
|
|
153220
153224
|
}, [dialogBusy]);
|
|
153221
153225
|
const chooseDialog = (kind) => {
|
|
153222
|
-
|
|
153226
|
+
closeMenu();
|
|
153223
153227
|
setDialogBusy(false);
|
|
153224
153228
|
setDialogKind(kind);
|
|
153225
153229
|
};
|
|
153226
153230
|
const openMenu = () => {
|
|
153227
153231
|
setMenuError("");
|
|
153228
|
-
|
|
153232
|
+
setMenuMode((current) => current ?? "hover");
|
|
153229
153233
|
};
|
|
153230
153234
|
const menu = /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeQuickAddMenu, {
|
|
153231
153235
|
open: menuOpen,
|
|
153232
|
-
onClose:
|
|
153233
|
-
hoverAnchor: triggerRef.current ?? void 0,
|
|
153236
|
+
onClose: closeMenu,
|
|
153237
|
+
hoverAnchor: menuMode === "hover" ? triggerRef.current ?? void 0 : void 0,
|
|
153234
153238
|
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
153235
153239
|
"data-arkme-feedback": "neutral",
|
|
153236
153240
|
ref: triggerRef,
|
|
@@ -153243,9 +153247,9 @@ html body {
|
|
|
153243
153247
|
onPointerEnter: (event) => {
|
|
153244
153248
|
if (event?.pointerType !== "touch") openMenu();
|
|
153245
153249
|
},
|
|
153246
|
-
onClick: (
|
|
153247
|
-
|
|
153248
|
-
|
|
153250
|
+
onClick: () => {
|
|
153251
|
+
setMenuError("");
|
|
153252
|
+
setMenuMode("pinned");
|
|
153249
153253
|
},
|
|
153250
153254
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, {
|
|
153251
153255
|
size: 20,
|
|
@@ -153257,13 +153261,13 @@ html body {
|
|
|
153257
153261
|
try {
|
|
153258
153262
|
onNewDshSession();
|
|
153259
153263
|
setMenuError("");
|
|
153260
|
-
|
|
153264
|
+
closeMenu();
|
|
153261
153265
|
} catch (error) {
|
|
153262
153266
|
setMenuError(error instanceof Error ? error.message : "暂时无法新建 DSH 会话,请稍后再试");
|
|
153263
153267
|
}
|
|
153264
153268
|
},
|
|
153265
153269
|
onContactAdd: () => {
|
|
153266
|
-
|
|
153270
|
+
closeMenu();
|
|
153267
153271
|
onContactAdd();
|
|
153268
153272
|
},
|
|
153269
153273
|
onCreateGroup: () => {
|
|
@@ -163486,1642 +163490,6 @@ html body {
|
|
|
163486
163490
|
});
|
|
163487
163491
|
}
|
|
163488
163492
|
//#endregion
|
|
163489
|
-
//#region src/client/arko-native-transport.ts
|
|
163490
|
-
function record(value) {
|
|
163491
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
163492
|
-
}
|
|
163493
|
-
function requestOf(payload) {
|
|
163494
|
-
return record(record(record(payload).args).request);
|
|
163495
|
-
}
|
|
163496
|
-
function messageKey(message) {
|
|
163497
|
-
return message.presentationKey ?? (message.messageId === void 0 ? message.id : `arko:${String(message.sessionId ?? "")}:${String(message.messageId)}`);
|
|
163498
|
-
}
|
|
163499
|
-
function renderContent(message) {
|
|
163500
|
-
return [...message.reasoning ? [{
|
|
163501
|
-
type: "reasoning",
|
|
163502
|
-
text: message.reasoning
|
|
163503
|
-
}] : [], {
|
|
163504
|
-
type: "text",
|
|
163505
|
-
text: message.text
|
|
163506
|
-
}];
|
|
163507
|
-
}
|
|
163508
|
-
function endReason(message) {
|
|
163509
|
-
if (message.status === "error" || message.runStatus === "failed") return {
|
|
163510
|
-
kind: "error",
|
|
163511
|
-
error: {
|
|
163512
|
-
code: "ARKO_RUN_FAILED",
|
|
163513
|
-
message: message.text || "Arko 运行失败"
|
|
163514
|
-
}
|
|
163515
|
-
};
|
|
163516
|
-
if (message.runStatus === "cancelled") return {
|
|
163517
|
-
kind: "aborted",
|
|
163518
|
-
reason: { kind: "user" }
|
|
163519
|
-
};
|
|
163520
|
-
if (message.runStatus === "waiting_user") return { kind: "blocked" };
|
|
163521
|
-
if (message.runStatus === "expired" || message.runStatus === "partial") return { kind: "interrupted" };
|
|
163522
|
-
return { kind: "completed" };
|
|
163523
|
-
}
|
|
163524
|
-
const ok = (value) => ({
|
|
163525
|
-
ok: true,
|
|
163526
|
-
value
|
|
163527
|
-
});
|
|
163528
|
-
const denied = (message, code = "gateway/bad-request") => ({
|
|
163529
|
-
ok: false,
|
|
163530
|
-
error: {
|
|
163531
|
-
code,
|
|
163532
|
-
message,
|
|
163533
|
-
details: {}
|
|
163534
|
-
}
|
|
163535
|
-
});
|
|
163536
|
-
/**
|
|
163537
|
-
* Render-only protocol adapter. Snapshots and admitted actions remain owned by
|
|
163538
|
-
* ArkmeArkoSurface; this object owns only DSH cursor/identity presentation data.
|
|
163539
|
-
* Unsupported calls never reach the host transport or any Arkme API.
|
|
163540
|
-
*/
|
|
163541
|
-
function createArkoNativeTransport(initial, initialActions) {
|
|
163542
|
-
let snapshot = initial;
|
|
163543
|
-
let actions = initialActions;
|
|
163544
|
-
const accountKey = initial.accountKey;
|
|
163545
|
-
const sessionId = `arko-native-${crypto.randomUUID()}`;
|
|
163546
|
-
const createdAt = Date.now();
|
|
163547
|
-
let disposed = false;
|
|
163548
|
-
let historyRevision = 0;
|
|
163549
|
-
let submitting = false;
|
|
163550
|
-
let changingModel = false;
|
|
163551
|
-
let pendingPrompt;
|
|
163552
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
163553
|
-
const streams = /* @__PURE__ */ new Set();
|
|
163554
|
-
const sequenceOrigin = 2 ** 40;
|
|
163555
|
-
let nextSeq = sequenceOrigin;
|
|
163556
|
-
let pageRequest;
|
|
163557
|
-
let journal = [];
|
|
163558
|
-
let projected = [];
|
|
163559
|
-
let turn = 0;
|
|
163560
|
-
let assistantRevision = 0;
|
|
163561
|
-
let activeAssistant;
|
|
163562
|
-
function emit(endpoint, value) {
|
|
163563
|
-
for (const stream of streams) if (stream.endpoint === endpoint && (endpoint !== "session/follow" || stream.historyRevision === historyRevision)) stream.push(value);
|
|
163564
|
-
}
|
|
163565
|
-
function append(type, data, message, surfaceOp) {
|
|
163566
|
-
const event = {
|
|
163567
|
-
type,
|
|
163568
|
-
seq: nextSeq++,
|
|
163569
|
-
time: Math.max(0, Math.trunc(message.createdAtMillis ?? createdAt)),
|
|
163570
|
-
data,
|
|
163571
|
-
...surfaceOp === void 0 ? {} : { surfaceOp },
|
|
163572
|
-
...type.startsWith("arko/") ? { ignorable: true } : {}
|
|
163573
|
-
};
|
|
163574
|
-
const entry = {
|
|
163575
|
-
type: "event",
|
|
163576
|
-
event
|
|
163577
|
-
};
|
|
163578
|
-
journal.push(entry);
|
|
163579
|
-
emit("session/follow", entry);
|
|
163580
|
-
return event.seq;
|
|
163581
|
-
}
|
|
163582
|
-
function appendMessage(row) {
|
|
163583
|
-
const { message, key, rpcId } = row;
|
|
163584
|
-
const source = message.role === "user" ? {
|
|
163585
|
-
kind: "user",
|
|
163586
|
-
...rpcId === void 0 ? {} : { rpcId }
|
|
163587
|
-
} : message.role === "divider" ? {
|
|
163588
|
-
kind: "plugin",
|
|
163589
|
-
plugin: "arko",
|
|
163590
|
-
form: "notice",
|
|
163591
|
-
summary: message.text
|
|
163592
|
-
} : {
|
|
163593
|
-
kind: "model",
|
|
163594
|
-
provider: "arko",
|
|
163595
|
-
model: "unspecified"
|
|
163596
|
-
};
|
|
163597
|
-
const wire = {
|
|
163598
|
-
id: key,
|
|
163599
|
-
role: message.role === "assistant" ? "assistant" : "user",
|
|
163600
|
-
source,
|
|
163601
|
-
content: renderContent(message)
|
|
163602
|
-
};
|
|
163603
|
-
row.seq = append(message.role === "assistant" ? "assistant/message" : "user/message", message.role === "assistant" ? {
|
|
163604
|
-
turn: row.turn,
|
|
163605
|
-
step: 1,
|
|
163606
|
-
message: wire,
|
|
163607
|
-
stream: activeAssistant?.attemptId === key ? activeAssistant.stream.slice() : [],
|
|
163608
|
-
...[
|
|
163609
|
-
"cancelled",
|
|
163610
|
-
"partial",
|
|
163611
|
-
"expired"
|
|
163612
|
-
].includes(message.runStatus ?? "") ? { interrupted: true } : {}
|
|
163613
|
-
} : wire, message, "append");
|
|
163614
|
-
}
|
|
163615
|
-
function assistantFrame(frame) {
|
|
163616
|
-
emit("session/follow", {
|
|
163617
|
-
type: "assistant-stream",
|
|
163618
|
-
frame: {
|
|
163619
|
-
...frame,
|
|
163620
|
-
revision: ++assistantRevision
|
|
163621
|
-
}
|
|
163622
|
-
});
|
|
163623
|
-
}
|
|
163624
|
-
function assistantChunk(chunk, message) {
|
|
163625
|
-
if (activeAssistant === void 0) return;
|
|
163626
|
-
const time = Math.max(0, Math.trunc(message.createdAtMillis ?? createdAt));
|
|
163627
|
-
const index = activeAssistant.nextIndex++;
|
|
163628
|
-
activeAssistant.stream.push({
|
|
163629
|
-
type: "chunk",
|
|
163630
|
-
time,
|
|
163631
|
-
chunk
|
|
163632
|
-
});
|
|
163633
|
-
assistantFrame({
|
|
163634
|
-
type: "chunk",
|
|
163635
|
-
attemptId: activeAssistant.attemptId,
|
|
163636
|
-
index,
|
|
163637
|
-
time,
|
|
163638
|
-
chunk
|
|
163639
|
-
});
|
|
163640
|
-
}
|
|
163641
|
-
function streamMessage(row, previous) {
|
|
163642
|
-
if (activeAssistant?.attemptId !== row.key) {
|
|
163643
|
-
activeAssistant = {
|
|
163644
|
-
attemptId: row.key,
|
|
163645
|
-
startedAfterSeq: nextSeq - 1,
|
|
163646
|
-
turn: row.turn,
|
|
163647
|
-
step: 1,
|
|
163648
|
-
nextIndex: 0,
|
|
163649
|
-
stream: []
|
|
163650
|
-
};
|
|
163651
|
-
assistantFrame({
|
|
163652
|
-
type: "start",
|
|
163653
|
-
attemptId: row.key,
|
|
163654
|
-
startedAfterSeq: activeAssistant.startedAfterSeq,
|
|
163655
|
-
turn: row.turn,
|
|
163656
|
-
step: 1
|
|
163657
|
-
});
|
|
163658
|
-
}
|
|
163659
|
-
for (const [index, kind] of ["reasoning", "text"].entries()) {
|
|
163660
|
-
const text = kind === "reasoning" ? row.message.reasoning ?? "" : row.message.text;
|
|
163661
|
-
const before = previous === void 0 ? void 0 : kind === "reasoning" ? previous.reasoning ?? "" : previous.text;
|
|
163662
|
-
if (before === void 0 || !text.startsWith(before)) assistantChunk({
|
|
163663
|
-
type: "block-start",
|
|
163664
|
-
index,
|
|
163665
|
-
blockType: kind
|
|
163666
|
-
}, row.message);
|
|
163667
|
-
const delta = before !== void 0 && text.startsWith(before) ? text.slice(before.length) : text;
|
|
163668
|
-
if (delta !== "") assistantChunk({
|
|
163669
|
-
type: `${kind}-delta`,
|
|
163670
|
-
index,
|
|
163671
|
-
text: delta
|
|
163672
|
-
}, row.message);
|
|
163673
|
-
}
|
|
163674
|
-
}
|
|
163675
|
-
function settleAssistant(row) {
|
|
163676
|
-
appendMessage(row);
|
|
163677
|
-
if (activeAssistant?.attemptId === row.key) {
|
|
163678
|
-
assistantFrame({
|
|
163679
|
-
type: "end",
|
|
163680
|
-
attemptId: row.key,
|
|
163681
|
-
index: activeAssistant.nextIndex,
|
|
163682
|
-
outcome: {
|
|
163683
|
-
kind: "committed",
|
|
163684
|
-
eventType: "assistant/message",
|
|
163685
|
-
seq: row.seq
|
|
163686
|
-
}
|
|
163687
|
-
});
|
|
163688
|
-
activeAssistant = void 0;
|
|
163689
|
-
}
|
|
163690
|
-
}
|
|
163691
|
-
function endMessage(row) {
|
|
163692
|
-
if (row.message.role !== "assistant" || row.message.status === "sending" || row.ended) return;
|
|
163693
|
-
append("step/end", {
|
|
163694
|
-
turn: row.turn,
|
|
163695
|
-
step: 1
|
|
163696
|
-
}, row.message);
|
|
163697
|
-
append("turn/end", {
|
|
163698
|
-
turn: row.turn,
|
|
163699
|
-
reason: endReason(row.message)
|
|
163700
|
-
}, row.message);
|
|
163701
|
-
row.ended = true;
|
|
163702
|
-
}
|
|
163703
|
-
function addMessage(message) {
|
|
163704
|
-
if (message.role === "user" || turn === 0 || message.role === "assistant" && projected.at(-1)?.ended === true) {
|
|
163705
|
-
turn++;
|
|
163706
|
-
append("turn/start", { turn }, message);
|
|
163707
|
-
append("step/start", {
|
|
163708
|
-
turn,
|
|
163709
|
-
step: 1
|
|
163710
|
-
}, message);
|
|
163711
|
-
}
|
|
163712
|
-
const row = {
|
|
163713
|
-
message,
|
|
163714
|
-
key: messageKey(message),
|
|
163715
|
-
seq: -1,
|
|
163716
|
-
turn,
|
|
163717
|
-
ended: false
|
|
163718
|
-
};
|
|
163719
|
-
if (message.role === "user" && pendingPrompt !== void 0 && message.text.trim() === pendingPrompt.text) {
|
|
163720
|
-
row.rpcId = pendingPrompt.requestId;
|
|
163721
|
-
pendingPrompt = void 0;
|
|
163722
|
-
}
|
|
163723
|
-
if (message.role === "assistant" && message.status === "sending") streamMessage(row);
|
|
163724
|
-
else appendMessage(row);
|
|
163725
|
-
endMessage(row);
|
|
163726
|
-
projected.push(row);
|
|
163727
|
-
}
|
|
163728
|
-
function historyRecord(message, seq) {
|
|
163729
|
-
const key = messageKey(message);
|
|
163730
|
-
const wire = {
|
|
163731
|
-
id: key,
|
|
163732
|
-
role: message.role === "assistant" ? "assistant" : "user",
|
|
163733
|
-
source: message.role === "assistant" ? {
|
|
163734
|
-
kind: "model",
|
|
163735
|
-
provider: "arko",
|
|
163736
|
-
model: "unspecified"
|
|
163737
|
-
} : message.role === "divider" ? {
|
|
163738
|
-
kind: "plugin",
|
|
163739
|
-
plugin: "arko",
|
|
163740
|
-
form: "notice",
|
|
163741
|
-
summary: message.text
|
|
163742
|
-
} : { kind: "user" },
|
|
163743
|
-
content: renderContent(message)
|
|
163744
|
-
};
|
|
163745
|
-
const presentationTurn = seq + 1;
|
|
163746
|
-
return {
|
|
163747
|
-
entry: {
|
|
163748
|
-
type: "event",
|
|
163749
|
-
event: {
|
|
163750
|
-
type: message.role === "assistant" ? "assistant/message" : "user/message",
|
|
163751
|
-
seq,
|
|
163752
|
-
time: Math.max(0, Math.trunc(message.createdAtMillis ?? createdAt)),
|
|
163753
|
-
surfaceOp: "append",
|
|
163754
|
-
data: message.role === "assistant" ? {
|
|
163755
|
-
turn: presentationTurn,
|
|
163756
|
-
step: 1,
|
|
163757
|
-
message: wire,
|
|
163758
|
-
stream: [],
|
|
163759
|
-
...[
|
|
163760
|
-
"cancelled",
|
|
163761
|
-
"partial",
|
|
163762
|
-
"expired"
|
|
163763
|
-
].includes(message.runStatus ?? "") ? { interrupted: true } : {}
|
|
163764
|
-
} : wire
|
|
163765
|
-
}
|
|
163766
|
-
},
|
|
163767
|
-
row: {
|
|
163768
|
-
message,
|
|
163769
|
-
key,
|
|
163770
|
-
seq,
|
|
163771
|
-
turn: presentationTurn,
|
|
163772
|
-
ended: true
|
|
163773
|
-
}
|
|
163774
|
-
};
|
|
163775
|
-
}
|
|
163776
|
-
function prependHistory(messages) {
|
|
163777
|
-
const known = new Set(projected.map((row) => row.key));
|
|
163778
|
-
const persistedKey = (message) => message.messageId === void 0 ? void 0 : `${message.sessionId}:${message.messageId}`;
|
|
163779
|
-
const persisted = new Set(projected.map((row) => persistedKey(row.message)).filter((key) => key !== void 0));
|
|
163780
|
-
const older = messages.filter((message) => {
|
|
163781
|
-
const key = messageKey(message), identity = persistedKey(message);
|
|
163782
|
-
if (known.has(key) || identity !== void 0 && persisted.has(identity)) return false;
|
|
163783
|
-
known.add(key);
|
|
163784
|
-
if (identity !== void 0) persisted.add(identity);
|
|
163785
|
-
return true;
|
|
163786
|
-
});
|
|
163787
|
-
const base = journal[0]?.event.seq ?? nextSeq;
|
|
163788
|
-
if (older.length > base) throw new Error("Arko 历史窗口边界已变化,请重新打开会话");
|
|
163789
|
-
const entries = older.map((message, index) => historyRecord(message, base - older.length + index));
|
|
163790
|
-
journal = [...entries.map((value) => value.entry), ...journal];
|
|
163791
|
-
projected = [...entries.map((value) => value.row), ...projected];
|
|
163792
|
-
}
|
|
163793
|
-
function seedHistory(messages) {
|
|
163794
|
-
for (const message of messages) {
|
|
163795
|
-
if (message.status === "sending" || message.messageId === void 0) {
|
|
163796
|
-
addMessage(message);
|
|
163797
|
-
continue;
|
|
163798
|
-
}
|
|
163799
|
-
const value = historyRecord(message, nextSeq++);
|
|
163800
|
-
journal.push(value.entry);
|
|
163801
|
-
projected.push(value.row);
|
|
163802
|
-
turn = Math.max(turn, value.row.turn);
|
|
163803
|
-
}
|
|
163804
|
-
}
|
|
163805
|
-
function selectedModel() {
|
|
163806
|
-
const route = snapshot.modelCatalog?.effectiveRouteKey;
|
|
163807
|
-
return route ? {
|
|
163808
|
-
provider: "arko",
|
|
163809
|
-
model: route
|
|
163810
|
-
} : null;
|
|
163811
|
-
}
|
|
163812
|
-
function projectionValues() {
|
|
163813
|
-
return {
|
|
163814
|
-
title: snapshot.displayName,
|
|
163815
|
-
modelSelection: {
|
|
163816
|
-
lastUsed: null,
|
|
163817
|
-
next: selectedModel()
|
|
163818
|
-
},
|
|
163819
|
-
sessionListMetadata: {
|
|
163820
|
-
blank: false,
|
|
163821
|
-
lastPromptAt: snapshot.messages.filter((message) => message.role === "user").at(-1)?.createdAtMillis ?? null
|
|
163822
|
-
}
|
|
163823
|
-
};
|
|
163824
|
-
}
|
|
163825
|
-
function projections() {
|
|
163826
|
-
return {
|
|
163827
|
-
asOfSeq: nextSeq - 1,
|
|
163828
|
-
values: projectionValues()
|
|
163829
|
-
};
|
|
163830
|
-
}
|
|
163831
|
-
function summary() {
|
|
163832
|
-
return {
|
|
163833
|
-
sessionId,
|
|
163834
|
-
updatedAt: snapshot.messages.at(-1)?.createdAtMillis ?? createdAt,
|
|
163835
|
-
running: snapshot.busy,
|
|
163836
|
-
blank: false,
|
|
163837
|
-
projections: projections()
|
|
163838
|
-
};
|
|
163839
|
-
}
|
|
163840
|
-
function checkSession(request) {
|
|
163841
|
-
return request.sessionId === sessionId;
|
|
163842
|
-
}
|
|
163843
|
-
function blocked() {
|
|
163844
|
-
return snapshot.loading ? "Arko 正在加载" : snapshot.inputBlockedReason || (snapshot.busy || submitting || changingModel ? "Arko 正在处理上一项操作" : void 0);
|
|
163845
|
-
}
|
|
163846
|
-
async function dispatch(method, payload) {
|
|
163847
|
-
const request = requestOf(payload);
|
|
163848
|
-
switch (method) {
|
|
163849
|
-
case "settings/describe": return ok({
|
|
163850
|
-
writable: false,
|
|
163851
|
-
hasDocument: false,
|
|
163852
|
-
namespaces: []
|
|
163853
|
-
});
|
|
163854
|
-
case "credentials/describe": return ok({});
|
|
163855
|
-
case "dynamicCordisRunner/syncInspectManifest": return ok(null);
|
|
163856
|
-
case "dynamicCordisRunner/inventory":
|
|
163857
|
-
case "commands/list":
|
|
163858
|
-
case "llm/listConfigurableProviders": return ok([]);
|
|
163859
|
-
case "agentPresets/list": return ok({
|
|
163860
|
-
presets: [],
|
|
163861
|
-
authorable: false
|
|
163862
|
-
});
|
|
163863
|
-
case "subagents/list": return ok({
|
|
163864
|
-
entries: [],
|
|
163865
|
-
parentAvailable: false
|
|
163866
|
-
});
|
|
163867
|
-
case "skills/list": return ok({ skills: [] });
|
|
163868
|
-
case "session/list": return ok({ items: [summary()] });
|
|
163869
|
-
case "llm/listProviders": return ok([{
|
|
163870
|
-
id: "arko",
|
|
163871
|
-
name: snapshot.displayName
|
|
163872
|
-
}]);
|
|
163873
|
-
case "session/modelCatalog": {
|
|
163874
|
-
const catalog = snapshot.modelCatalog;
|
|
163875
|
-
return ok({
|
|
163876
|
-
default: {
|
|
163877
|
-
provider: "arko",
|
|
163878
|
-
model: catalog?.defaultRouteKey || catalog?.effectiveRouteKey || ""
|
|
163879
|
-
},
|
|
163880
|
-
routableProviders: catalog?.options.length ? ["arko"] : [],
|
|
163881
|
-
groups: catalog === null ? [] : [{
|
|
163882
|
-
id: "arko",
|
|
163883
|
-
name: snapshot.displayName,
|
|
163884
|
-
models: catalog.options.map((option) => ({
|
|
163885
|
-
id: option.routeKey,
|
|
163886
|
-
name: option.displayName,
|
|
163887
|
-
description: option.description
|
|
163888
|
-
}))
|
|
163889
|
-
}],
|
|
163890
|
-
failures: []
|
|
163891
|
-
});
|
|
163892
|
-
}
|
|
163893
|
-
case "session/selectModel": {
|
|
163894
|
-
if (!checkSession(request)) return denied("Arko 会话已失效");
|
|
163895
|
-
const reason = blocked();
|
|
163896
|
-
if (reason !== void 0) return denied(reason);
|
|
163897
|
-
if (request.provider !== "arko" || typeof request.model !== "string" || request.reasoningEffort !== void 0 || !snapshot.modelCatalog?.options.some((option) => option.routeKey === request.model)) return denied("此 Arko 模型不可用");
|
|
163898
|
-
if (request.model === snapshot.modelCatalog.effectiveRouteKey) return ok({ selected: selectedModel() });
|
|
163899
|
-
changingModel = true;
|
|
163900
|
-
try {
|
|
163901
|
-
if (await actions.selectModel(request.model) !== true && snapshot.modelCatalog?.effectiveRouteKey !== request.model) return denied(snapshot.error || "Arko 模型切换未确认");
|
|
163902
|
-
return ok({ selected: {
|
|
163903
|
-
provider: "arko",
|
|
163904
|
-
model: request.model
|
|
163905
|
-
} });
|
|
163906
|
-
} finally {
|
|
163907
|
-
changingModel = false;
|
|
163908
|
-
}
|
|
163909
|
-
}
|
|
163910
|
-
case "session/prompt": {
|
|
163911
|
-
if (!checkSession(request)) return denied("Arko 会话已失效");
|
|
163912
|
-
const reason = blocked();
|
|
163913
|
-
if (reason !== void 0) return denied(reason);
|
|
163914
|
-
if (request.mode !== "queue" || typeof request.requestId !== "string" || request.requestId.length === 0) return denied("Arko 不支持此发送方式");
|
|
163915
|
-
if (!Array.isArray(request.content) || request.content.some((part) => record(part).type !== "text" || typeof record(part).text !== "string")) return denied("Arko 当前仅支持文字输入");
|
|
163916
|
-
const text = request.content.map((part) => record(part).text).join("").trim();
|
|
163917
|
-
if (!text || text.length > 60 * 1024) return denied("Arko 输入为空或超过长度上限");
|
|
163918
|
-
submitting = true;
|
|
163919
|
-
pendingPrompt = {
|
|
163920
|
-
requestId: request.requestId,
|
|
163921
|
-
text
|
|
163922
|
-
};
|
|
163923
|
-
try {
|
|
163924
|
-
if (await actions.submit(text) !== true) {
|
|
163925
|
-
pendingPrompt = void 0;
|
|
163926
|
-
return denied(snapshot.error || "Arko 未接受此次发送");
|
|
163927
|
-
}
|
|
163928
|
-
return ok({ accepted: true });
|
|
163929
|
-
} catch (error) {
|
|
163930
|
-
pendingPrompt = void 0;
|
|
163931
|
-
throw error;
|
|
163932
|
-
} finally {
|
|
163933
|
-
submitting = false;
|
|
163934
|
-
}
|
|
163935
|
-
}
|
|
163936
|
-
case "session/cancel":
|
|
163937
|
-
if (!checkSession(request)) return denied("Arko 会话已失效");
|
|
163938
|
-
if (!snapshot.busy) return denied("Arko 当前没有可停止的运行");
|
|
163939
|
-
return await actions.cancel() === true ? ok({ accepted: true }) : denied(snapshot.error || "Arko 停止请求未确认");
|
|
163940
|
-
case "session/page": {
|
|
163941
|
-
if (record(request.address).kind !== "session" || record(request.address).sessionId !== sessionId) return denied("Arko 会话已失效");
|
|
163942
|
-
if (request.beforeSeq !== void 0 && (!Number.isSafeInteger(request.beforeSeq) || Number(request.beforeSeq) < 0)) return denied("Arko 历史边界无效");
|
|
163943
|
-
const before = typeof request.beforeSeq === "number" ? request.beforeSeq : Infinity;
|
|
163944
|
-
const through = typeof request.throughSeq === "number" ? request.throughSeq : nextSeq - 1;
|
|
163945
|
-
if (snapshot.hasMore && before <= (journal[0]?.event.seq ?? nextSeq)) {
|
|
163946
|
-
pageRequest ??= (async () => {
|
|
163947
|
-
const page = await actions.loadEarlier();
|
|
163948
|
-
if (disposed) throw new Error("Arko 原生呈现已关闭");
|
|
163949
|
-
prependHistory(page.messages);
|
|
163950
|
-
snapshot = {
|
|
163951
|
-
...snapshot,
|
|
163952
|
-
hasMore: page.hasMore
|
|
163953
|
-
};
|
|
163954
|
-
})().finally(() => {
|
|
163955
|
-
pageRequest = void 0;
|
|
163956
|
-
});
|
|
163957
|
-
await pageRequest;
|
|
163958
|
-
}
|
|
163959
|
-
const available = journal.filter((entry) => entry.event.seq <= through && entry.event.seq < before);
|
|
163960
|
-
const limit = typeof request.maxMessages === "number" && Number.isSafeInteger(request.maxMessages) ? Math.min(50, Math.max(1, request.maxMessages)) : 50;
|
|
163961
|
-
return ok({
|
|
163962
|
-
records: available.slice(-limit),
|
|
163963
|
-
hasMore: available.length > limit || snapshot.hasMore === true
|
|
163964
|
-
});
|
|
163965
|
-
}
|
|
163966
|
-
default: return denied(`Arko 不支持原生操作:${method}`);
|
|
163967
|
-
}
|
|
163968
|
-
}
|
|
163969
|
-
seedHistory(snapshot.messages);
|
|
163970
|
-
return {
|
|
163971
|
-
sessionId,
|
|
163972
|
-
get historyRevision() {
|
|
163973
|
-
return historyRevision;
|
|
163974
|
-
},
|
|
163975
|
-
getSnapshot: () => snapshot,
|
|
163976
|
-
subscribe(listener) {
|
|
163977
|
-
if (disposed) return () => {};
|
|
163978
|
-
listeners.add(listener);
|
|
163979
|
-
return () => {
|
|
163980
|
-
listeners.delete(listener);
|
|
163981
|
-
};
|
|
163982
|
-
},
|
|
163983
|
-
update(next, nextActions) {
|
|
163984
|
-
if (disposed) throw new Error("Arko 原生呈现已销毁");
|
|
163985
|
-
if (next.accountKey !== accountKey) throw new Error("Arko 账号切换必须建立新的原生呈现");
|
|
163986
|
-
const previous = snapshot;
|
|
163987
|
-
const oldValues = projectionValues();
|
|
163988
|
-
snapshot = next;
|
|
163989
|
-
if (nextActions !== void 0) actions = nextActions;
|
|
163990
|
-
if (projected.length > 0) {
|
|
163991
|
-
const head = next.messages.findIndex((message) => messageKey(message) === projected[0].key);
|
|
163992
|
-
if (head > 0) prependHistory(next.messages.slice(0, head));
|
|
163993
|
-
}
|
|
163994
|
-
if (projected.some((row, index) => {
|
|
163995
|
-
const message = next.messages[index];
|
|
163996
|
-
if (message === void 0 || messageKey(message) !== row.key) return true;
|
|
163997
|
-
return row.seq >= 0 && (row.message.text !== message.text || row.message.reasoning !== message.reasoning || row.message.role !== message.role || row.message.status !== message.status || JSON.stringify(endReason(row.message)) !== JSON.stringify(endReason(message)));
|
|
163998
|
-
})) {
|
|
163999
|
-
historyRevision++;
|
|
164000
|
-
journal = [];
|
|
164001
|
-
projected = [];
|
|
164002
|
-
turn = 0;
|
|
164003
|
-
activeAssistant = void 0;
|
|
164004
|
-
assistantRevision = 0;
|
|
164005
|
-
nextSeq = sequenceOrigin;
|
|
164006
|
-
seedHistory(next.messages);
|
|
164007
|
-
} else for (let index = 0; index < next.messages.length; index++) {
|
|
164008
|
-
const message = next.messages[index];
|
|
164009
|
-
const row = projected[index];
|
|
164010
|
-
if (row === void 0) {
|
|
164011
|
-
addMessage(message);
|
|
164012
|
-
continue;
|
|
164013
|
-
}
|
|
164014
|
-
const previousMessage = row.message;
|
|
164015
|
-
row.message = message;
|
|
164016
|
-
if (message.role === "assistant" && row.seq < 0) if (message.status === "sending") streamMessage(row, previousMessage);
|
|
164017
|
-
else settleAssistant(row);
|
|
164018
|
-
endMessage(row);
|
|
164019
|
-
}
|
|
164020
|
-
const values = projectionValues();
|
|
164021
|
-
const changedKeys = Object.keys(values).filter((key) => JSON.stringify(values[key]) !== JSON.stringify(oldValues[key]));
|
|
164022
|
-
const context = {
|
|
164023
|
-
id: "",
|
|
164024
|
-
role: "divider",
|
|
164025
|
-
text: "",
|
|
164026
|
-
status: "done",
|
|
164027
|
-
createdAtMillis: Date.now()
|
|
164028
|
-
};
|
|
164029
|
-
if (changedKeys.length > 0) append("arko/presentation", Object.fromEntries(changedKeys.map((key) => [key, values[key]])), context);
|
|
164030
|
-
for (const key of changedKeys) emit("session/control", {
|
|
164031
|
-
type: "projection",
|
|
164032
|
-
sessionId,
|
|
164033
|
-
key,
|
|
164034
|
-
value: values[key],
|
|
164035
|
-
seq: nextSeq - 1
|
|
164036
|
-
});
|
|
164037
|
-
if (previous.busy !== next.busy) emit("$events", {
|
|
164038
|
-
type: "emit",
|
|
164039
|
-
event: "api-session/status",
|
|
164040
|
-
args: [sessionId, next.busy]
|
|
164041
|
-
});
|
|
164042
|
-
if (next.error && previous.error !== next.error) emit("$events", {
|
|
164043
|
-
type: "emit",
|
|
164044
|
-
event: "api-session/error",
|
|
164045
|
-
args: [sessionId, next.error]
|
|
164046
|
-
});
|
|
164047
|
-
if (JSON.stringify(previous.modelCatalog) !== JSON.stringify(next.modelCatalog)) emit("$events", {
|
|
164048
|
-
type: "emit",
|
|
164049
|
-
event: "llm/adapters-updated",
|
|
164050
|
-
args: []
|
|
164051
|
-
});
|
|
164052
|
-
for (const listener of listeners) listener();
|
|
164053
|
-
},
|
|
164054
|
-
async fetch(_input, init) {
|
|
164055
|
-
let rpcId = "";
|
|
164056
|
-
let result;
|
|
164057
|
-
try {
|
|
164058
|
-
if (typeof init.body !== "string") throw new Error("Arko 原生请求格式无效");
|
|
164059
|
-
const envelope = record(JSON.parse(init.body));
|
|
164060
|
-
rpcId = typeof envelope.rpcId === "string" ? envelope.rpcId : "";
|
|
164061
|
-
if (envelope.type !== "client-request" || typeof envelope.method !== "string" || rpcId === "") throw new Error("Arko 原生请求格式无效");
|
|
164062
|
-
if (disposed || init.signal?.aborted) result = denied("Arko 原生呈现已关闭");
|
|
164063
|
-
else {
|
|
164064
|
-
result = await dispatch(envelope.method, envelope.payload);
|
|
164065
|
-
if (disposed || init.signal?.aborted) result = denied("Arko 原生呈现已关闭");
|
|
164066
|
-
}
|
|
164067
|
-
} catch (error) {
|
|
164068
|
-
result = denied(error instanceof Error ? error.message : "Arko 原生请求失败");
|
|
164069
|
-
}
|
|
164070
|
-
return new Response(JSON.stringify({
|
|
164071
|
-
type: "server-response",
|
|
164072
|
-
rpcId,
|
|
164073
|
-
result
|
|
164074
|
-
}), { headers: { "content-type": "application/json" } });
|
|
164075
|
-
},
|
|
164076
|
-
async *openStream(endpoint, payload, signal) {
|
|
164077
|
-
if (disposed || signal.aborted) return;
|
|
164078
|
-
if (![
|
|
164079
|
-
"$events",
|
|
164080
|
-
"session/control",
|
|
164081
|
-
"session/follow",
|
|
164082
|
-
"workspace/follow"
|
|
164083
|
-
].includes(endpoint)) throw new Error(`Arko 不支持原生流:${endpoint}`);
|
|
164084
|
-
if (endpoint === "session/follow") {
|
|
164085
|
-
const address = record(requestOf(payload).address);
|
|
164086
|
-
if (address.kind !== "session" || address.sessionId !== sessionId) throw new Error("Arko 会话已失效");
|
|
164087
|
-
}
|
|
164088
|
-
const queue = [];
|
|
164089
|
-
let wake;
|
|
164090
|
-
let ended = false;
|
|
164091
|
-
const sink = {
|
|
164092
|
-
endpoint,
|
|
164093
|
-
historyRevision,
|
|
164094
|
-
push(value) {
|
|
164095
|
-
if (!ended) {
|
|
164096
|
-
queue.push(value);
|
|
164097
|
-
wake?.();
|
|
164098
|
-
}
|
|
164099
|
-
},
|
|
164100
|
-
close() {
|
|
164101
|
-
ended = true;
|
|
164102
|
-
wake?.();
|
|
164103
|
-
}
|
|
164104
|
-
};
|
|
164105
|
-
streams.add(sink);
|
|
164106
|
-
const abort = () => sink.close();
|
|
164107
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
164108
|
-
try {
|
|
164109
|
-
if (endpoint === "$events") yield {
|
|
164110
|
-
type: "ready",
|
|
164111
|
-
clientId: crypto.randomUUID(),
|
|
164112
|
-
host: { home: "" }
|
|
164113
|
-
};
|
|
164114
|
-
if (endpoint === "workspace/follow") yield {
|
|
164115
|
-
type: "baseline",
|
|
164116
|
-
value: {
|
|
164117
|
-
items: [],
|
|
164118
|
-
archivedSessionIds: []
|
|
164119
|
-
}
|
|
164120
|
-
};
|
|
164121
|
-
if (endpoint === "session/control") yield {
|
|
164122
|
-
type: "baseline",
|
|
164123
|
-
value: {
|
|
164124
|
-
queues: { [sessionId]: [] },
|
|
164125
|
-
jobs: { [sessionId]: [] },
|
|
164126
|
-
projections: { [sessionId]: projections() }
|
|
164127
|
-
}
|
|
164128
|
-
};
|
|
164129
|
-
if (endpoint === "session/follow") yield {
|
|
164130
|
-
type: "snapshot",
|
|
164131
|
-
header: {
|
|
164132
|
-
version: 3,
|
|
164133
|
-
id: sessionId,
|
|
164134
|
-
createdAt,
|
|
164135
|
-
isSeeded: false
|
|
164136
|
-
},
|
|
164137
|
-
cursor: nextSeq - 1,
|
|
164138
|
-
records: journal.slice(),
|
|
164139
|
-
hasMore: snapshot.hasMore === true,
|
|
164140
|
-
projections: projections(),
|
|
164141
|
-
assistantStream: {
|
|
164142
|
-
revision: assistantRevision,
|
|
164143
|
-
...activeAssistant === void 0 ? {} : { activeAttempt: {
|
|
164144
|
-
...activeAssistant,
|
|
164145
|
-
stream: activeAssistant.stream.slice()
|
|
164146
|
-
} }
|
|
164147
|
-
}
|
|
164148
|
-
};
|
|
164149
|
-
while (!ended) {
|
|
164150
|
-
if (queue.length > 0) {
|
|
164151
|
-
yield queue.shift();
|
|
164152
|
-
continue;
|
|
164153
|
-
}
|
|
164154
|
-
await new Promise((resolve) => {
|
|
164155
|
-
wake = resolve;
|
|
164156
|
-
});
|
|
164157
|
-
wake = void 0;
|
|
164158
|
-
}
|
|
164159
|
-
} finally {
|
|
164160
|
-
streams.delete(sink);
|
|
164161
|
-
signal.removeEventListener("abort", abort);
|
|
164162
|
-
queue.length = 0;
|
|
164163
|
-
}
|
|
164164
|
-
},
|
|
164165
|
-
dispose() {
|
|
164166
|
-
if (disposed) return;
|
|
164167
|
-
disposed = true;
|
|
164168
|
-
for (const stream of streams) stream.close();
|
|
164169
|
-
streams.clear();
|
|
164170
|
-
listeners.clear();
|
|
164171
|
-
journal = [];
|
|
164172
|
-
projected = [];
|
|
164173
|
-
pendingPrompt = void 0;
|
|
164174
|
-
activeAssistant = void 0;
|
|
164175
|
-
}
|
|
164176
|
-
};
|
|
164177
|
-
}
|
|
164178
|
-
//#endregion
|
|
164179
|
-
//#region src/client/arko-native-frame.ts
|
|
164180
|
-
const conversationOnlyLayout = `
|
|
164181
|
-
button[aria-haspopup="listbox"][aria-label="指令"],
|
|
164182
|
-
button[aria-haspopup="listbox"][aria-label="Commands"] {
|
|
164183
|
-
display: none !important;
|
|
164184
|
-
}
|
|
164185
|
-
body div:has(> :first-child > [data-slot="sidebar"]):has(> [data-rightbar-col]) > :first-child,
|
|
164186
|
-
body div:has(> :first-child > [data-slot="sidebar"]):has(> [data-rightbar-col]) > [data-side="sidebar"] {
|
|
164187
|
-
display: none !important;
|
|
164188
|
-
}
|
|
164189
|
-
body div:has(> :first-child > [data-slot="sidebar"]):has(> [data-rightbar-col]) > :nth-child(2) {
|
|
164190
|
-
grid-column: 1 / 3; grid-row: 1;
|
|
164191
|
-
}
|
|
164192
|
-
body div:has(> :first-child > [data-slot="sidebar"]):has(> [data-rightbar-col]) > [data-rightbar-col] {
|
|
164193
|
-
grid-column: 3; grid-row: 1;
|
|
164194
|
-
}
|
|
164195
|
-
`;
|
|
164196
|
-
/** The owning parent installs a per-frame carrier before any native DSH code executes. */
|
|
164197
|
-
function arkoNativeFrameDocument(html, key, origin) {
|
|
164198
|
-
if (!/^[a-zA-Z0-9-]+$/.test(key) || !/<head(?:\s[^>]*)?>/i.test(html)) throw new Error("Arko 原生页面启动配置无效");
|
|
164199
|
-
const base = new URL("/", origin).href.replaceAll("&", "&").replaceAll("\"", """);
|
|
164200
|
-
return html.replace(/<head(?:\s[^>]*)?>/i, (head) => `${head}<base href="${base}"><style data-arkme-arko-layout>${conversationOnlyLayout}</style><script>
|
|
164201
|
-
const carrier = parent.__arkmeArkoNativeFrames?.get(${JSON.stringify(key)});
|
|
164202
|
-
if (!carrier) throw new Error('Arko native carrier unavailable');
|
|
164203
|
-
// Session selection belongs to this document, not the ordinary DSH tab.
|
|
164204
|
-
const storage = globalThis.localStorage;
|
|
164205
|
-
const isolated = new Map();
|
|
164206
|
-
const conversationKey = 'dsh.conversation.' + carrier.sessionId;
|
|
164207
|
-
for (const method of ['getItem', 'setItem', 'removeItem']) {
|
|
164208
|
-
const original = Storage.prototype[method];
|
|
164209
|
-
Storage.prototype[method] = function(key, value) {
|
|
164210
|
-
if (this !== storage || (key !== 'dsh.sessions.current' && key !== conversationKey)) return original.apply(this, arguments);
|
|
164211
|
-
if (method === 'getItem') return isolated.get(key) ?? null;
|
|
164212
|
-
if (method === 'removeItem') isolated.delete(key);
|
|
164213
|
-
else isolated.set(key, String(value));
|
|
164214
|
-
};
|
|
164215
|
-
}
|
|
164216
|
-
globalThis.__DSH_TRANSPORT__ = {
|
|
164217
|
-
async fetch(...args) {
|
|
164218
|
-
const response = await carrier.fetch(...args);
|
|
164219
|
-
return new Response(await response.text(), { status: response.status, headers: { 'content-type': 'application/json' } });
|
|
164220
|
-
},
|
|
164221
|
-
async *openStream(...args) {
|
|
164222
|
-
for await (const value of carrier.openStream(...args)) yield JSON.parse(JSON.stringify(value));
|
|
164223
|
-
},
|
|
164224
|
-
};
|
|
164225
|
-
globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
164226
|
-
<\/script>`);
|
|
164227
|
-
}
|
|
164228
|
-
//#endregion
|
|
164229
|
-
//#region src/client/ArkoNativeSurface.tsx
|
|
164230
|
-
/** This component owns only the native document and its disposable presentation carrier. */
|
|
164231
|
-
function ArkoNativeSurface({ snapshot, actions, ui }) {
|
|
164232
|
-
const latest = (0, react$1.useRef)({
|
|
164233
|
-
snapshot,
|
|
164234
|
-
actions,
|
|
164235
|
-
ui
|
|
164236
|
-
});
|
|
164237
|
-
latest.current = {
|
|
164238
|
-
snapshot,
|
|
164239
|
-
actions,
|
|
164240
|
-
ui
|
|
164241
|
-
};
|
|
164242
|
-
const carrier = (0, react$1.useRef)();
|
|
164243
|
-
const [html, setHtml] = (0, react$1.useState)("");
|
|
164244
|
-
const [error, setError] = (0, react$1.useState)("");
|
|
164245
|
-
const [ready, setReady] = (0, react$1.useState)(false);
|
|
164246
|
-
const [attempt, setAttempt] = (0, react$1.useState)(0);
|
|
164247
|
-
(0, react$1.useLayoutEffect)(() => {
|
|
164248
|
-
const transport = carrier.current;
|
|
164249
|
-
if (!transport || transport.getSnapshot().accountKey !== snapshot.accountKey) return;
|
|
164250
|
-
const revision = transport.historyRevision;
|
|
164251
|
-
transport.ui = ui;
|
|
164252
|
-
transport.update(snapshot, actions);
|
|
164253
|
-
if (transport.historyRevision !== revision) setAttempt((value) => value + 1);
|
|
164254
|
-
}, [
|
|
164255
|
-
snapshot,
|
|
164256
|
-
actions,
|
|
164257
|
-
ui
|
|
164258
|
-
]);
|
|
164259
|
-
(0, react$1.useEffect)(() => {
|
|
164260
|
-
if (snapshot.loading) return;
|
|
164261
|
-
const controller = new AbortController();
|
|
164262
|
-
const key = crypto.randomUUID();
|
|
164263
|
-
const current = latest.current;
|
|
164264
|
-
const transport = Object.assign(createArkoNativeTransport(current.snapshot, current.actions), {
|
|
164265
|
-
ui: current.ui,
|
|
164266
|
-
ready: () => {
|
|
164267
|
-
if (!controller.signal.aborted) {
|
|
164268
|
-
setError("");
|
|
164269
|
-
setReady(true);
|
|
164270
|
-
}
|
|
164271
|
-
}
|
|
164272
|
-
});
|
|
164273
|
-
carrier.current = transport;
|
|
164274
|
-
const frames = window.__arkmeArkoNativeFrames ??= /* @__PURE__ */ new Map();
|
|
164275
|
-
frames.set(key, transport);
|
|
164276
|
-
setError("");
|
|
164277
|
-
setHtml("");
|
|
164278
|
-
setReady(false);
|
|
164279
|
-
fetch("/arkme-self/harness-frame?arkme-arko=1", {
|
|
164280
|
-
signal: controller.signal,
|
|
164281
|
-
credentials: "same-origin"
|
|
164282
|
-
}).then(async (response) => {
|
|
164283
|
-
if (!response.ok) throw new Error(`原生页面加载失败(${response.status})`);
|
|
164284
|
-
const source = await response.text();
|
|
164285
|
-
if (!controller.signal.aborted) setHtml(arkoNativeFrameDocument(source, key, location.origin));
|
|
164286
|
-
}).catch((caught) => {
|
|
164287
|
-
if (!controller.signal.aborted) setError(caught instanceof Error ? caught.message : String(caught));
|
|
164288
|
-
});
|
|
164289
|
-
const deadline = window.setTimeout(() => {
|
|
164290
|
-
if (!controller.signal.aborted) setReady((value) => {
|
|
164291
|
-
if (!value) setError("原生页面启动超时,请重试");
|
|
164292
|
-
return value;
|
|
164293
|
-
});
|
|
164294
|
-
}, 3e4);
|
|
164295
|
-
return () => {
|
|
164296
|
-
controller.abort();
|
|
164297
|
-
clearTimeout(deadline);
|
|
164298
|
-
transport.dispose();
|
|
164299
|
-
frames.delete(key);
|
|
164300
|
-
if (carrier.current === transport) carrier.current = void 0;
|
|
164301
|
-
};
|
|
164302
|
-
}, [
|
|
164303
|
-
snapshot.accountKey,
|
|
164304
|
-
attempt,
|
|
164305
|
-
snapshot.loading
|
|
164306
|
-
]);
|
|
164307
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
164308
|
-
"data-arkme-owned": "arko-native-surface",
|
|
164309
|
-
style: {
|
|
164310
|
-
height: "100%",
|
|
164311
|
-
minHeight: 0,
|
|
164312
|
-
position: "relative",
|
|
164313
|
-
display: "flex",
|
|
164314
|
-
flexDirection: "column"
|
|
164315
|
-
},
|
|
164316
|
-
children: [
|
|
164317
|
-
error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
164318
|
-
role: "alert",
|
|
164319
|
-
children: [error, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
164320
|
-
onClick: () => setAttempt((value) => value + 1),
|
|
164321
|
-
children: "重新加载原生页面"
|
|
164322
|
-
})]
|
|
164323
|
-
}),
|
|
164324
|
-
!ready && !error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
164325
|
-
role: "status",
|
|
164326
|
-
"aria-label": "正在加载 Arko 对话",
|
|
164327
|
-
"data-arko-loading-skeleton": true,
|
|
164328
|
-
style: {
|
|
164329
|
-
position: "absolute",
|
|
164330
|
-
inset: 0,
|
|
164331
|
-
display: "flex",
|
|
164332
|
-
flexDirection: "column",
|
|
164333
|
-
background: arkmeTheme.base
|
|
164334
|
-
},
|
|
164335
|
-
children: [
|
|
164336
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
164337
|
-
style: {
|
|
164338
|
-
display: "flex",
|
|
164339
|
-
alignItems: "center",
|
|
164340
|
-
gap: 10,
|
|
164341
|
-
padding: "16px 24px",
|
|
164342
|
-
borderBottom: `1px solid ${arkmeTheme.border}`
|
|
164343
|
-
},
|
|
164344
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeArkoAvatar, { size: 30 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
164345
|
-
style: { color: arkmeTheme.text },
|
|
164346
|
-
children: snapshot.displayName
|
|
164347
|
-
})]
|
|
164348
|
-
}),
|
|
164349
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
164350
|
-
"aria-hidden": true,
|
|
164351
|
-
style: {
|
|
164352
|
-
flex: 1,
|
|
164353
|
-
width: "min(720px, 86%)",
|
|
164354
|
-
margin: "24px auto",
|
|
164355
|
-
display: "flex",
|
|
164356
|
-
flexDirection: "column",
|
|
164357
|
-
gap: 20
|
|
164358
|
-
},
|
|
164359
|
-
children: [
|
|
164360
|
-
70,
|
|
164361
|
-
45,
|
|
164362
|
-
82
|
|
164363
|
-
].map((width, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
164364
|
-
width: `${width}%`,
|
|
164365
|
-
height: index === 1 ? 40 : 64,
|
|
164366
|
-
alignSelf: index === 1 ? "flex-end" : "flex-start",
|
|
164367
|
-
borderRadius: 12,
|
|
164368
|
-
background: arkmeTheme.hover
|
|
164369
|
-
} }, index))
|
|
164370
|
-
}),
|
|
164371
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
164372
|
-
style: {
|
|
164373
|
-
width: "min(720px, 86%)",
|
|
164374
|
-
margin: "0 auto 24px"
|
|
164375
|
-
},
|
|
164376
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
164377
|
-
"aria-hidden": true,
|
|
164378
|
-
style: {
|
|
164379
|
-
height: 92,
|
|
164380
|
-
border: `1px solid ${arkmeTheme.border}`,
|
|
164381
|
-
borderRadius: 16,
|
|
164382
|
-
background: arkmeTheme.hover
|
|
164383
|
-
}
|
|
164384
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
164385
|
-
style: {
|
|
164386
|
-
textAlign: "center",
|
|
164387
|
-
color: arkmeTheme.secondary,
|
|
164388
|
-
fontSize: 12,
|
|
164389
|
-
paddingTop: 10
|
|
164390
|
-
},
|
|
164391
|
-
children: "正在加载对话…"
|
|
164392
|
-
})]
|
|
164393
|
-
})
|
|
164394
|
-
]
|
|
164395
|
-
}),
|
|
164396
|
-
html && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
|
|
164397
|
-
name: "arkme-arko-native",
|
|
164398
|
-
title: "Arko 原生 DSH 页面",
|
|
164399
|
-
srcDoc: html,
|
|
164400
|
-
style: {
|
|
164401
|
-
border: 0,
|
|
164402
|
-
width: "100%",
|
|
164403
|
-
flex: 1,
|
|
164404
|
-
minHeight: 0,
|
|
164405
|
-
visibility: ready && !error ? "visible" : "hidden"
|
|
164406
|
-
},
|
|
164407
|
-
"aria-hidden": !ready || !!error,
|
|
164408
|
-
allow: "clipboard-read; clipboard-write"
|
|
164409
|
-
})
|
|
164410
|
-
]
|
|
164411
|
-
});
|
|
164412
|
-
}
|
|
164413
|
-
//#endregion
|
|
164414
|
-
//#region src/client/arko-pending-turn-store.ts
|
|
164415
|
-
const STORAGE_KEY_PREFIX = "arkme:arko:pending-turn:v1:";
|
|
164416
|
-
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
164417
|
-
function defaultStorage() {
|
|
164418
|
-
try {
|
|
164419
|
-
return typeof globalThis.sessionStorage === "undefined" ? void 0 : globalThis.sessionStorage;
|
|
164420
|
-
} catch {
|
|
164421
|
-
return;
|
|
164422
|
-
}
|
|
164423
|
-
}
|
|
164424
|
-
function storageKey(userId) {
|
|
164425
|
-
return `${STORAGE_KEY_PREFIX}${String(userId)}`;
|
|
164426
|
-
}
|
|
164427
|
-
function optionalTrimmedString(value) {
|
|
164428
|
-
if (typeof value !== "string") return void 0;
|
|
164429
|
-
const normalized = value.trim();
|
|
164430
|
-
return normalized === "" ? void 0 : normalized;
|
|
164431
|
-
}
|
|
164432
|
-
function isValidArkoPendingTurn(value, expectedUserId) {
|
|
164433
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
164434
|
-
const turn = value;
|
|
164435
|
-
const hasContinuationRun = optionalTrimmedString(turn.replyToRunUid) !== void 0;
|
|
164436
|
-
const hasContinuationMessage = Number.isSafeInteger(turn.replyToAssistantMsgId) && (turn.replyToAssistantMsgId ?? 0) > 0;
|
|
164437
|
-
return Number.isSafeInteger(turn.userId) && (turn.userId ?? 0) > 0 && (expectedUserId === void 0 || turn.userId === expectedUserId) && Number.isSafeInteger(turn.sessionId) && (turn.sessionId ?? 0) > 0 && typeof turn.clientTurnUid === "string" && UUID_PATTERN.test(turn.clientTurnUid) && typeof turn.text === "string" && turn.text.trim() !== "" && Number.isSafeInteger(turn.createdAtMillis) && (turn.createdAtMillis ?? 0) > 0 && optionalTrimmedString(turn.localUserMessageId) !== void 0 && optionalTrimmedString(turn.localAssistantMessageId) !== void 0 && (turn.modelRouteKey === void 0 || optionalTrimmedString(turn.modelRouteKey) !== void 0) && hasContinuationRun === hasContinuationMessage && (!hasContinuationRun || turn.modelRouteKey === void 0);
|
|
164438
|
-
}
|
|
164439
|
-
function readArkoPendingTurn(userId, storage = defaultStorage()) {
|
|
164440
|
-
if (!Number.isSafeInteger(userId) || userId <= 0 || storage === void 0) return void 0;
|
|
164441
|
-
try {
|
|
164442
|
-
const encoded = storage.getItem(storageKey(userId));
|
|
164443
|
-
if (encoded === null) return void 0;
|
|
164444
|
-
const value = JSON.parse(encoded);
|
|
164445
|
-
if (!isValidArkoPendingTurn(value, userId)) {
|
|
164446
|
-
storage.removeItem(storageKey(userId));
|
|
164447
|
-
return;
|
|
164448
|
-
}
|
|
164449
|
-
return value;
|
|
164450
|
-
} catch {
|
|
164451
|
-
return;
|
|
164452
|
-
}
|
|
164453
|
-
}
|
|
164454
|
-
function writeArkoPendingTurn(turn, storage = defaultStorage()) {
|
|
164455
|
-
if (!isValidArkoPendingTurn(turn) || storage === void 0) return false;
|
|
164456
|
-
try {
|
|
164457
|
-
storage.setItem(storageKey(turn.userId), JSON.stringify(turn));
|
|
164458
|
-
return true;
|
|
164459
|
-
} catch {
|
|
164460
|
-
return false;
|
|
164461
|
-
}
|
|
164462
|
-
}
|
|
164463
|
-
function removeArkoPendingTurn(userId, storage = defaultStorage()) {
|
|
164464
|
-
if (!Number.isSafeInteger(userId) || userId <= 0 || storage === void 0) return;
|
|
164465
|
-
try {
|
|
164466
|
-
storage.removeItem(storageKey(userId));
|
|
164467
|
-
} catch {}
|
|
164468
|
-
}
|
|
164469
|
-
//#endregion
|
|
164470
|
-
//#region src/client/useArkoConversationController.ts
|
|
164471
|
-
const arkoQuestionMaxLength = 60 * 1024;
|
|
164472
|
-
const ACTIVE_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
164473
|
-
"accepted",
|
|
164474
|
-
"queued",
|
|
164475
|
-
"running",
|
|
164476
|
-
"stream_timeout",
|
|
164477
|
-
"waiting_tool"
|
|
164478
|
-
]);
|
|
164479
|
-
function errorMessage$8(error) {
|
|
164480
|
-
if (error instanceof ArkmeClientError) return error.body.message;
|
|
164481
|
-
return error instanceof Error ? error.message : String(error);
|
|
164482
|
-
}
|
|
164483
|
-
function isActiveRunStatus(status) {
|
|
164484
|
-
return status !== void 0 && ACTIVE_RUN_STATUSES.has(status);
|
|
164485
|
-
}
|
|
164486
|
-
function isActivityPlaceholderText(value) {
|
|
164487
|
-
return /^(正在)?(思考|处理)(中)?[.。…]*$/.test(value.trim());
|
|
164488
|
-
}
|
|
164489
|
-
function isActiveHistoryRun(item) {
|
|
164490
|
-
const placeholder = isActivityPlaceholderText(item.text);
|
|
164491
|
-
return item.role === "assistant" && (isActiveRunStatus(item.runStatus) || item.runStatus === void 0 && item.status === 2 && (item.text.trim() === "" || placeholder));
|
|
164492
|
-
}
|
|
164493
|
-
function arkoHistoryHasTerminalRun(items, sessionId, assistantMsgId, runUid) {
|
|
164494
|
-
const matchingItem = items.find((item) => item.role === "assistant" && item.sessionId === sessionId && item.messageId === assistantMsgId && (item.runUid === void 0 || item.runUid === runUid));
|
|
164495
|
-
return matchingItem !== void 0 && !isActiveHistoryRun(matchingItem);
|
|
164496
|
-
}
|
|
164497
|
-
function waitForNextPoll(signal, delayMillis = 1200) {
|
|
164498
|
-
return new Promise((resolve) => {
|
|
164499
|
-
if (signal.aborted) {
|
|
164500
|
-
resolve();
|
|
164501
|
-
return;
|
|
164502
|
-
}
|
|
164503
|
-
const finish = () => {
|
|
164504
|
-
clearTimeout(timeout);
|
|
164505
|
-
signal.removeEventListener("abort", finish);
|
|
164506
|
-
resolve();
|
|
164507
|
-
};
|
|
164508
|
-
const timeout = setTimeout(finish, delayMillis);
|
|
164509
|
-
signal.addEventListener("abort", finish, { once: true });
|
|
164510
|
-
});
|
|
164511
|
-
}
|
|
164512
|
-
function historyMessage(item) {
|
|
164513
|
-
const placeholder = isActivityPlaceholderText(item.text);
|
|
164514
|
-
const reasoningPlaceholder = isActivityPlaceholderText(item.reasoning);
|
|
164515
|
-
const active = isActiveHistoryRun(item);
|
|
164516
|
-
return {
|
|
164517
|
-
id: `history:${String(item.messageId)}`,
|
|
164518
|
-
messageId: item.messageId,
|
|
164519
|
-
sessionId: item.sessionId,
|
|
164520
|
-
role: item.role,
|
|
164521
|
-
text: active && placeholder ? "" : item.text,
|
|
164522
|
-
status: active ? "sending" : item.runStatus === "failed" ? "error" : "done",
|
|
164523
|
-
createdAtMillis: item.createdAtMillis,
|
|
164524
|
-
...item.reasoning.trim() === "" || !active && reasoningPlaceholder ? {} : { reasoning: item.reasoning },
|
|
164525
|
-
...item.role !== "assistant" ? {} : { assistantMsgId: item.messageId },
|
|
164526
|
-
...item.runUid === void 0 ? {} : { runUid: item.runUid },
|
|
164527
|
-
...item.runStatus === void 0 ? {} : { runStatus: item.runStatus },
|
|
164528
|
-
...item.messageActionRef === void 0 ? {} : {
|
|
164529
|
-
messageActionRef: item.messageActionRef,
|
|
164530
|
-
...item.messageActionConversationRef === void 0 ? {} : { messageActionConversationRef: item.messageActionConversationRef },
|
|
164531
|
-
copyLinkAvailable: item.messageActionCapabilities?.copyLink === true,
|
|
164532
|
-
forwardAvailable: item.messageActionCapabilities?.forward === true
|
|
164533
|
-
}
|
|
164534
|
-
};
|
|
164535
|
-
}
|
|
164536
|
-
function latestActiveRun(items, sessionId) {
|
|
164537
|
-
const item = items.filter((candidate) => candidate.sessionId === sessionId && candidate.role === "assistant" && candidate.runUid !== void 0 && isActiveRunStatus(candidate.runStatus)).sort((left, right) => right.createdAtMillis - left.createdAtMillis || right.messageId - left.messageId)[0];
|
|
164538
|
-
if (item?.runUid === void 0) return void 0;
|
|
164539
|
-
return {
|
|
164540
|
-
sessionId: item.sessionId,
|
|
164541
|
-
assistantMsgId: item.messageId,
|
|
164542
|
-
runUid: item.runUid
|
|
164543
|
-
};
|
|
164544
|
-
}
|
|
164545
|
-
function mergeHistory(current, items) {
|
|
164546
|
-
const byId = new Map(current.map((item) => [item.id, item]));
|
|
164547
|
-
for (const item of items) {
|
|
164548
|
-
const key = `history:${String(item.messageId)}`;
|
|
164549
|
-
const prior = byId.get(key);
|
|
164550
|
-
byId.set(key, {
|
|
164551
|
-
...historyMessage(item),
|
|
164552
|
-
...prior?.presentationKey ? { presentationKey: prior.presentationKey } : {}
|
|
164553
|
-
});
|
|
164554
|
-
}
|
|
164555
|
-
return [...byId.values()].sort((left, right) => {
|
|
164556
|
-
const leftAt = left.createdAtMillis ?? Number.MAX_SAFE_INTEGER;
|
|
164557
|
-
const rightAt = right.createdAtMillis ?? Number.MAX_SAFE_INTEGER;
|
|
164558
|
-
if (leftAt !== rightAt) return leftAt - rightAt;
|
|
164559
|
-
return (left.messageId ?? Number.MAX_SAFE_INTEGER) - (right.messageId ?? Number.MAX_SAFE_INTEGER);
|
|
164560
|
-
});
|
|
164561
|
-
}
|
|
164562
|
-
function resultText(result) {
|
|
164563
|
-
if (result.text.trim() !== "") return result.text.trim();
|
|
164564
|
-
if (result.errorMessage?.trim()) return result.errorMessage.trim();
|
|
164565
|
-
if (isActiveRunStatus(result.run?.status ?? result.status)) return "";
|
|
164566
|
-
return "任务已处理。";
|
|
164567
|
-
}
|
|
164568
|
-
function latestContinuation(messages, sessionId) {
|
|
164569
|
-
if (sessionId === void 0) return void 0;
|
|
164570
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
164571
|
-
const message = messages[index];
|
|
164572
|
-
if (message === void 0) continue;
|
|
164573
|
-
if (message.role === "divider") return void 0;
|
|
164574
|
-
if (message.sessionId !== sessionId) continue;
|
|
164575
|
-
if (message.role === "user") return void 0;
|
|
164576
|
-
if (message.runStatus !== "waiting_user" || message.runUid === void 0 || message.assistantMsgId === void 0) return;
|
|
164577
|
-
return {
|
|
164578
|
-
runUid: message.runUid,
|
|
164579
|
-
assistantMsgId: message.assistantMsgId
|
|
164580
|
-
};
|
|
164581
|
-
}
|
|
164582
|
-
}
|
|
164583
|
-
function selectedModelName(catalog) {
|
|
164584
|
-
return catalog?.options.find((option) => option.routeKey === catalog.effectiveRouteKey)?.displayName ?? "模型目录暂不可用";
|
|
164585
|
-
}
|
|
164586
|
-
function useArkoConversationController() {
|
|
164587
|
-
const alive = (0, react$1.useRef)(true);
|
|
164588
|
-
(0, react$1.useEffect)(() => {
|
|
164589
|
-
alive.current = true;
|
|
164590
|
-
return () => {
|
|
164591
|
-
alive.current = false;
|
|
164592
|
-
};
|
|
164593
|
-
}, []);
|
|
164594
|
-
useArkmeLocale();
|
|
164595
|
-
const historyLoadInFlightRef = (0, react$1.useRef)(false);
|
|
164596
|
-
const sendInFlightRef = (0, react$1.useRef)(false);
|
|
164597
|
-
const authSnapshot = (0, react$1.useSyncExternalStore)(arkmeAuthStore.subscribe, arkmeAuthStore.getSnapshot, arkmeAuthStore.getSnapshot);
|
|
164598
|
-
const profileSnapshot = (0, react$1.useSyncExternalStore)(arkmeArkoProfileStore.subscribe, arkmeArkoProfileStore.getSnapshot, arkmeArkoProfileStore.getSnapshot);
|
|
164599
|
-
const profileUserId = authSnapshot.auth?.status === "authenticated" ? authSnapshot.auth.userId : void 0;
|
|
164600
|
-
const composerDraftKey = arkmeArkoComposerDraftKey(profileUserId);
|
|
164601
|
-
(0, react$1.useSyncExternalStore)(arkmeComposerDraftStore.subscribe, arkmeComposerDraftStore.getRevision, arkmeComposerDraftStore.getRevision);
|
|
164602
|
-
const draftSnapshot = arkmeComposerDraftStore.get(composerDraftKey);
|
|
164603
|
-
const draft = draftSnapshot.text;
|
|
164604
|
-
const accountKey = authSnapshot.auth?.status === "authenticated" && profileUserId !== void 0 ? `${authSnapshot.auth.environment}:${String(profileUserId)}` : void 0;
|
|
164605
|
-
const profile = profileSnapshot.userId === profileUserId ? profileSnapshot.profile : void 0;
|
|
164606
|
-
const [userProfile, setUserProfile] = (0, react$1.useState)(null);
|
|
164607
|
-
const [session, setSession] = (0, react$1.useState)();
|
|
164608
|
-
const [catalog, setCatalog] = (0, react$1.useState)();
|
|
164609
|
-
const [messages, setMessages] = (0, react$1.useState)([]);
|
|
164610
|
-
const [historyOffset, setHistoryOffset] = (0, react$1.useState)(null);
|
|
164611
|
-
const [historyError, setHistoryError] = (0, react$1.useState)("");
|
|
164612
|
-
const [historyPageError, setHistoryPageError] = (0, react$1.useState)("");
|
|
164613
|
-
const historyPageAbort = (0, react$1.useRef)();
|
|
164614
|
-
(0, react$1.useEffect)(() => () => {
|
|
164615
|
-
historyPageAbort.current?.abort();
|
|
164616
|
-
}, [accountKey]);
|
|
164617
|
-
const [loading, setLoading] = (0, react$1.useState)(true);
|
|
164618
|
-
const [historyLoading, setHistoryLoading] = (0, react$1.useState)(false);
|
|
164619
|
-
const [sending, setSending] = (0, react$1.useState)(false);
|
|
164620
|
-
const [clearing, setClearing] = (0, react$1.useState)(false);
|
|
164621
|
-
const clearInFlightRef = (0, react$1.useRef)(false);
|
|
164622
|
-
const [selectingModel, setSelectingModel] = (0, react$1.useState)(false);
|
|
164623
|
-
const modelSelectionInFlightRef = (0, react$1.useRef)(false);
|
|
164624
|
-
const [cancelling, setCancelling] = (0, react$1.useState)(false);
|
|
164625
|
-
const [error, setError] = (0, react$1.useState)("");
|
|
164626
|
-
const [notice, setNotice] = (0, react$1.useState)("");
|
|
164627
|
-
const [activeRun, setActiveRun] = (0, react$1.useState)();
|
|
164628
|
-
const [pendingTurn, setPendingTurn] = (0, react$1.useState)();
|
|
164629
|
-
(0, react$1.useEffect)(() => {
|
|
164630
|
-
arkmeArkoProfileStore.activateUser(profileUserId);
|
|
164631
|
-
arkmeArkoConversationPreviewStore.activateUser(profileUserId);
|
|
164632
|
-
}, [profileUserId]);
|
|
164633
|
-
(0, react$1.useEffect)(() => {
|
|
164634
|
-
if (profileUserId === void 0) return;
|
|
164635
|
-
arkmeArkoConversationPreviewStore.setLatestFromSurface(profileUserId, messages.filter((message) => message.role !== "divider").map((message) => ({
|
|
164636
|
-
key: message.id,
|
|
164637
|
-
text: message.text,
|
|
164638
|
-
...message.messageId === void 0 ? {} : { messageId: message.messageId },
|
|
164639
|
-
...message.createdAtMillis === void 0 ? {} : { createdAtMillis: message.createdAtMillis }
|
|
164640
|
-
})));
|
|
164641
|
-
}, [messages, profileUserId]);
|
|
164642
|
-
(0, react$1.useEffect)(() => {
|
|
164643
|
-
if (profileUserId === void 0) {
|
|
164644
|
-
setPendingTurn(void 0);
|
|
164645
|
-
return;
|
|
164646
|
-
}
|
|
164647
|
-
const restored = readArkoPendingTurn(profileUserId);
|
|
164648
|
-
setPendingTurn(restored);
|
|
164649
|
-
if (restored === void 0) return;
|
|
164650
|
-
setMessages((current) => {
|
|
164651
|
-
if (current.some((item) => item.id === restored.localAssistantMessageId)) return current;
|
|
164652
|
-
return [
|
|
164653
|
-
...current,
|
|
164654
|
-
{
|
|
164655
|
-
id: restored.localUserMessageId,
|
|
164656
|
-
presentationKey: restored.localUserMessageId,
|
|
164657
|
-
sessionId: restored.sessionId,
|
|
164658
|
-
role: "user",
|
|
164659
|
-
text: restored.text,
|
|
164660
|
-
status: "done",
|
|
164661
|
-
createdAtMillis: restored.createdAtMillis
|
|
164662
|
-
},
|
|
164663
|
-
{
|
|
164664
|
-
id: restored.localAssistantMessageId,
|
|
164665
|
-
presentationKey: restored.localAssistantMessageId,
|
|
164666
|
-
sessionId: restored.sessionId,
|
|
164667
|
-
role: "assistant",
|
|
164668
|
-
text: "",
|
|
164669
|
-
status: "error",
|
|
164670
|
-
createdAtMillis: restored.createdAtMillis + 1
|
|
164671
|
-
}
|
|
164672
|
-
];
|
|
164673
|
-
});
|
|
164674
|
-
}, [profileUserId]);
|
|
164675
|
-
(0, react$1.useEffect)(() => {
|
|
164676
|
-
const controller = new AbortController();
|
|
164677
|
-
setLoading(true);
|
|
164678
|
-
setError("");
|
|
164679
|
-
setHistoryError("");
|
|
164680
|
-
Promise.allSettled([
|
|
164681
|
-
callArkme("arko.session", void 0, controller.signal),
|
|
164682
|
-
callArkme("arko.profile", void 0, controller.signal),
|
|
164683
|
-
callArkme("arko.models", void 0, controller.signal),
|
|
164684
|
-
callArkme("arko.history", {
|
|
164685
|
-
limit: 50,
|
|
164686
|
-
offset: 0
|
|
164687
|
-
}, controller.signal),
|
|
164688
|
-
callArkme("user.profile", void 0, controller.signal).then(async (snapshot) => snapshot.profile === null ? await callArkme("user.profile.refresh", void 0, controller.signal) : snapshot)
|
|
164689
|
-
]).then(([sessionResult, profileResult, modelResult, historyResult, userProfileResult]) => {
|
|
164690
|
-
if (controller.signal.aborted) return;
|
|
164691
|
-
if (sessionResult.status === "rejected") {
|
|
164692
|
-
setError(errorMessage$8(sessionResult.reason));
|
|
164693
|
-
return;
|
|
164694
|
-
}
|
|
164695
|
-
setSession(sessionResult.value);
|
|
164696
|
-
if (profileResult.status === "fulfilled" && profileUserId !== void 0) arkmeArkoProfileStore.setProfile(profileUserId, profileResult.value);
|
|
164697
|
-
if (modelResult.status === "fulfilled") setCatalog(modelResult.value);
|
|
164698
|
-
if (userProfileResult.status === "fulfilled") setUserProfile(userProfileResult.value.profile);
|
|
164699
|
-
if (historyResult.status === "fulfilled") {
|
|
164700
|
-
setMessages((current) => mergeHistory(current, historyResult.value.items));
|
|
164701
|
-
setHistoryOffset(historyResult.value.nextOffset);
|
|
164702
|
-
const restoredRun = latestActiveRun(historyResult.value.items, sessionResult.value.sessionId);
|
|
164703
|
-
if (restoredRun !== void 0) {
|
|
164704
|
-
setActiveRun(restoredRun);
|
|
164705
|
-
setSending(true);
|
|
164706
|
-
}
|
|
164707
|
-
} else setHistoryError(tr$1("加载 Arko 对话记录失败:{v0}", { v0: errorMessage$8(historyResult.reason) }));
|
|
164708
|
-
}).finally(() => {
|
|
164709
|
-
if (!controller.signal.aborted) setLoading(false);
|
|
164710
|
-
});
|
|
164711
|
-
return () => {
|
|
164712
|
-
controller.abort();
|
|
164713
|
-
};
|
|
164714
|
-
}, [profileUserId]);
|
|
164715
|
-
(0, react$1.useEffect)(() => {
|
|
164716
|
-
if (activeRun === void 0) return;
|
|
164717
|
-
const controller = new AbortController();
|
|
164718
|
-
let consecutiveFailures = 0;
|
|
164719
|
-
const finishRun = async (knownHistory) => {
|
|
164720
|
-
const [historyResult, profileResult] = await Promise.allSettled([knownHistory === void 0 ? callArkme("arko.history", {
|
|
164721
|
-
limit: 50,
|
|
164722
|
-
offset: 0
|
|
164723
|
-
}, controller.signal) : Promise.resolve(knownHistory), callArkme("arko.profile", void 0, controller.signal)]);
|
|
164724
|
-
if (controller.signal.aborted) return;
|
|
164725
|
-
if (historyResult.status === "fulfilled") {
|
|
164726
|
-
setMessages((current) => mergeHistory(current, historyResult.value.items));
|
|
164727
|
-
setHistoryOffset((current) => current === null ? historyResult.value.nextOffset : current);
|
|
164728
|
-
setHistoryError("");
|
|
164729
|
-
} else setHistoryError(tr$1("刷新 Arko 对话记录失败:{v0}", { v0: errorMessage$8(historyResult.reason) }));
|
|
164730
|
-
if (profileResult.status === "fulfilled" && profileUserId !== void 0) arkmeArkoProfileStore.setProfile(profileUserId, profileResult.value);
|
|
164731
|
-
setActiveRun((current) => current?.runUid === activeRun.runUid ? void 0 : current);
|
|
164732
|
-
setSending(false);
|
|
164733
|
-
};
|
|
164734
|
-
const poll = async () => {
|
|
164735
|
-
await waitForNextPoll(controller.signal);
|
|
164736
|
-
while (!controller.signal.aborted) {
|
|
164737
|
-
try {
|
|
164738
|
-
const status = await callArkme("arko.run.status", {
|
|
164739
|
-
sessionId: activeRun.sessionId,
|
|
164740
|
-
runUid: activeRun.runUid
|
|
164741
|
-
}, controller.signal);
|
|
164742
|
-
if (controller.signal.aborted) return;
|
|
164743
|
-
consecutiveFailures = 0;
|
|
164744
|
-
if (status.status === "waiting_tool") setNotice("当前任务需要 DSH 尚未支持的客户端操作,可以停止任务后换一种方式重试");
|
|
164745
|
-
setMessages((current) => current.map((item) => item.assistantMsgId === activeRun.assistantMsgId ? {
|
|
164746
|
-
...item,
|
|
164747
|
-
runStatus: status.status,
|
|
164748
|
-
status: isActiveRunStatus(status.status) ? "sending" : status.status === "failed" ? "error" : "done"
|
|
164749
|
-
} : item));
|
|
164750
|
-
if (!isActiveRunStatus(status.status)) {
|
|
164751
|
-
await finishRun();
|
|
164752
|
-
return;
|
|
164753
|
-
}
|
|
164754
|
-
} catch {
|
|
164755
|
-
if (controller.signal.aborted) return;
|
|
164756
|
-
consecutiveFailures += 1;
|
|
164757
|
-
try {
|
|
164758
|
-
const history = await callArkme("arko.history", {
|
|
164759
|
-
limit: 50,
|
|
164760
|
-
offset: 0
|
|
164761
|
-
}, controller.signal);
|
|
164762
|
-
if (controller.signal.aborted) return;
|
|
164763
|
-
if (arkoHistoryHasTerminalRun(history.items, activeRun.sessionId, activeRun.assistantMsgId, activeRun.runUid)) {
|
|
164764
|
-
await finishRun(history);
|
|
164765
|
-
return;
|
|
164766
|
-
}
|
|
164767
|
-
} catch {
|
|
164768
|
-
if (controller.signal.aborted) return;
|
|
164769
|
-
}
|
|
164770
|
-
}
|
|
164771
|
-
const retryDelay = consecutiveFailures === 0 ? 1200 : Math.min(1e4, 1200 * 2 ** Math.min(consecutiveFailures - 1, 3));
|
|
164772
|
-
await waitForNextPoll(controller.signal, retryDelay);
|
|
164773
|
-
}
|
|
164774
|
-
};
|
|
164775
|
-
poll();
|
|
164776
|
-
return () => {
|
|
164777
|
-
controller.abort();
|
|
164778
|
-
};
|
|
164779
|
-
}, [activeRun, profileUserId]);
|
|
164780
|
-
const loadEarlier = (0, react$1.useCallback)(async () => {
|
|
164781
|
-
const offset = historyOffset;
|
|
164782
|
-
if (typeof offset !== "number") return {
|
|
164783
|
-
messages: [],
|
|
164784
|
-
hasMore: false
|
|
164785
|
-
};
|
|
164786
|
-
if (historyLoadInFlightRef.current) throw new Error("正在加载更早记录");
|
|
164787
|
-
const controller = new AbortController();
|
|
164788
|
-
historyPageAbort.current = controller;
|
|
164789
|
-
historyLoadInFlightRef.current = true;
|
|
164790
|
-
setHistoryPageError("");
|
|
164791
|
-
setHistoryLoading(true);
|
|
164792
|
-
try {
|
|
164793
|
-
const page = await callArkme("arko.history", {
|
|
164794
|
-
limit: 50,
|
|
164795
|
-
offset
|
|
164796
|
-
}, controller.signal);
|
|
164797
|
-
if (controller.signal.aborted) throw new Error("Arko 历史读取已取消");
|
|
164798
|
-
if (page.hasMore && (page.nextOffset === void 0 || page.nextOffset <= offset)) throw new Error("历史分页未前进,请重试");
|
|
164799
|
-
setMessages((current) => {
|
|
164800
|
-
const ids = new Set(current.map((item) => item.messageId));
|
|
164801
|
-
return [...page.items.filter((item) => {
|
|
164802
|
-
if (ids.has(item.messageId)) return false;
|
|
164803
|
-
ids.add(item.messageId);
|
|
164804
|
-
return true;
|
|
164805
|
-
}).reverse().map(historyMessage), ...current];
|
|
164806
|
-
});
|
|
164807
|
-
setHistoryOffset(page.nextOffset);
|
|
164808
|
-
return {
|
|
164809
|
-
messages: [...page.items].reverse().map(historyMessage),
|
|
164810
|
-
hasMore: page.hasMore
|
|
164811
|
-
};
|
|
164812
|
-
} catch (caught) {
|
|
164813
|
-
if (!controller.signal.aborted) setHistoryPageError(`加载更早记录失败:${errorMessage$8(caught)}。请重试。`);
|
|
164814
|
-
throw caught;
|
|
164815
|
-
} finally {
|
|
164816
|
-
if (historyPageAbort.current === controller) {
|
|
164817
|
-
historyLoadInFlightRef.current = false;
|
|
164818
|
-
setHistoryLoading(false);
|
|
164819
|
-
historyPageAbort.current = void 0;
|
|
164820
|
-
}
|
|
164821
|
-
}
|
|
164822
|
-
}, [historyOffset]);
|
|
164823
|
-
const retryHistory = (0, react$1.useCallback)(async () => {
|
|
164824
|
-
if (historyLoadInFlightRef.current) return;
|
|
164825
|
-
const controller = new AbortController();
|
|
164826
|
-
historyPageAbort.current = controller;
|
|
164827
|
-
historyLoadInFlightRef.current = true;
|
|
164828
|
-
setHistoryLoading(true);
|
|
164829
|
-
setHistoryError("");
|
|
164830
|
-
try {
|
|
164831
|
-
const page = await callArkme("arko.history", {
|
|
164832
|
-
limit: 50,
|
|
164833
|
-
offset: 0
|
|
164834
|
-
}, controller.signal);
|
|
164835
|
-
if (controller.signal.aborted) return;
|
|
164836
|
-
setMessages((current) => mergeHistory(current, page.items));
|
|
164837
|
-
setHistoryOffset((current) => current === null ? page.nextOffset : current);
|
|
164838
|
-
if (session !== void 0) {
|
|
164839
|
-
const restoredRun = latestActiveRun(page.items, session.sessionId);
|
|
164840
|
-
if (restoredRun !== void 0) {
|
|
164841
|
-
setActiveRun(restoredRun);
|
|
164842
|
-
setSending(true);
|
|
164843
|
-
}
|
|
164844
|
-
}
|
|
164845
|
-
} catch (caught) {
|
|
164846
|
-
if (!controller.signal.aborted) setHistoryError(tr$1("加载 Arko 对话记录失败:{v0}", { v0: errorMessage$8(caught) }));
|
|
164847
|
-
} finally {
|
|
164848
|
-
if (historyPageAbort.current === controller) {
|
|
164849
|
-
historyLoadInFlightRef.current = false;
|
|
164850
|
-
historyPageAbort.current = void 0;
|
|
164851
|
-
setHistoryLoading(false);
|
|
164852
|
-
}
|
|
164853
|
-
}
|
|
164854
|
-
}, [session]);
|
|
164855
|
-
const submitTurn = (0, react$1.useCallback)(async (turn) => {
|
|
164856
|
-
if (sendInFlightRef.current || sending || activeRun !== void 0) return false;
|
|
164857
|
-
sendInFlightRef.current = true;
|
|
164858
|
-
let handedOffToPolling = false;
|
|
164859
|
-
setSending(true);
|
|
164860
|
-
setError("");
|
|
164861
|
-
setNotice("");
|
|
164862
|
-
setMessages((current) => current.map((item) => item.id === turn.localAssistantMessageId ? {
|
|
164863
|
-
...item,
|
|
164864
|
-
text: "",
|
|
164865
|
-
status: "sending",
|
|
164866
|
-
runStatus: "accepted"
|
|
164867
|
-
} : item));
|
|
164868
|
-
try {
|
|
164869
|
-
const result = await callArkme("arko.ask", {
|
|
164870
|
-
text: turn.text,
|
|
164871
|
-
sessionId: turn.sessionId,
|
|
164872
|
-
clientTurnUid: turn.clientTurnUid,
|
|
164873
|
-
waitSeconds: 1,
|
|
164874
|
-
...turn.modelRouteKey === void 0 ? {} : { modelRouteKey: turn.modelRouteKey },
|
|
164875
|
-
...turn.replyToRunUid === void 0 ? {} : { replyToRunUid: turn.replyToRunUid },
|
|
164876
|
-
...turn.replyToAssistantMsgId === void 0 ? {} : { replyToAssistantMsgId: turn.replyToAssistantMsgId }
|
|
164877
|
-
});
|
|
164878
|
-
if (!alive.current) return false;
|
|
164879
|
-
removeArkoPendingTurn(turn.userId);
|
|
164880
|
-
setPendingTurn((current) => current?.clientTurnUid === turn.clientTurnUid ? void 0 : current);
|
|
164881
|
-
setSession((current) => current === void 0 ? current : {
|
|
164882
|
-
...current,
|
|
164883
|
-
sessionId: result.sessionId
|
|
164884
|
-
});
|
|
164885
|
-
if (result.profile !== void 0 && profileUserId !== void 0) arkmeArkoProfileStore.setProfile(profileUserId, result.profile);
|
|
164886
|
-
const runStatus = result.run?.status ?? result.status;
|
|
164887
|
-
const runActive = isActiveRunStatus(runStatus);
|
|
164888
|
-
const hasVisibleReasoning = result.reasoning.trim() !== "" && (runActive || !isActivityPlaceholderText(result.reasoning));
|
|
164889
|
-
setMessages((current) => mergeHistory(current.map((item) => item.id === turn.localUserMessageId ? {
|
|
164890
|
-
...item,
|
|
164891
|
-
id: `history:${String(result.userMsgId)}`,
|
|
164892
|
-
messageId: result.userMsgId,
|
|
164893
|
-
sessionId: result.sessionId
|
|
164894
|
-
} : item.id === turn.localAssistantMessageId ? {
|
|
164895
|
-
id: `history:${String(result.assistantMsgId)}`,
|
|
164896
|
-
presentationKey: item.presentationKey ?? item.id,
|
|
164897
|
-
messageId: result.assistantMsgId,
|
|
164898
|
-
sessionId: result.sessionId,
|
|
164899
|
-
role: "assistant",
|
|
164900
|
-
text: resultText(result),
|
|
164901
|
-
status: runActive ? "sending" : result.errorMessage === void 0 ? "done" : "error",
|
|
164902
|
-
assistantMsgId: result.assistantMsgId,
|
|
164903
|
-
...item.createdAtMillis === void 0 ? {} : { createdAtMillis: item.createdAtMillis },
|
|
164904
|
-
...hasVisibleReasoning ? { reasoning: result.reasoning } : {},
|
|
164905
|
-
...result.runUid === void 0 ? {} : { runUid: result.runUid },
|
|
164906
|
-
runStatus
|
|
164907
|
-
} : item), []));
|
|
164908
|
-
if (runActive && result.runUid !== void 0) {
|
|
164909
|
-
handedOffToPolling = true;
|
|
164910
|
-
setActiveRun({
|
|
164911
|
-
sessionId: result.sessionId,
|
|
164912
|
-
assistantMsgId: result.assistantMsgId,
|
|
164913
|
-
runUid: result.runUid
|
|
164914
|
-
});
|
|
164915
|
-
}
|
|
164916
|
-
return true;
|
|
164917
|
-
} catch (caught) {
|
|
164918
|
-
if (!alive.current) return false;
|
|
164919
|
-
const message = errorMessage$8(caught);
|
|
164920
|
-
if (!(caught instanceof ArkmeClientError) || caught.body.retryable) {
|
|
164921
|
-
setPendingTurn(turn);
|
|
164922
|
-
writeArkoPendingTurn(turn);
|
|
164923
|
-
setError(`Arko 发送结果暂未确认:${message}。请重试确认,系统会复用同一次请求,不会重复执行。`);
|
|
164924
|
-
setMessages((current) => current.map((item) => item.id === turn.localAssistantMessageId ? {
|
|
164925
|
-
...item,
|
|
164926
|
-
role: "assistant",
|
|
164927
|
-
text: "",
|
|
164928
|
-
status: "error"
|
|
164929
|
-
} : item));
|
|
164930
|
-
} else {
|
|
164931
|
-
removeArkoPendingTurn(turn.userId);
|
|
164932
|
-
setPendingTurn((current) => current?.clientTurnUid === turn.clientTurnUid ? void 0 : current);
|
|
164933
|
-
setError(message);
|
|
164934
|
-
setMessages((current) => current.map((item) => item.id === turn.localAssistantMessageId ? {
|
|
164935
|
-
...item,
|
|
164936
|
-
role: "assistant",
|
|
164937
|
-
text: message,
|
|
164938
|
-
status: "error"
|
|
164939
|
-
} : item));
|
|
164940
|
-
}
|
|
164941
|
-
return false;
|
|
164942
|
-
} finally {
|
|
164943
|
-
sendInFlightRef.current = false;
|
|
164944
|
-
if (!handedOffToPolling) setSending(false);
|
|
164945
|
-
}
|
|
164946
|
-
}, [
|
|
164947
|
-
activeRun,
|
|
164948
|
-
composerDraftKey,
|
|
164949
|
-
profileUserId,
|
|
164950
|
-
sending
|
|
164951
|
-
]);
|
|
164952
|
-
const interactionLocked = sending || pendingTurn !== void 0 || activeRun !== void 0;
|
|
164953
|
-
const sendDisabled = loading || interactionLocked || clearing || selectingModel || session === void 0 || profileUserId === void 0;
|
|
164954
|
-
const inputDisabled = loading || interactionLocked || session === void 0 || profileUserId === void 0;
|
|
164955
|
-
const send = (0, react$1.useCallback)(async (presetText) => {
|
|
164956
|
-
const text = (presetText ?? serializeArkmeComposerDraft(arkmeComposerDraftStore.get(composerDraftKey)).text).trim();
|
|
164957
|
-
if (text === "" || sendInFlightRef.current || modelSelectionInFlightRef.current || clearInFlightRef.current || sendDisabled || session === void 0 || profileUserId === void 0 || composerDraftKey === void 0) return false;
|
|
164958
|
-
if (text.length > 61440) {
|
|
164959
|
-
setError("内容长度超过上限,请删减后再发送");
|
|
164960
|
-
return false;
|
|
164961
|
-
}
|
|
164962
|
-
const continuation = latestContinuation(messages, session.sessionId);
|
|
164963
|
-
const createdAtMillis = Date.now();
|
|
164964
|
-
const turn = {
|
|
164965
|
-
userId: profileUserId,
|
|
164966
|
-
sessionId: session.sessionId,
|
|
164967
|
-
clientTurnUid: crypto.randomUUID(),
|
|
164968
|
-
text,
|
|
164969
|
-
createdAtMillis,
|
|
164970
|
-
localUserMessageId: crypto.randomUUID(),
|
|
164971
|
-
localAssistantMessageId: crypto.randomUUID(),
|
|
164972
|
-
...continuation === void 0 ? { ...catalog === void 0 ? {} : { modelRouteKey: catalog.effectiveRouteKey } } : {
|
|
164973
|
-
replyToRunUid: continuation.runUid,
|
|
164974
|
-
replyToAssistantMsgId: continuation.assistantMsgId
|
|
164975
|
-
}
|
|
164976
|
-
};
|
|
164977
|
-
writeArkoPendingTurn(turn);
|
|
164978
|
-
setPendingTurn(turn);
|
|
164979
|
-
if (presetText === void 0) arkmeComposerDraftStore.clear(composerDraftKey);
|
|
164980
|
-
setMessages((current) => [
|
|
164981
|
-
...current,
|
|
164982
|
-
{
|
|
164983
|
-
id: turn.localUserMessageId,
|
|
164984
|
-
presentationKey: turn.localUserMessageId,
|
|
164985
|
-
sessionId: turn.sessionId,
|
|
164986
|
-
role: "user",
|
|
164987
|
-
text,
|
|
164988
|
-
status: "done",
|
|
164989
|
-
createdAtMillis
|
|
164990
|
-
},
|
|
164991
|
-
{
|
|
164992
|
-
id: turn.localAssistantMessageId,
|
|
164993
|
-
presentationKey: turn.localAssistantMessageId,
|
|
164994
|
-
sessionId: turn.sessionId,
|
|
164995
|
-
role: "assistant",
|
|
164996
|
-
text: "",
|
|
164997
|
-
status: "sending",
|
|
164998
|
-
runStatus: "accepted",
|
|
164999
|
-
createdAtMillis: createdAtMillis + 1
|
|
165000
|
-
}
|
|
165001
|
-
]);
|
|
165002
|
-
return await submitTurn(turn);
|
|
165003
|
-
}, [
|
|
165004
|
-
catalog,
|
|
165005
|
-
composerDraftKey,
|
|
165006
|
-
messages,
|
|
165007
|
-
profileUserId,
|
|
165008
|
-
sendDisabled,
|
|
165009
|
-
session,
|
|
165010
|
-
submitTurn
|
|
165011
|
-
]);
|
|
165012
|
-
const selectModel = (0, react$1.useCallback)(async (routeKey) => {
|
|
165013
|
-
if (modelSelectionInFlightRef.current || sendInFlightRef.current || clearInFlightRef.current || loading || interactionLocked || clearing || catalog === void 0 || routeKey === catalog.effectiveRouteKey || !catalog.options.some((option) => option.routeKey === routeKey)) return false;
|
|
165014
|
-
modelSelectionInFlightRef.current = true;
|
|
165015
|
-
setSelectingModel(true);
|
|
165016
|
-
setError("");
|
|
165017
|
-
try {
|
|
165018
|
-
const next = await callArkme("arko.model.activate", { routeKey });
|
|
165019
|
-
if (!alive.current) return false;
|
|
165020
|
-
setCatalog(next);
|
|
165021
|
-
return true;
|
|
165022
|
-
} catch (caught) {
|
|
165023
|
-
setError(errorMessage$8(caught));
|
|
165024
|
-
return false;
|
|
165025
|
-
} finally {
|
|
165026
|
-
modelSelectionInFlightRef.current = false;
|
|
165027
|
-
setSelectingModel(false);
|
|
165028
|
-
}
|
|
165029
|
-
}, [
|
|
165030
|
-
catalog,
|
|
165031
|
-
clearing,
|
|
165032
|
-
interactionLocked,
|
|
165033
|
-
loading
|
|
165034
|
-
]);
|
|
165035
|
-
const cancelActiveRun = (0, react$1.useCallback)(async () => {
|
|
165036
|
-
if (activeRun === void 0 || cancelling) return false;
|
|
165037
|
-
setCancelling(true);
|
|
165038
|
-
setError("");
|
|
165039
|
-
try {
|
|
165040
|
-
await callArkme("arko.cancel", {
|
|
165041
|
-
sessionId: activeRun.sessionId,
|
|
165042
|
-
assistantMsgId: activeRun.assistantMsgId,
|
|
165043
|
-
runUid: activeRun.runUid
|
|
165044
|
-
});
|
|
165045
|
-
setNotice("已请求停止当前任务,正在确认最终状态");
|
|
165046
|
-
return true;
|
|
165047
|
-
} catch (caught) {
|
|
165048
|
-
setError(tr$1("停止 Arko 任务失败:{v0}", { v0: errorMessage$8(caught) }));
|
|
165049
|
-
return false;
|
|
165050
|
-
} finally {
|
|
165051
|
-
setCancelling(false);
|
|
165052
|
-
}
|
|
165053
|
-
}, [activeRun, cancelling]);
|
|
165054
|
-
const clearContext = (0, react$1.useCallback)(async () => {
|
|
165055
|
-
if (clearInFlightRef.current || sendInFlightRef.current || modelSelectionInFlightRef.current || loading || interactionLocked || clearing) return;
|
|
165056
|
-
clearInFlightRef.current = true;
|
|
165057
|
-
setClearing(true);
|
|
165058
|
-
setError("");
|
|
165059
|
-
setNotice("");
|
|
165060
|
-
try {
|
|
165061
|
-
const nextSession = await callArkme("arko.new-session");
|
|
165062
|
-
if (!alive.current) return;
|
|
165063
|
-
setSession(nextSession);
|
|
165064
|
-
setMessages((current) => [...current, {
|
|
165065
|
-
id: crypto.randomUUID(),
|
|
165066
|
-
role: "divider",
|
|
165067
|
-
text: "新的对话",
|
|
165068
|
-
status: "done",
|
|
165069
|
-
createdAtMillis: Date.now()
|
|
165070
|
-
}]);
|
|
165071
|
-
setNotice("上下文已清除,历史记录仍然保留");
|
|
165072
|
-
} catch (caught) {
|
|
165073
|
-
setError(errorMessage$8(caught));
|
|
165074
|
-
} finally {
|
|
165075
|
-
clearInFlightRef.current = false;
|
|
165076
|
-
setClearing(false);
|
|
165077
|
-
}
|
|
165078
|
-
}, [
|
|
165079
|
-
clearing,
|
|
165080
|
-
interactionLocked,
|
|
165081
|
-
loading
|
|
165082
|
-
]);
|
|
165083
|
-
return {
|
|
165084
|
-
accountKey,
|
|
165085
|
-
profileUserId,
|
|
165086
|
-
composerDraftKey,
|
|
165087
|
-
draftSnapshot,
|
|
165088
|
-
draft,
|
|
165089
|
-
userProfile,
|
|
165090
|
-
session,
|
|
165091
|
-
catalog,
|
|
165092
|
-
messages,
|
|
165093
|
-
historyOffset,
|
|
165094
|
-
historyError,
|
|
165095
|
-
historyPageError,
|
|
165096
|
-
loading,
|
|
165097
|
-
historyLoading,
|
|
165098
|
-
sending,
|
|
165099
|
-
clearing,
|
|
165100
|
-
selectingModel,
|
|
165101
|
-
cancelling,
|
|
165102
|
-
error,
|
|
165103
|
-
notice,
|
|
165104
|
-
activeRun,
|
|
165105
|
-
pendingTurn,
|
|
165106
|
-
interactionLocked,
|
|
165107
|
-
sendDisabled,
|
|
165108
|
-
inputDisabled,
|
|
165109
|
-
displayName: arkoPresentationName(profile),
|
|
165110
|
-
selectedModel: selectedModelName(catalog),
|
|
165111
|
-
canChooseModel: (catalog?.options.length ?? 0) > 1,
|
|
165112
|
-
continuation: (0, react$1.useMemo)(() => latestContinuation(messages, session?.sessionId), [messages, session?.sessionId]),
|
|
165113
|
-
send,
|
|
165114
|
-
submitTurn,
|
|
165115
|
-
selectModel,
|
|
165116
|
-
cancelActiveRun,
|
|
165117
|
-
clearContext,
|
|
165118
|
-
loadEarlier,
|
|
165119
|
-
retryHistory,
|
|
165120
|
-
setDraft: (text) => arkmeComposerDraftStore.setText(composerDraftKey, text),
|
|
165121
|
-
feedback: setError
|
|
165122
|
-
};
|
|
165123
|
-
}
|
|
165124
|
-
//#endregion
|
|
165125
163493
|
//#region src/harness-conversation-layout-contract.ts
|
|
165126
163494
|
/** Optional, presentation-only exports from the installed Harness runtime. */
|
|
165127
163495
|
const HARNESS_LAYOUT_MODULES = {
|
|
@@ -165591,6 +163959,62 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
165591
163959
|
r$3.displayName = "ArrowsClockwiseIcon";
|
|
165592
163960
|
const m$4 = r$3;
|
|
165593
163961
|
//#endregion
|
|
163962
|
+
//#region src/client/arko-pending-turn-store.ts
|
|
163963
|
+
const STORAGE_KEY_PREFIX = "arkme:arko:pending-turn:v1:";
|
|
163964
|
+
const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
163965
|
+
function defaultStorage() {
|
|
163966
|
+
try {
|
|
163967
|
+
return typeof globalThis.sessionStorage === "undefined" ? void 0 : globalThis.sessionStorage;
|
|
163968
|
+
} catch {
|
|
163969
|
+
return;
|
|
163970
|
+
}
|
|
163971
|
+
}
|
|
163972
|
+
function storageKey(userId) {
|
|
163973
|
+
return `${STORAGE_KEY_PREFIX}${String(userId)}`;
|
|
163974
|
+
}
|
|
163975
|
+
function optionalTrimmedString(value) {
|
|
163976
|
+
if (typeof value !== "string") return void 0;
|
|
163977
|
+
const normalized = value.trim();
|
|
163978
|
+
return normalized === "" ? void 0 : normalized;
|
|
163979
|
+
}
|
|
163980
|
+
function isValidArkoPendingTurn(value, expectedUserId) {
|
|
163981
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
163982
|
+
const turn = value;
|
|
163983
|
+
const hasContinuationRun = optionalTrimmedString(turn.replyToRunUid) !== void 0;
|
|
163984
|
+
const hasContinuationMessage = Number.isSafeInteger(turn.replyToAssistantMsgId) && (turn.replyToAssistantMsgId ?? 0) > 0;
|
|
163985
|
+
return Number.isSafeInteger(turn.userId) && (turn.userId ?? 0) > 0 && (expectedUserId === void 0 || turn.userId === expectedUserId) && Number.isSafeInteger(turn.sessionId) && (turn.sessionId ?? 0) > 0 && typeof turn.clientTurnUid === "string" && UUID_PATTERN.test(turn.clientTurnUid) && typeof turn.text === "string" && turn.text.trim() !== "" && Number.isSafeInteger(turn.createdAtMillis) && (turn.createdAtMillis ?? 0) > 0 && optionalTrimmedString(turn.localUserMessageId) !== void 0 && optionalTrimmedString(turn.localAssistantMessageId) !== void 0 && (turn.modelRouteKey === void 0 || optionalTrimmedString(turn.modelRouteKey) !== void 0) && hasContinuationRun === hasContinuationMessage && (!hasContinuationRun || turn.modelRouteKey === void 0);
|
|
163986
|
+
}
|
|
163987
|
+
function readArkoPendingTurn(userId, storage = defaultStorage()) {
|
|
163988
|
+
if (!Number.isSafeInteger(userId) || userId <= 0 || storage === void 0) return void 0;
|
|
163989
|
+
try {
|
|
163990
|
+
const encoded = storage.getItem(storageKey(userId));
|
|
163991
|
+
if (encoded === null) return void 0;
|
|
163992
|
+
const value = JSON.parse(encoded);
|
|
163993
|
+
if (!isValidArkoPendingTurn(value, userId)) {
|
|
163994
|
+
storage.removeItem(storageKey(userId));
|
|
163995
|
+
return;
|
|
163996
|
+
}
|
|
163997
|
+
return value;
|
|
163998
|
+
} catch {
|
|
163999
|
+
return;
|
|
164000
|
+
}
|
|
164001
|
+
}
|
|
164002
|
+
function writeArkoPendingTurn(turn, storage = defaultStorage()) {
|
|
164003
|
+
if (!isValidArkoPendingTurn(turn) || storage === void 0) return false;
|
|
164004
|
+
try {
|
|
164005
|
+
storage.setItem(storageKey(turn.userId), JSON.stringify(turn));
|
|
164006
|
+
return true;
|
|
164007
|
+
} catch {
|
|
164008
|
+
return false;
|
|
164009
|
+
}
|
|
164010
|
+
}
|
|
164011
|
+
function removeArkoPendingTurn(userId, storage = defaultStorage()) {
|
|
164012
|
+
if (!Number.isSafeInteger(userId) || userId <= 0 || storage === void 0) return;
|
|
164013
|
+
try {
|
|
164014
|
+
storage.removeItem(storageKey(userId));
|
|
164015
|
+
} catch {}
|
|
164016
|
+
}
|
|
164017
|
+
//#endregion
|
|
165594
164018
|
//#region src/client/conversation-composer-presentation.ts
|
|
165595
164019
|
const arkmeConversationComposerMaxHeight = 336;
|
|
165596
164020
|
/** Keep each border property present across target and resize transitions. */
|
|
@@ -166949,7 +165373,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
166949
165373
|
}]))
|
|
166950
165374
|
};
|
|
166951
165375
|
}
|
|
166952
|
-
function errorMessage$
|
|
165376
|
+
function errorMessage$8(error) {
|
|
166953
165377
|
if (error instanceof ArkmeClientError) return error.body.message;
|
|
166954
165378
|
return error instanceof Error ? error.message : String(error);
|
|
166955
165379
|
}
|
|
@@ -167264,7 +165688,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
167264
165688
|
await copyText$3(value);
|
|
167265
165689
|
showStatus("已复制", revision);
|
|
167266
165690
|
} catch (error) {
|
|
167267
|
-
showStatus(errorMessage$
|
|
165691
|
+
showStatus(errorMessage$8(error) || "复制失败,请稍后重试", revision);
|
|
167268
165692
|
}
|
|
167269
165693
|
}, [showStatus]);
|
|
167270
165694
|
const copyLink = (0, react$1.useCallback)(async (items) => {
|
|
@@ -167292,7 +165716,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
167292
165716
|
setSelectedIds(void 0);
|
|
167293
165717
|
showStatus("已复制链接");
|
|
167294
165718
|
} catch (error) {
|
|
167295
|
-
if (revision === revisionRef.current) showStatus(controller.signal.aborted ? "复制链接超时,请重试" : errorMessage$
|
|
165719
|
+
if (revision === revisionRef.current) showStatus(controller.signal.aborted ? "复制链接超时,请重试" : errorMessage$8(error) || "分享失败,请重试");
|
|
167296
165720
|
} finally {
|
|
167297
165721
|
window.clearTimeout(timeout);
|
|
167298
165722
|
if (revision === revisionRef.current) setBusy(void 0);
|
|
@@ -167355,7 +165779,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
167355
165779
|
setPicker((current) => current === void 0 ? current : {
|
|
167356
165780
|
...current,
|
|
167357
165781
|
loading: false,
|
|
167358
|
-
error: controller.signal.aborted ? "转发对象加载超时" : errorMessage$
|
|
165782
|
+
error: controller.signal.aborted ? "转发对象加载超时" : errorMessage$8(error) || "转发对象加载失败"
|
|
167359
165783
|
});
|
|
167360
165784
|
} finally {
|
|
167361
165785
|
window.clearTimeout(timeout);
|
|
@@ -167422,7 +165846,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
167422
165846
|
const warningText = successes.map((success) => success.value.result.warningText?.trim() ?? "").find((value) => value !== "") ?? "转发已完成,附言发送失败";
|
|
167423
165847
|
for (const success of successes) input.onForwarded?.(success.value.target, success.value.result);
|
|
167424
165848
|
if (successes.length === 0) {
|
|
167425
|
-
const message = controller.signal.aborted ? "转发超时,请重试" : errorMessage$
|
|
165849
|
+
const message = controller.signal.aborted ? "转发超时,请重试" : errorMessage$8(results[0]?.reason) || "发送失败,请重试";
|
|
167426
165850
|
setPicker((current) => current === void 0 ? current : {
|
|
167427
165851
|
...current,
|
|
167428
165852
|
error: message
|
|
@@ -167794,6 +166218,14 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
167794
166218
|
}
|
|
167795
166219
|
//#endregion
|
|
167796
166220
|
//#region src/client/ArkmeArkoSurface.tsx
|
|
166221
|
+
const arkoQuestionMaxLength = 60 * 1024;
|
|
166222
|
+
const ACTIVE_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
166223
|
+
"accepted",
|
|
166224
|
+
"queued",
|
|
166225
|
+
"running",
|
|
166226
|
+
"stream_timeout",
|
|
166227
|
+
"waiting_tool"
|
|
166228
|
+
]);
|
|
167797
166229
|
const colors$5 = {
|
|
167798
166230
|
text: arkmeTheme.text,
|
|
167799
166231
|
secondary: arkmeTheme.secondary,
|
|
@@ -168296,6 +166728,10 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168296
166728
|
},
|
|
168297
166729
|
stop: { background: colors$5.danger }
|
|
168298
166730
|
};
|
|
166731
|
+
function errorMessage$7(error) {
|
|
166732
|
+
if (error instanceof ArkmeClientError) return error.body.message;
|
|
166733
|
+
return error instanceof Error ? error.message : String(error);
|
|
166734
|
+
}
|
|
168299
166735
|
function arkoRunActivityLabel(status) {
|
|
168300
166736
|
if (status === "accepted" || status === "queued") return "正在思考";
|
|
168301
166737
|
if (status === "running" || status === "stream_timeout") return tr$1("正在处理");
|
|
@@ -168313,6 +166749,29 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168313
166749
|
function arkoPreservedScrollTop(previousScrollTop, previousScrollHeight, nextScrollHeight) {
|
|
168314
166750
|
return Math.max(0, previousScrollTop + (nextScrollHeight - previousScrollHeight));
|
|
168315
166751
|
}
|
|
166752
|
+
function isActiveRunStatus(status) {
|
|
166753
|
+
return status !== void 0 && ACTIVE_RUN_STATUSES.has(status);
|
|
166754
|
+
}
|
|
166755
|
+
function isActivityPlaceholderText(value) {
|
|
166756
|
+
return /^(正在)?(思考|处理)(中)?[.。…]*$/.test(value.trim());
|
|
166757
|
+
}
|
|
166758
|
+
function isActiveHistoryRun(item) {
|
|
166759
|
+
const placeholder = isActivityPlaceholderText(item.text);
|
|
166760
|
+
return item.role === "assistant" && (isActiveRunStatus(item.runStatus) || item.runStatus === void 0 && item.status === 2 && (item.text.trim() === "" || placeholder));
|
|
166761
|
+
}
|
|
166762
|
+
function arkoHistoryHasTerminalRun(items, sessionId, assistantMsgId, runUid) {
|
|
166763
|
+
const matchingItem = items.find((item) => item.role === "assistant" && item.sessionId === sessionId && item.messageId === assistantMsgId && (item.runUid === void 0 || item.runUid === runUid));
|
|
166764
|
+
return matchingItem !== void 0 && !isActiveHistoryRun(matchingItem);
|
|
166765
|
+
}
|
|
166766
|
+
function waitForNextPoll(signal, delayMillis = 1200) {
|
|
166767
|
+
return new Promise((resolve) => {
|
|
166768
|
+
const timeout = setTimeout(resolve, delayMillis);
|
|
166769
|
+
signal.addEventListener("abort", () => {
|
|
166770
|
+
clearTimeout(timeout);
|
|
166771
|
+
resolve();
|
|
166772
|
+
}, { once: true });
|
|
166773
|
+
});
|
|
166774
|
+
}
|
|
168316
166775
|
function ArkoThinkingPanel({ reasoning, activity }) {
|
|
168317
166776
|
useArkmeLocale();
|
|
168318
166777
|
const [expanded, setExpanded] = (0, react$1.useState)(true);
|
|
@@ -168359,37 +166818,115 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168359
166818
|
})]
|
|
168360
166819
|
});
|
|
168361
166820
|
}
|
|
168362
|
-
function
|
|
168363
|
-
const
|
|
168364
|
-
|
|
166821
|
+
function historyMessage(item) {
|
|
166822
|
+
const placeholder = isActivityPlaceholderText(item.text);
|
|
166823
|
+
const reasoningPlaceholder = isActivityPlaceholderText(item.reasoning);
|
|
166824
|
+
const active = isActiveHistoryRun(item);
|
|
166825
|
+
return {
|
|
166826
|
+
id: `history:${String(item.messageId)}`,
|
|
166827
|
+
messageId: item.messageId,
|
|
166828
|
+
sessionId: item.sessionId,
|
|
166829
|
+
role: item.role,
|
|
166830
|
+
text: active && placeholder ? "" : item.text,
|
|
166831
|
+
status: active ? "sending" : item.runStatus === "failed" ? "error" : "done",
|
|
166832
|
+
createdAtMillis: item.createdAtMillis,
|
|
166833
|
+
...item.reasoning.trim() === "" || !active && reasoningPlaceholder ? {} : { reasoning: item.reasoning },
|
|
166834
|
+
...item.role !== "assistant" ? {} : { assistantMsgId: item.messageId },
|
|
166835
|
+
...item.runUid === void 0 ? {} : { runUid: item.runUid },
|
|
166836
|
+
...item.runStatus === void 0 ? {} : { runStatus: item.runStatus },
|
|
166837
|
+
...item.messageActionRef === void 0 ? {} : {
|
|
166838
|
+
messageActionRef: item.messageActionRef,
|
|
166839
|
+
...item.messageActionConversationRef === void 0 ? {} : { messageActionConversationRef: item.messageActionConversationRef },
|
|
166840
|
+
copyLinkAvailable: item.messageActionCapabilities?.copyLink === true,
|
|
166841
|
+
forwardAvailable: item.messageActionCapabilities?.forward === true
|
|
166842
|
+
}
|
|
166843
|
+
};
|
|
166844
|
+
}
|
|
166845
|
+
function latestActiveRun(items, sessionId) {
|
|
166846
|
+
const item = items.filter((candidate) => candidate.sessionId === sessionId && candidate.role === "assistant" && candidate.runUid !== void 0 && isActiveRunStatus(candidate.runStatus)).sort((left, right) => right.createdAtMillis - left.createdAtMillis || right.messageId - left.messageId)[0];
|
|
166847
|
+
if (item?.runUid === void 0) return void 0;
|
|
166848
|
+
return {
|
|
166849
|
+
sessionId: item.sessionId,
|
|
166850
|
+
assistantMsgId: item.messageId,
|
|
166851
|
+
runUid: item.runUid
|
|
166852
|
+
};
|
|
166853
|
+
}
|
|
166854
|
+
function mergeHistory(current, items) {
|
|
166855
|
+
const byId = new Map(current.map((item) => [item.id, item]));
|
|
166856
|
+
for (const item of items) byId.set(`history:${String(item.messageId)}`, historyMessage(item));
|
|
166857
|
+
return [...byId.values()].sort((left, right) => {
|
|
166858
|
+
const leftAt = left.createdAtMillis ?? Number.MAX_SAFE_INTEGER;
|
|
166859
|
+
const rightAt = right.createdAtMillis ?? Number.MAX_SAFE_INTEGER;
|
|
166860
|
+
if (leftAt !== rightAt) return leftAt - rightAt;
|
|
166861
|
+
return (left.messageId ?? Number.MAX_SAFE_INTEGER) - (right.messageId ?? Number.MAX_SAFE_INTEGER);
|
|
166862
|
+
});
|
|
166863
|
+
}
|
|
166864
|
+
function resultText(result) {
|
|
166865
|
+
if (result.text.trim() !== "") return result.text.trim();
|
|
166866
|
+
if (result.errorMessage?.trim()) return result.errorMessage.trim();
|
|
166867
|
+
if (isActiveRunStatus(result.run?.status ?? result.status)) return "";
|
|
166868
|
+
return "任务已处理。";
|
|
168365
166869
|
}
|
|
168366
|
-
function
|
|
166870
|
+
function latestContinuation(messages, sessionId) {
|
|
166871
|
+
if (sessionId === void 0) return void 0;
|
|
166872
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
166873
|
+
const message = messages[index];
|
|
166874
|
+
if (message === void 0) continue;
|
|
166875
|
+
if (message.role === "divider") return void 0;
|
|
166876
|
+
if (message.sessionId !== sessionId) continue;
|
|
166877
|
+
if (message.role === "user") return void 0;
|
|
166878
|
+
if (message.runStatus !== "waiting_user" || message.runUid === void 0 || message.assistantMsgId === void 0) return;
|
|
166879
|
+
return {
|
|
166880
|
+
runUid: message.runUid,
|
|
166881
|
+
assistantMsgId: message.assistantMsgId
|
|
166882
|
+
};
|
|
166883
|
+
}
|
|
166884
|
+
}
|
|
166885
|
+
function selectedModelName(catalog) {
|
|
166886
|
+
return catalog?.options.find((option) => option.routeKey === catalog.effectiveRouteKey)?.displayName ?? "模型目录暂不可用";
|
|
166887
|
+
}
|
|
166888
|
+
function ArkmeArkoSurface() {
|
|
168367
166889
|
useArkmeLocale();
|
|
168368
|
-
const { accountKey, profileUserId, composerDraftKey, draftSnapshot, draft, userProfile, session, catalog, messages, historyOffset, historyError, historyPageError, loading, historyLoading, sending, clearing, selectingModel, cancelling, error, notice, activeRun, pendingTurn, interactionLocked, sendDisabled, inputDisabled, displayName, selectedModel, canChooseModel, continuation, submitTurn, cancelActiveRun, retryHistory, feedback: setError } = controller;
|
|
168369
166890
|
const bodyRef = (0, react$1.useRef)(null);
|
|
168370
166891
|
const historySentinelRef = (0, react$1.useRef)(null);
|
|
166892
|
+
const historyLoadInFlightRef = (0, react$1.useRef)(false);
|
|
168371
166893
|
const composerInputBoundaryRef = (0, react$1.useRef)(null);
|
|
168372
166894
|
const composerRef = (0, react$1.useRef)(null);
|
|
168373
166895
|
const textareaRef = (0, react$1.useRef)(null);
|
|
168374
166896
|
const pendingComposerFocusRef = (0, react$1.useRef)(false);
|
|
166897
|
+
const sendInFlightRef = (0, react$1.useRef)(false);
|
|
166898
|
+
const authSnapshot = (0, react$1.useSyncExternalStore)(arkmeAuthStore.subscribe, arkmeAuthStore.getSnapshot, arkmeAuthStore.getSnapshot);
|
|
166899
|
+
const profileSnapshot = (0, react$1.useSyncExternalStore)(arkmeArkoProfileStore.subscribe, arkmeArkoProfileStore.getSnapshot, arkmeArkoProfileStore.getSnapshot);
|
|
166900
|
+
const profileUserId = authSnapshot.auth?.status === "authenticated" ? authSnapshot.auth.userId : void 0;
|
|
166901
|
+
const composerDraftKey = arkmeArkoComposerDraftKey(profileUserId);
|
|
166902
|
+
(0, react$1.useSyncExternalStore)(arkmeComposerDraftStore.subscribe, arkmeComposerDraftStore.getRevision, arkmeComposerDraftStore.getRevision);
|
|
166903
|
+
const draftSnapshot = arkmeComposerDraftStore.get(composerDraftKey);
|
|
166904
|
+
const draft = draftSnapshot.text;
|
|
166905
|
+
const accountKey = authSnapshot.auth?.status === "authenticated" && profileUserId !== void 0 ? `${authSnapshot.auth.environment}:${String(profileUserId)}` : void 0;
|
|
166906
|
+
const profile = profileSnapshot.userId === profileUserId ? profileSnapshot.profile : void 0;
|
|
166907
|
+
const [userProfile, setUserProfile] = (0, react$1.useState)(null);
|
|
166908
|
+
const [session, setSession] = (0, react$1.useState)();
|
|
166909
|
+
const [catalog, setCatalog] = (0, react$1.useState)();
|
|
166910
|
+
const [messages, setMessages] = (0, react$1.useState)([]);
|
|
166911
|
+
const [historyOffset, setHistoryOffset] = (0, react$1.useState)();
|
|
166912
|
+
const [historyError, setHistoryError] = (0, react$1.useState)("");
|
|
166913
|
+
const [loading, setLoading] = (0, react$1.useState)(true);
|
|
166914
|
+
const [historyLoading, setHistoryLoading] = (0, react$1.useState)(false);
|
|
166915
|
+
const [sending, setSending] = (0, react$1.useState)(false);
|
|
166916
|
+
const [clearing, setClearing] = (0, react$1.useState)(false);
|
|
166917
|
+
const [selectingModel, setSelectingModel] = (0, react$1.useState)(false);
|
|
166918
|
+
const [cancelling, setCancelling] = (0, react$1.useState)(false);
|
|
168375
166919
|
const [modelDialogOpen, setModelDialogOpen] = (0, react$1.useState)(false);
|
|
168376
166920
|
const [clearConfirmOpen, setClearConfirmOpen] = (0, react$1.useState)(false);
|
|
168377
|
-
const
|
|
168378
|
-
|
|
168379
|
-
|
|
168380
|
-
|
|
168381
|
-
const selectModel = async (routeKey) => {
|
|
168382
|
-
if (await controller.selectModel(routeKey)) setModelDialogOpen(false);
|
|
168383
|
-
};
|
|
168384
|
-
const clearContext = async () => {
|
|
168385
|
-
setClearConfirmOpen(false);
|
|
168386
|
-
await controller.clearContext();
|
|
168387
|
-
};
|
|
166921
|
+
const [error, setError] = (0, react$1.useState)("");
|
|
166922
|
+
const [notice, setNotice] = (0, react$1.useState)("");
|
|
166923
|
+
const [activeRun, setActiveRun] = (0, react$1.useState)();
|
|
166924
|
+
const [pendingTurn, setPendingTurn] = (0, react$1.useState)();
|
|
168388
166925
|
const detailTriggerRef = (0, react$1.useRef)(null);
|
|
168389
166926
|
const detailBodyRef = (0, react$1.useRef)(null);
|
|
168390
|
-
const detailScope = `${
|
|
166927
|
+
const detailScope = `${authSnapshot.auth?.environment ?? ""}:${String(profileUserId)}:${String(session?.sessionId)}`;
|
|
168391
166928
|
const [detailSelection, setDetailSelection] = (0, react$1.useState)();
|
|
168392
|
-
const detailMessage = detailSelection?.scope === detailScope ? messages.find((message) =>
|
|
166929
|
+
const detailMessage = detailSelection?.scope === detailScope ? messages.find((message) => message.id === detailSelection.id && message.role !== "divider") : void 0;
|
|
168393
166930
|
const detailActivity = detailMessage?.status === "sending" ? arkoRunActivityLabel(detailMessage.runStatus) ?? "等待回复" : detailMessage?.status === "error" ? pendingTurn?.localAssistantMessageId === detailMessage.id ? "发送结果待确认" : "消息处理失败" : void 0;
|
|
168394
166931
|
(0, react$1.useEffect)(() => {
|
|
168395
166932
|
setDetailSelection(void 0);
|
|
@@ -168400,7 +166937,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168400
166937
|
trigger.focus({ preventScroll: true });
|
|
168401
166938
|
setDetailSelection({
|
|
168402
166939
|
scope: detailScope,
|
|
168403
|
-
id
|
|
166940
|
+
id
|
|
168404
166941
|
});
|
|
168405
166942
|
};
|
|
168406
166943
|
const messageActionItems = (0, react$1.useMemo)(() => messages.flatMap((message) => message.role === "divider" || message.messageActionRef === void 0 || message.messageActionConversationRef === void 0 ? [] : [{
|
|
@@ -168429,33 +166966,195 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168429
166966
|
if (bodyRef.current !== null) bodyRef.current.scrollTop = bodyRef.current.scrollHeight;
|
|
168430
166967
|
});
|
|
168431
166968
|
}, []);
|
|
168432
|
-
const lastMessage = messages.at(-1);
|
|
168433
166969
|
(0, react$1.useEffect)(() => {
|
|
166970
|
+
arkmeArkoProfileStore.activateUser(profileUserId);
|
|
166971
|
+
arkmeArkoConversationPreviewStore.activateUser(profileUserId);
|
|
166972
|
+
}, [profileUserId]);
|
|
166973
|
+
(0, react$1.useEffect)(() => {
|
|
166974
|
+
if (profileUserId === void 0) return;
|
|
166975
|
+
arkmeArkoConversationPreviewStore.setLatestFromSurface(profileUserId, messages.filter((message) => message.role !== "divider").map((message) => ({
|
|
166976
|
+
key: message.id,
|
|
166977
|
+
text: message.text,
|
|
166978
|
+
...message.messageId === void 0 ? {} : { messageId: message.messageId },
|
|
166979
|
+
...message.createdAtMillis === void 0 ? {} : { createdAtMillis: message.createdAtMillis }
|
|
166980
|
+
})));
|
|
166981
|
+
}, [messages, profileUserId]);
|
|
166982
|
+
(0, react$1.useEffect)(() => {
|
|
166983
|
+
if (profileUserId === void 0) {
|
|
166984
|
+
setPendingTurn(void 0);
|
|
166985
|
+
return;
|
|
166986
|
+
}
|
|
166987
|
+
const restored = readArkoPendingTurn(profileUserId);
|
|
166988
|
+
setPendingTurn(restored);
|
|
166989
|
+
if (restored === void 0) return;
|
|
166990
|
+
setMessages((current) => {
|
|
166991
|
+
if (current.some((item) => item.id === restored.localAssistantMessageId)) return current;
|
|
166992
|
+
return [
|
|
166993
|
+
...current,
|
|
166994
|
+
{
|
|
166995
|
+
id: restored.localUserMessageId,
|
|
166996
|
+
sessionId: restored.sessionId,
|
|
166997
|
+
role: "user",
|
|
166998
|
+
text: restored.text,
|
|
166999
|
+
status: "done",
|
|
167000
|
+
createdAtMillis: restored.createdAtMillis
|
|
167001
|
+
},
|
|
167002
|
+
{
|
|
167003
|
+
id: restored.localAssistantMessageId,
|
|
167004
|
+
sessionId: restored.sessionId,
|
|
167005
|
+
role: "assistant",
|
|
167006
|
+
text: "",
|
|
167007
|
+
status: "error",
|
|
167008
|
+
createdAtMillis: restored.createdAtMillis + 1
|
|
167009
|
+
}
|
|
167010
|
+
];
|
|
167011
|
+
});
|
|
168434
167012
|
scrollToBottom();
|
|
167013
|
+
}, [profileUserId, scrollToBottom]);
|
|
167014
|
+
(0, react$1.useEffect)(() => {
|
|
167015
|
+
const controller = new AbortController();
|
|
167016
|
+
setLoading(true);
|
|
167017
|
+
setError("");
|
|
167018
|
+
setHistoryError("");
|
|
167019
|
+
Promise.allSettled([
|
|
167020
|
+
callArkme("arko.session", void 0, controller.signal),
|
|
167021
|
+
callArkme("arko.profile", void 0, controller.signal),
|
|
167022
|
+
callArkme("arko.models", void 0, controller.signal),
|
|
167023
|
+
callArkme("arko.history", {
|
|
167024
|
+
limit: 50,
|
|
167025
|
+
offset: 0
|
|
167026
|
+
}, controller.signal),
|
|
167027
|
+
callArkme("user.profile", void 0, controller.signal).then(async (snapshot) => snapshot.profile === null ? await callArkme("user.profile.refresh", void 0, controller.signal) : snapshot)
|
|
167028
|
+
]).then(([sessionResult, profileResult, modelResult, historyResult, userProfileResult]) => {
|
|
167029
|
+
if (controller.signal.aborted) return;
|
|
167030
|
+
if (sessionResult.status === "rejected") {
|
|
167031
|
+
setError(errorMessage$7(sessionResult.reason));
|
|
167032
|
+
return;
|
|
167033
|
+
}
|
|
167034
|
+
setSession(sessionResult.value);
|
|
167035
|
+
if (profileResult.status === "fulfilled" && profileUserId !== void 0) arkmeArkoProfileStore.setProfile(profileUserId, profileResult.value);
|
|
167036
|
+
if (modelResult.status === "fulfilled") setCatalog(modelResult.value);
|
|
167037
|
+
if (userProfileResult.status === "fulfilled") setUserProfile(userProfileResult.value.profile);
|
|
167038
|
+
if (historyResult.status === "fulfilled") {
|
|
167039
|
+
setMessages((current) => mergeHistory(current, historyResult.value.items));
|
|
167040
|
+
setHistoryOffset(historyResult.value.nextOffset);
|
|
167041
|
+
scrollToBottom();
|
|
167042
|
+
const restoredRun = latestActiveRun(historyResult.value.items, sessionResult.value.sessionId);
|
|
167043
|
+
if (restoredRun !== void 0) {
|
|
167044
|
+
setActiveRun(restoredRun);
|
|
167045
|
+
setSending(true);
|
|
167046
|
+
}
|
|
167047
|
+
} else setHistoryError(tr$1("加载 Arko 对话记录失败:{v0}", { v0: errorMessage$7(historyResult.reason) }));
|
|
167048
|
+
}).finally(() => {
|
|
167049
|
+
if (!controller.signal.aborted) setLoading(false);
|
|
167050
|
+
});
|
|
167051
|
+
return () => {
|
|
167052
|
+
controller.abort();
|
|
167053
|
+
};
|
|
167054
|
+
}, [profileUserId, scrollToBottom]);
|
|
167055
|
+
(0, react$1.useEffect)(() => {
|
|
167056
|
+
if (activeRun === void 0) return;
|
|
167057
|
+
const controller = new AbortController();
|
|
167058
|
+
let consecutiveFailures = 0;
|
|
167059
|
+
const finishRun = async (knownHistory) => {
|
|
167060
|
+
const [historyResult, profileResult] = await Promise.allSettled([knownHistory === void 0 ? callArkme("arko.history", {
|
|
167061
|
+
limit: 50,
|
|
167062
|
+
offset: 0
|
|
167063
|
+
}, controller.signal) : Promise.resolve(knownHistory), callArkme("arko.profile", void 0, controller.signal)]);
|
|
167064
|
+
if (controller.signal.aborted) return;
|
|
167065
|
+
if (historyResult.status === "fulfilled") {
|
|
167066
|
+
setMessages((current) => mergeHistory(current, historyResult.value.items));
|
|
167067
|
+
setHistoryOffset(historyResult.value.nextOffset);
|
|
167068
|
+
setHistoryError("");
|
|
167069
|
+
scrollToBottom();
|
|
167070
|
+
} else setHistoryError(tr$1("刷新 Arko 对话记录失败:{v0}", { v0: errorMessage$7(historyResult.reason) }));
|
|
167071
|
+
if (profileResult.status === "fulfilled" && profileUserId !== void 0) arkmeArkoProfileStore.setProfile(profileUserId, profileResult.value);
|
|
167072
|
+
setActiveRun((current) => current?.runUid === activeRun.runUid ? void 0 : current);
|
|
167073
|
+
setSending(false);
|
|
167074
|
+
};
|
|
167075
|
+
const poll = async () => {
|
|
167076
|
+
await waitForNextPoll(controller.signal);
|
|
167077
|
+
while (!controller.signal.aborted) {
|
|
167078
|
+
try {
|
|
167079
|
+
const status = await callArkme("arko.run.status", {
|
|
167080
|
+
sessionId: activeRun.sessionId,
|
|
167081
|
+
runUid: activeRun.runUid
|
|
167082
|
+
}, controller.signal);
|
|
167083
|
+
if (controller.signal.aborted) return;
|
|
167084
|
+
consecutiveFailures = 0;
|
|
167085
|
+
if (status.status === "waiting_tool") setNotice("当前任务需要 DSH 尚未支持的客户端操作,可以停止任务后换一种方式重试");
|
|
167086
|
+
setMessages((current) => current.map((item) => item.assistantMsgId === activeRun.assistantMsgId ? {
|
|
167087
|
+
...item,
|
|
167088
|
+
runStatus: status.status,
|
|
167089
|
+
status: isActiveRunStatus(status.status) ? "sending" : status.status === "failed" ? "error" : "done"
|
|
167090
|
+
} : item));
|
|
167091
|
+
if (!isActiveRunStatus(status.status)) {
|
|
167092
|
+
await finishRun();
|
|
167093
|
+
return;
|
|
167094
|
+
}
|
|
167095
|
+
} catch {
|
|
167096
|
+
if (controller.signal.aborted) return;
|
|
167097
|
+
consecutiveFailures += 1;
|
|
167098
|
+
try {
|
|
167099
|
+
const history = await callArkme("arko.history", {
|
|
167100
|
+
limit: 50,
|
|
167101
|
+
offset: 0
|
|
167102
|
+
}, controller.signal);
|
|
167103
|
+
if (controller.signal.aborted) return;
|
|
167104
|
+
if (arkoHistoryHasTerminalRun(history.items, activeRun.sessionId, activeRun.assistantMsgId, activeRun.runUid)) {
|
|
167105
|
+
await finishRun(history);
|
|
167106
|
+
return;
|
|
167107
|
+
}
|
|
167108
|
+
} catch {
|
|
167109
|
+
if (controller.signal.aborted) return;
|
|
167110
|
+
}
|
|
167111
|
+
}
|
|
167112
|
+
const retryDelay = consecutiveFailures === 0 ? 1200 : Math.min(1e4, 1200 * 2 ** Math.min(consecutiveFailures - 1, 3));
|
|
167113
|
+
await waitForNextPoll(controller.signal, retryDelay);
|
|
167114
|
+
}
|
|
167115
|
+
};
|
|
167116
|
+
poll();
|
|
167117
|
+
return () => {
|
|
167118
|
+
controller.abort();
|
|
167119
|
+
};
|
|
168435
167120
|
}, [
|
|
168436
|
-
|
|
168437
|
-
|
|
168438
|
-
lastMessage?.reasoning,
|
|
167121
|
+
activeRun,
|
|
167122
|
+
profileUserId,
|
|
168439
167123
|
scrollToBottom
|
|
168440
167124
|
]);
|
|
168441
167125
|
const loadEarlier = (0, react$1.useCallback)(async () => {
|
|
167126
|
+
if (historyOffset === void 0 || historyLoadInFlightRef.current) return;
|
|
168442
167127
|
const body = bodyRef.current;
|
|
168443
167128
|
const previousScrollHeight = body?.scrollHeight ?? 0;
|
|
168444
167129
|
const previousScrollTop = body?.scrollTop ?? 0;
|
|
167130
|
+
historyLoadInFlightRef.current = true;
|
|
167131
|
+
setHistoryLoading(true);
|
|
168445
167132
|
try {
|
|
168446
|
-
await
|
|
167133
|
+
const page = await callArkme("arko.history", {
|
|
167134
|
+
limit: 50,
|
|
167135
|
+
offset: historyOffset
|
|
167136
|
+
});
|
|
167137
|
+
setMessages((current) => mergeHistory(current, page.items));
|
|
167138
|
+
setHistoryOffset(page.nextOffset);
|
|
167139
|
+
setHistoryError("");
|
|
168447
167140
|
requestAnimationFrame(() => {
|
|
168448
167141
|
const target = bodyRef.current;
|
|
168449
|
-
if (target
|
|
167142
|
+
if (target === null) return;
|
|
167143
|
+
target.scrollTop = arkoPreservedScrollTop(previousScrollTop, previousScrollHeight, target.scrollHeight);
|
|
168450
167144
|
});
|
|
168451
|
-
} catch {
|
|
168452
|
-
|
|
167145
|
+
} catch (caught) {
|
|
167146
|
+
setHistoryError(tr$1("加载更早的 Arko 对话记录失败:{v0}", { v0: errorMessage$7(caught) }));
|
|
167147
|
+
} finally {
|
|
167148
|
+
historyLoadInFlightRef.current = false;
|
|
167149
|
+
setHistoryLoading(false);
|
|
167150
|
+
}
|
|
167151
|
+
}, [historyOffset]);
|
|
168453
167152
|
(0, react$1.useEffect)(() => {
|
|
168454
167153
|
const root = bodyRef.current;
|
|
168455
167154
|
const sentinel = historySentinelRef.current;
|
|
168456
|
-
if (loading || historyLoading || historyError !== "" ||
|
|
167155
|
+
if (loading || historyLoading || historyError !== "" || root === null || sentinel === null || historyOffset === void 0) return;
|
|
168457
167156
|
const observer = new IntersectionObserver((entries) => {
|
|
168458
|
-
if (entries[0]?.isIntersecting !== true) return;
|
|
167157
|
+
if (entries[0]?.isIntersecting !== true || historyLoadInFlightRef.current) return;
|
|
168459
167158
|
loadEarlier();
|
|
168460
167159
|
}, {
|
|
168461
167160
|
root,
|
|
@@ -168466,19 +167165,280 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168466
167165
|
observer.disconnect();
|
|
168467
167166
|
};
|
|
168468
167167
|
}, [
|
|
168469
|
-
historyPageError,
|
|
168470
167168
|
historyError,
|
|
168471
167169
|
historyLoading,
|
|
168472
167170
|
historyOffset,
|
|
168473
167171
|
loadEarlier,
|
|
168474
167172
|
loading
|
|
168475
167173
|
]);
|
|
167174
|
+
const retryHistory = (0, react$1.useCallback)(async () => {
|
|
167175
|
+
if (historyLoading) return;
|
|
167176
|
+
setHistoryLoading(true);
|
|
167177
|
+
setHistoryError("");
|
|
167178
|
+
try {
|
|
167179
|
+
const page = await callArkme("arko.history", {
|
|
167180
|
+
limit: 50,
|
|
167181
|
+
offset: 0
|
|
167182
|
+
});
|
|
167183
|
+
setMessages((current) => mergeHistory(current, page.items));
|
|
167184
|
+
setHistoryOffset(page.nextOffset);
|
|
167185
|
+
scrollToBottom();
|
|
167186
|
+
if (session !== void 0) {
|
|
167187
|
+
const restoredRun = latestActiveRun(page.items, session.sessionId);
|
|
167188
|
+
if (restoredRun !== void 0) {
|
|
167189
|
+
setActiveRun(restoredRun);
|
|
167190
|
+
setSending(true);
|
|
167191
|
+
}
|
|
167192
|
+
}
|
|
167193
|
+
} catch (caught) {
|
|
167194
|
+
setHistoryError(tr$1("加载 Arko 对话记录失败:{v0}", { v0: errorMessage$7(caught) }));
|
|
167195
|
+
} finally {
|
|
167196
|
+
setHistoryLoading(false);
|
|
167197
|
+
}
|
|
167198
|
+
}, [
|
|
167199
|
+
historyLoading,
|
|
167200
|
+
scrollToBottom,
|
|
167201
|
+
session
|
|
167202
|
+
]);
|
|
167203
|
+
const submitTurn = (0, react$1.useCallback)(async (turn) => {
|
|
167204
|
+
if (sending || activeRun !== void 0) return;
|
|
167205
|
+
let handedOffToPolling = false;
|
|
167206
|
+
setSending(true);
|
|
167207
|
+
setError("");
|
|
167208
|
+
setNotice("");
|
|
167209
|
+
setMessages((current) => current.map((item) => item.id === turn.localAssistantMessageId ? {
|
|
167210
|
+
...item,
|
|
167211
|
+
text: "",
|
|
167212
|
+
status: "sending",
|
|
167213
|
+
runStatus: "accepted"
|
|
167214
|
+
} : item));
|
|
167215
|
+
try {
|
|
167216
|
+
const result = await callArkme("arko.ask", {
|
|
167217
|
+
text: turn.text,
|
|
167218
|
+
sessionId: turn.sessionId,
|
|
167219
|
+
clientTurnUid: turn.clientTurnUid,
|
|
167220
|
+
waitSeconds: 1,
|
|
167221
|
+
...turn.modelRouteKey === void 0 ? {} : { modelRouteKey: turn.modelRouteKey },
|
|
167222
|
+
...turn.replyToRunUid === void 0 ? {} : { replyToRunUid: turn.replyToRunUid },
|
|
167223
|
+
...turn.replyToAssistantMsgId === void 0 ? {} : { replyToAssistantMsgId: turn.replyToAssistantMsgId }
|
|
167224
|
+
});
|
|
167225
|
+
removeArkoPendingTurn(turn.userId);
|
|
167226
|
+
setPendingTurn((current) => current?.clientTurnUid === turn.clientTurnUid ? void 0 : current);
|
|
167227
|
+
setSession((current) => current === void 0 ? current : {
|
|
167228
|
+
...current,
|
|
167229
|
+
sessionId: result.sessionId
|
|
167230
|
+
});
|
|
167231
|
+
if (result.profile !== void 0 && profileUserId !== void 0) arkmeArkoProfileStore.setProfile(profileUserId, result.profile);
|
|
167232
|
+
const runStatus = result.run?.status ?? result.status;
|
|
167233
|
+
const runActive = isActiveRunStatus(runStatus);
|
|
167234
|
+
const hasVisibleReasoning = result.reasoning.trim() !== "" && (runActive || !isActivityPlaceholderText(result.reasoning));
|
|
167235
|
+
setMessages((current) => mergeHistory(current.map((item) => item.id === turn.localUserMessageId ? {
|
|
167236
|
+
...item,
|
|
167237
|
+
id: `history:${String(result.userMsgId)}`,
|
|
167238
|
+
messageId: result.userMsgId,
|
|
167239
|
+
sessionId: result.sessionId
|
|
167240
|
+
} : item.id === turn.localAssistantMessageId ? {
|
|
167241
|
+
id: `history:${String(result.assistantMsgId)}`,
|
|
167242
|
+
messageId: result.assistantMsgId,
|
|
167243
|
+
sessionId: result.sessionId,
|
|
167244
|
+
role: "assistant",
|
|
167245
|
+
text: resultText(result),
|
|
167246
|
+
status: runActive ? "sending" : result.errorMessage === void 0 ? "done" : "error",
|
|
167247
|
+
assistantMsgId: result.assistantMsgId,
|
|
167248
|
+
...item.createdAtMillis === void 0 ? {} : { createdAtMillis: item.createdAtMillis },
|
|
167249
|
+
...hasVisibleReasoning ? { reasoning: result.reasoning } : {},
|
|
167250
|
+
...result.runUid === void 0 ? {} : { runUid: result.runUid },
|
|
167251
|
+
runStatus
|
|
167252
|
+
} : item), []));
|
|
167253
|
+
setDetailSelection((current) => {
|
|
167254
|
+
if (current?.scope !== detailScope) return current;
|
|
167255
|
+
if (current.id === turn.localUserMessageId) return {
|
|
167256
|
+
...current,
|
|
167257
|
+
id: `history:${String(result.userMsgId)}`
|
|
167258
|
+
};
|
|
167259
|
+
if (current.id === turn.localAssistantMessageId) return {
|
|
167260
|
+
...current,
|
|
167261
|
+
id: `history:${String(result.assistantMsgId)}`
|
|
167262
|
+
};
|
|
167263
|
+
return current;
|
|
167264
|
+
});
|
|
167265
|
+
if (runActive && result.runUid !== void 0) {
|
|
167266
|
+
handedOffToPolling = true;
|
|
167267
|
+
setActiveRun({
|
|
167268
|
+
sessionId: result.sessionId,
|
|
167269
|
+
assistantMsgId: result.assistantMsgId,
|
|
167270
|
+
runUid: result.runUid
|
|
167271
|
+
});
|
|
167272
|
+
}
|
|
167273
|
+
} catch (caught) {
|
|
167274
|
+
const message = errorMessage$7(caught);
|
|
167275
|
+
if (!(caught instanceof ArkmeClientError) || caught.body.retryable) {
|
|
167276
|
+
setPendingTurn(turn);
|
|
167277
|
+
writeArkoPendingTurn(turn);
|
|
167278
|
+
setError(`Arko 发送结果暂未确认:${message}。请重试确认,系统会复用同一次请求,不会重复执行。`);
|
|
167279
|
+
setMessages((current) => current.map((item) => item.id === turn.localAssistantMessageId ? {
|
|
167280
|
+
...item,
|
|
167281
|
+
role: "assistant",
|
|
167282
|
+
text: "",
|
|
167283
|
+
status: "error"
|
|
167284
|
+
} : item));
|
|
167285
|
+
} else {
|
|
167286
|
+
removeArkoPendingTurn(turn.userId);
|
|
167287
|
+
setPendingTurn((current) => current?.clientTurnUid === turn.clientTurnUid ? void 0 : current);
|
|
167288
|
+
setError(message);
|
|
167289
|
+
setMessages((current) => current.map((item) => item.id === turn.localAssistantMessageId ? {
|
|
167290
|
+
...item,
|
|
167291
|
+
role: "assistant",
|
|
167292
|
+
text: message,
|
|
167293
|
+
status: "error"
|
|
167294
|
+
} : item));
|
|
167295
|
+
}
|
|
167296
|
+
} finally {
|
|
167297
|
+
if (!handedOffToPolling) setSending(false);
|
|
167298
|
+
}
|
|
167299
|
+
}, [
|
|
167300
|
+
activeRun,
|
|
167301
|
+
detailScope,
|
|
167302
|
+
profileUserId,
|
|
167303
|
+
sending
|
|
167304
|
+
]);
|
|
167305
|
+
const interactionLocked = sending || pendingTurn !== void 0 || activeRun !== void 0;
|
|
167306
|
+
const sendDisabled = loading || interactionLocked || clearing || selectingModel || session === void 0 || profileUserId === void 0;
|
|
167307
|
+
const inputDisabled = loading || interactionLocked || session === void 0 || profileUserId === void 0;
|
|
168476
167308
|
const insertEmoji = (0, react$1.useCallback)((emoji) => {
|
|
168477
167309
|
if (inputDisabled || composerDraftKey === void 0) return false;
|
|
168478
167310
|
const result = textareaRef.current?.insertEmoji(emoji);
|
|
168479
167311
|
if (result === "length-limit") setError("内容长度已达上限,请删减后再添加表情");
|
|
168480
167312
|
return result === "inserted";
|
|
168481
167313
|
}, [composerDraftKey, inputDisabled]);
|
|
167314
|
+
const send = (0, react$1.useCallback)(async (presetText) => {
|
|
167315
|
+
const text = (presetText ?? serializeArkmeComposerDraft(arkmeComposerDraftStore.get(composerDraftKey)).text).trim();
|
|
167316
|
+
if (text === "" || sendInFlightRef.current || sendDisabled || session === void 0 || profileUserId === void 0 || composerDraftKey === void 0) return;
|
|
167317
|
+
if (text.length > arkoQuestionMaxLength) {
|
|
167318
|
+
setError("内容长度超过上限,请删减后再发送");
|
|
167319
|
+
return;
|
|
167320
|
+
}
|
|
167321
|
+
sendInFlightRef.current = true;
|
|
167322
|
+
try {
|
|
167323
|
+
const continuation = latestContinuation(messages, session.sessionId);
|
|
167324
|
+
const createdAtMillis = Date.now();
|
|
167325
|
+
const turn = {
|
|
167326
|
+
userId: profileUserId,
|
|
167327
|
+
sessionId: session.sessionId,
|
|
167328
|
+
clientTurnUid: crypto.randomUUID(),
|
|
167329
|
+
text,
|
|
167330
|
+
createdAtMillis,
|
|
167331
|
+
localUserMessageId: crypto.randomUUID(),
|
|
167332
|
+
localAssistantMessageId: crypto.randomUUID(),
|
|
167333
|
+
...continuation === void 0 ? { ...catalog === void 0 ? {} : { modelRouteKey: catalog.effectiveRouteKey } } : {
|
|
167334
|
+
replyToRunUid: continuation.runUid,
|
|
167335
|
+
replyToAssistantMsgId: continuation.assistantMsgId
|
|
167336
|
+
}
|
|
167337
|
+
};
|
|
167338
|
+
writeArkoPendingTurn(turn);
|
|
167339
|
+
pendingComposerFocusRef.current = true;
|
|
167340
|
+
setPendingTurn(turn);
|
|
167341
|
+
if (presetText === void 0) arkmeComposerDraftStore.clear(composerDraftKey);
|
|
167342
|
+
setMessages((current) => [
|
|
167343
|
+
...current,
|
|
167344
|
+
{
|
|
167345
|
+
id: turn.localUserMessageId,
|
|
167346
|
+
sessionId: turn.sessionId,
|
|
167347
|
+
role: "user",
|
|
167348
|
+
text,
|
|
167349
|
+
status: "done",
|
|
167350
|
+
createdAtMillis
|
|
167351
|
+
},
|
|
167352
|
+
{
|
|
167353
|
+
id: turn.localAssistantMessageId,
|
|
167354
|
+
sessionId: turn.sessionId,
|
|
167355
|
+
role: "assistant",
|
|
167356
|
+
text: "",
|
|
167357
|
+
status: "sending",
|
|
167358
|
+
runStatus: "accepted",
|
|
167359
|
+
createdAtMillis: createdAtMillis + 1
|
|
167360
|
+
}
|
|
167361
|
+
]);
|
|
167362
|
+
scrollToBottom();
|
|
167363
|
+
await submitTurn(turn);
|
|
167364
|
+
} finally {
|
|
167365
|
+
sendInFlightRef.current = false;
|
|
167366
|
+
}
|
|
167367
|
+
}, [
|
|
167368
|
+
catalog,
|
|
167369
|
+
composerDraftKey,
|
|
167370
|
+
messages,
|
|
167371
|
+
profileUserId,
|
|
167372
|
+
scrollToBottom,
|
|
167373
|
+
sendDisabled,
|
|
167374
|
+
session,
|
|
167375
|
+
submitTurn
|
|
167376
|
+
]);
|
|
167377
|
+
const selectModel = (0, react$1.useCallback)(async (routeKey) => {
|
|
167378
|
+
if (selectingModel) return;
|
|
167379
|
+
setSelectingModel(true);
|
|
167380
|
+
setError("");
|
|
167381
|
+
try {
|
|
167382
|
+
const next = await callArkme("arko.model.activate", { routeKey });
|
|
167383
|
+
setCatalog(next);
|
|
167384
|
+
setModelDialogOpen(false);
|
|
167385
|
+
setNotice(tr$1("已切换到 {v0}", { v0: selectedModelName(next) }));
|
|
167386
|
+
} catch (caught) {
|
|
167387
|
+
setError(errorMessage$7(caught));
|
|
167388
|
+
} finally {
|
|
167389
|
+
setSelectingModel(false);
|
|
167390
|
+
}
|
|
167391
|
+
}, [selectingModel]);
|
|
167392
|
+
const cancelActiveRun = (0, react$1.useCallback)(async () => {
|
|
167393
|
+
if (activeRun === void 0 || cancelling) return;
|
|
167394
|
+
setCancelling(true);
|
|
167395
|
+
setError("");
|
|
167396
|
+
try {
|
|
167397
|
+
await callArkme("arko.cancel", {
|
|
167398
|
+
sessionId: activeRun.sessionId,
|
|
167399
|
+
assistantMsgId: activeRun.assistantMsgId,
|
|
167400
|
+
runUid: activeRun.runUid
|
|
167401
|
+
});
|
|
167402
|
+
setNotice("已请求停止当前任务,正在确认最终状态");
|
|
167403
|
+
} catch (caught) {
|
|
167404
|
+
setError(tr$1("停止 Arko 任务失败:{v0}", { v0: errorMessage$7(caught) }));
|
|
167405
|
+
} finally {
|
|
167406
|
+
setCancelling(false);
|
|
167407
|
+
}
|
|
167408
|
+
}, [activeRun, cancelling]);
|
|
167409
|
+
const clearContext = (0, react$1.useCallback)(async () => {
|
|
167410
|
+
if (sending || clearing || pendingTurn !== void 0) return;
|
|
167411
|
+
setClearConfirmOpen(false);
|
|
167412
|
+
setClearing(true);
|
|
167413
|
+
setError("");
|
|
167414
|
+
setNotice("");
|
|
167415
|
+
try {
|
|
167416
|
+
const nextSession = await callArkme("arko.new-session");
|
|
167417
|
+
setSession(nextSession);
|
|
167418
|
+
setMessages((current) => [...current, {
|
|
167419
|
+
id: crypto.randomUUID(),
|
|
167420
|
+
role: "divider",
|
|
167421
|
+
text: "新的对话",
|
|
167422
|
+
status: "done",
|
|
167423
|
+
createdAtMillis: Date.now()
|
|
167424
|
+
}]);
|
|
167425
|
+
scrollToBottom();
|
|
167426
|
+
setNotice("上下文已清除,历史记录仍然保留");
|
|
167427
|
+
} catch (caught) {
|
|
167428
|
+
setError(errorMessage$7(caught));
|
|
167429
|
+
} finally {
|
|
167430
|
+
setClearing(false);
|
|
167431
|
+
}
|
|
167432
|
+
}, [
|
|
167433
|
+
clearing,
|
|
167434
|
+
pendingTurn,
|
|
167435
|
+
scrollToBottom,
|
|
167436
|
+
sending
|
|
167437
|
+
]);
|
|
167438
|
+
const displayName = arkoPresentationName(profile);
|
|
167439
|
+
const selectedModel = selectedModelName(catalog);
|
|
167440
|
+
const canChooseModel = (catalog?.options.length ?? 0) > 1;
|
|
167441
|
+
const continuation = (0, react$1.useMemo)(() => latestContinuation(messages, session?.sessionId), [messages, session?.sessionId]);
|
|
168482
167442
|
(0, react$1.useEffect)(() => {
|
|
168483
167443
|
if (!pendingComposerFocusRef.current || loading || interactionLocked || session === void 0 || profileUserId === void 0) return;
|
|
168484
167444
|
pendingComposerFocusRef.current = false;
|
|
@@ -168601,23 +167561,6 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168601
167561
|
"data-arko-message-viewport": true,
|
|
168602
167562
|
style: styles$24.body,
|
|
168603
167563
|
children: [
|
|
168604
|
-
historyPageError && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
168605
|
-
role: "alert",
|
|
168606
|
-
style: {
|
|
168607
|
-
...styles$24.error,
|
|
168608
|
-
...styles$24.feedbackRow
|
|
168609
|
-
},
|
|
168610
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: historyPageError }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
168611
|
-
"data-arkme-feedback": "neutral",
|
|
168612
|
-
type: "button",
|
|
168613
|
-
style: styles$24.retryButton,
|
|
168614
|
-
disabled: historyLoading,
|
|
168615
|
-
onClick: () => {
|
|
168616
|
-
loadEarlier();
|
|
168617
|
-
},
|
|
168618
|
-
children: tr$1("重试加载更早记录")
|
|
168619
|
-
})]
|
|
168620
|
-
}),
|
|
168621
167564
|
notice !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
168622
167565
|
style: styles$24.notice,
|
|
168623
167566
|
children: notice
|
|
@@ -168637,7 +167580,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168637
167580
|
style: styles$24.retryButton,
|
|
168638
167581
|
disabled: historyLoading,
|
|
168639
167582
|
onClick: () => {
|
|
168640
|
-
if (
|
|
167583
|
+
if (historyOffset === void 0) retryHistory();
|
|
168641
167584
|
else loadEarlier();
|
|
168642
167585
|
},
|
|
168643
167586
|
children: historyLoading ? tr$1("加载中...") : tr$1("重新加载")
|
|
@@ -169120,89 +168063,6 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
169120
168063
|
})]
|
|
169121
168064
|
});
|
|
169122
168065
|
}
|
|
169123
|
-
function ArkoNativeConversation({ controller }) {
|
|
169124
|
-
const { accountKey, session, catalog, messages, loading, sending, activeRun, draft, error, historyError, notice, historyOffset, historyPageError, inputDisabled, sendDisabled, selectModel, cancelActiveRun, loadEarlier, pendingTurn, submitTurn, retryHistory, setDraft, feedback: setError, send, displayName, clearing, selectingModel, continuation } = controller;
|
|
169125
|
-
const [clearConfirmOpen, setClearConfirmOpen] = (0, react$1.useState)(false);
|
|
169126
|
-
const clearContext = async () => {
|
|
169127
|
-
setClearConfirmOpen(false);
|
|
169128
|
-
await controller.clearContext();
|
|
169129
|
-
};
|
|
169130
|
-
const hint = loading ? "正在恢复会话" : clearing ? "正在清除上下文" : selectingModel ? "正在切换模型" : pendingTurn !== void 0 && !sending ? "请先确认上一次发送结果" : sending ? "等待回复" : continuation === void 0 ? "" : "继续当前任务";
|
|
169131
|
-
if (accountKey === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
169132
|
-
role: "status",
|
|
169133
|
-
children: "正在恢复账号…"
|
|
169134
|
-
});
|
|
169135
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkoNativeSurface, {
|
|
169136
|
-
snapshot: {
|
|
169137
|
-
accountKey,
|
|
169138
|
-
displayName,
|
|
169139
|
-
...session ? { sessionId: session.sessionId } : {},
|
|
169140
|
-
messages,
|
|
169141
|
-
modelCatalog: catalog ?? null,
|
|
169142
|
-
loading,
|
|
169143
|
-
busy: sending || activeRun !== void 0,
|
|
169144
|
-
draft,
|
|
169145
|
-
error: error || historyError,
|
|
169146
|
-
notice: notice || hint,
|
|
169147
|
-
hasMore: typeof historyOffset === "number",
|
|
169148
|
-
historyError: historyPageError,
|
|
169149
|
-
...inputDisabled && activeRun === void 0 ? { inputBlockedReason: hint || "当前输入暂不可用" } : {}
|
|
169150
|
-
},
|
|
169151
|
-
actions: {
|
|
169152
|
-
submit: async (text) => {
|
|
169153
|
-
if (sendDisabled || text.trim() === "" || text.length > 61440) return false;
|
|
169154
|
-
setDraft(text);
|
|
169155
|
-
return await send() === true;
|
|
169156
|
-
},
|
|
169157
|
-
selectModel,
|
|
169158
|
-
cancel: cancelActiveRun,
|
|
169159
|
-
loadEarlier
|
|
169160
|
-
},
|
|
169161
|
-
ui: {
|
|
169162
|
-
clearDisabled: sendDisabled,
|
|
169163
|
-
setDraft: (text) => setDraft(text),
|
|
169164
|
-
clearContext: () => setClearConfirmOpen(true),
|
|
169165
|
-
retry: async () => {
|
|
169166
|
-
if (pendingTurn) await submitTurn(pendingTurn);
|
|
169167
|
-
else await retryHistory();
|
|
169168
|
-
},
|
|
169169
|
-
...pendingTurn ? { retryLabel: "重试确认" } : historyError ? { retryLabel: "重试加载记录" } : {},
|
|
169170
|
-
feedback: setError
|
|
169171
|
-
}
|
|
169172
|
-
}), clearConfirmOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
169173
|
-
role: "dialog",
|
|
169174
|
-
"aria-label": "清除上下文",
|
|
169175
|
-
style: {
|
|
169176
|
-
position: "absolute",
|
|
169177
|
-
inset: 0,
|
|
169178
|
-
zIndex: 30,
|
|
169179
|
-
display: "grid",
|
|
169180
|
-
placeItems: "center",
|
|
169181
|
-
background: "#0004"
|
|
169182
|
-
},
|
|
169183
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
169184
|
-
style: {
|
|
169185
|
-
background: arkmeTheme.base,
|
|
169186
|
-
padding: 24,
|
|
169187
|
-
borderRadius: 12
|
|
169188
|
-
},
|
|
169189
|
-
children: [
|
|
169190
|
-
"清除当前上下文?历史记录仍然保留。",
|
|
169191
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
169192
|
-
onClick: () => setClearConfirmOpen(false),
|
|
169193
|
-
children: "取消"
|
|
169194
|
-
}),
|
|
169195
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
169196
|
-
disabled: sendDisabled,
|
|
169197
|
-
onClick: () => {
|
|
169198
|
-
clearContext();
|
|
169199
|
-
},
|
|
169200
|
-
children: "确认清除"
|
|
169201
|
-
})
|
|
169202
|
-
]
|
|
169203
|
-
})
|
|
169204
|
-
})] });
|
|
169205
|
-
}
|
|
169206
168066
|
//#endregion
|
|
169207
168067
|
//#region src/client/ArkmePrivateCallMenu.tsx
|
|
169208
168068
|
const maskStyle = {
|
|
@@ -201413,7 +200273,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
201413
200273
|
const c$3 = e$24;
|
|
201414
200274
|
//#endregion
|
|
201415
200275
|
//#region package.json
|
|
201416
|
-
var version = "0.1.
|
|
200276
|
+
var version = "0.1.74";
|
|
201417
200277
|
//#endregion
|
|
201418
200278
|
//#region src/client/profile-change-store.ts
|
|
201419
200279
|
let revision = 0;
|
|
@@ -222334,7 +221194,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
222334
221194
|
onPrivateChatOpened: activateSource
|
|
222335
221195
|
}) : ui.mode === "voiceprint" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeVoiceprintSurface, { onBack: () => {
|
|
222336
221196
|
arkmeUi.showRecordings();
|
|
222337
|
-
} }) : ui.mode === "arko" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeArkoSurface, {
|
|
221197
|
+
} }) : ui.mode === "arko" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeArkoSurface, {}, arkmeArkoSurfaceKey(auth)) : botConversationVisible && ui.selectedBot !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeBotConversationSurface, {
|
|
222338
221198
|
bot: ui.selectedBot,
|
|
222339
221199
|
onConversationActivity: (bot) => {
|
|
222340
221200
|
arkmeUi.openBotConversation(bot);
|
|
@@ -236865,29 +235725,6 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
|
|
|
236865
235725
|
};
|
|
236866
235726
|
}
|
|
236867
235727
|
//#endregion
|
|
236868
|
-
//#region src/client/ArkmeArkoPanel.tsx
|
|
236869
|
-
/** The workspace keys this single retained panel by authenticated account scope. */
|
|
236870
|
-
function ArkmeArkoPanel({ visible }) {
|
|
236871
|
-
const [visited, setVisited] = (0, react$1.useState)(false);
|
|
236872
|
-
(0, react$1.useEffect)(() => {
|
|
236873
|
-
if (visible) setVisited(true);
|
|
236874
|
-
}, [visible]);
|
|
236875
|
-
if (!visible && !visited) return null;
|
|
236876
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
236877
|
-
"data-arkme-owned": "arko-panel",
|
|
236878
|
-
"aria-hidden": !visible || void 0,
|
|
236879
|
-
...!visible ? { inert: "" } : {},
|
|
236880
|
-
style: {
|
|
236881
|
-
position: "absolute",
|
|
236882
|
-
inset: 0,
|
|
236883
|
-
visibility: visible ? "visible" : "hidden",
|
|
236884
|
-
pointerEvents: visible ? "auto" : "none",
|
|
236885
|
-
zIndex: visible ? 1 : 0
|
|
236886
|
-
},
|
|
236887
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeArkoSurface, { native: true })
|
|
236888
|
-
});
|
|
236889
|
-
}
|
|
236890
|
-
//#endregion
|
|
236891
235728
|
//#region src/client/redesign/contacts/ContactDirectoryAddDialog.tsx
|
|
236892
235729
|
const styles$4 = {
|
|
236893
235730
|
backdrop: {
|
|
@@ -240893,8 +239730,7 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
|
|
|
240893
239730
|
const contactsMode = ui.mode === "source" && ui.productMode === "contacts";
|
|
240894
239731
|
const webLockedHarness = !startupAuthGateEnabled() && authState.auth?.status !== "authenticated";
|
|
240895
239732
|
const harnessVisible = ui.mode === "harness" || webLockedHarness;
|
|
240896
|
-
const
|
|
240897
|
-
const conversationHidden = harnessVisible || contactsMode || arkoVisible;
|
|
239733
|
+
const conversationHidden = harnessVisible || contactsMode;
|
|
240898
239734
|
const conversationActive = !conversationHidden && ui.calendarOpen !== true;
|
|
240899
239735
|
const contactsContextRef = (0, react$1.useRef)({
|
|
240900
239736
|
accountKey: contactsAccountKey,
|
|
@@ -240927,7 +239763,6 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
|
|
|
240927
239763
|
accountScope: contactsAccountKey,
|
|
240928
239764
|
followSession: ui.mode === "harness"
|
|
240929
239765
|
}, contactsAccountKey ?? "guest"),
|
|
240930
|
-
contactsAccountKey !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeArkoPanel, { visible: arkoVisible }, contactsAccountKey),
|
|
240931
239766
|
!webLockedHarness && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
240932
239767
|
"data-arkme-owned": "arkme-conversation-layer",
|
|
240933
239768
|
style: {
|