@senguoyun/dsh-arkme 0.1.73 → 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/lib/client.js +659 -1828
- package/lib/client.js.map +1 -1
- 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/ArkmePersistentShell.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 -6079
- 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
|
/**
|
|
@@ -146353,7 +146353,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
146353
146353
|
* Wrap `React.useLayoutEffect` which will not throw warning message in test env
|
|
146354
146354
|
*/
|
|
146355
146355
|
const useInternalLayoutEffect = canUseDom() ? react.useLayoutEffect : react.useEffect;
|
|
146356
|
-
const useLayoutEffect$
|
|
146356
|
+
const useLayoutEffect$21 = (callback, deps) => {
|
|
146357
146357
|
const firstMountRef = react.useRef(true);
|
|
146358
146358
|
useInternalLayoutEffect(() => {
|
|
146359
146359
|
return callback(firstMountRef.current);
|
|
@@ -146397,7 +146397,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
146397
146397
|
function useControlledState(defaultStateValue, value) {
|
|
146398
146398
|
const [innerValue, setInnerValue] = (0, react.useState)(defaultStateValue);
|
|
146399
146399
|
const mergedValue = value !== void 0 ? value : innerValue;
|
|
146400
|
-
useLayoutEffect$
|
|
146400
|
+
useLayoutEffect$21((mount) => {
|
|
146401
146401
|
if (!mount) setInnerValue(value);
|
|
146402
146402
|
}, [value]);
|
|
146403
146403
|
return [mergedValue, setInnerValue];
|
|
@@ -146460,7 +146460,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
146460
146460
|
};
|
|
146461
146461
|
//#endregion
|
|
146462
146462
|
//#region node_modules/@rc-component/util/es/hooks/useMemo.js
|
|
146463
|
-
function useMemo$
|
|
146463
|
+
function useMemo$31(getValue, condition, shouldUpdate) {
|
|
146464
146464
|
const cacheRef = react.useRef({});
|
|
146465
146465
|
if (!("value" in cacheRef.current) || shouldUpdate(cacheRef.current.condition, condition)) {
|
|
146466
146466
|
cacheRef.current.value = getValue();
|
|
@@ -146573,7 +146573,7 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
|
|
|
146573
146573
|
};
|
|
146574
146574
|
};
|
|
146575
146575
|
const useComposeRef = (...refs) => {
|
|
146576
|
-
return useMemo$
|
|
146576
|
+
return useMemo$31(() => composeRef(...refs), refs, (prev, next) => prev.length !== next.length || prev.every((ref, i) => ref !== next[i]));
|
|
146577
146577
|
};
|
|
146578
146578
|
const supportRef = (nodeOrComponent) => {
|
|
146579
146579
|
if (!nodeOrComponent) return false;
|
|
@@ -147463,13 +147463,13 @@ ${height ? `height: ${webkitScrollbarStyle.height};` : ""}
|
|
|
147463
147463
|
ele.parentElement?.removeChild(ele);
|
|
147464
147464
|
appendedRef.current = false;
|
|
147465
147465
|
}
|
|
147466
|
-
useLayoutEffect$
|
|
147466
|
+
useLayoutEffect$21(() => {
|
|
147467
147467
|
if (render) if (queueCreate) queueCreate(append);
|
|
147468
147468
|
else append();
|
|
147469
147469
|
else cleanup();
|
|
147470
147470
|
return cleanup;
|
|
147471
147471
|
}, [render]);
|
|
147472
|
-
useLayoutEffect$
|
|
147472
|
+
useLayoutEffect$21(() => {
|
|
147473
147473
|
if (queue.length) {
|
|
147474
147474
|
queue.forEach((appendFn) => appendFn());
|
|
147475
147475
|
setQueue(EMPTY_LIST);
|
|
@@ -147495,7 +147495,7 @@ ${height ? `height: ${webkitScrollbarStyle.height};` : ""}
|
|
|
147495
147495
|
uuid$1 += 1;
|
|
147496
147496
|
return `${UNIQUE_ID}_${uuid$1}`;
|
|
147497
147497
|
});
|
|
147498
|
-
useLayoutEffect$
|
|
147498
|
+
useLayoutEffect$21(() => {
|
|
147499
147499
|
if (mergedLock) {
|
|
147500
147500
|
const scrollbarSize = getTargetScrollBarSize(document.body).width;
|
|
147501
147501
|
updateCSS(`
|
|
@@ -148438,7 +148438,7 @@ html body {
|
|
|
148438
148438
|
]);
|
|
148439
148439
|
const getPopupContainerNeedParams = getPopupContainer?.length > 0;
|
|
148440
148440
|
const [show, setShow] = react.useState(!getPopupContainer || !getPopupContainerNeedParams);
|
|
148441
|
-
useLayoutEffect$
|
|
148441
|
+
useLayoutEffect$21(() => {
|
|
148442
148442
|
if (!show && getPopupContainerNeedParams && target) setShow(true);
|
|
148443
148443
|
}, [
|
|
148444
148444
|
show,
|
|
@@ -148990,8 +148990,8 @@ html body {
|
|
|
148990
148990
|
ready: false
|
|
148991
148991
|
}));
|
|
148992
148992
|
};
|
|
148993
|
-
useLayoutEffect$
|
|
148994
|
-
useLayoutEffect$
|
|
148993
|
+
useLayoutEffect$21(resetReady, [placement]);
|
|
148994
|
+
useLayoutEffect$21(() => {
|
|
148995
148995
|
if (!open) resetReady();
|
|
148996
148996
|
}, [open]);
|
|
148997
148997
|
return [
|
|
@@ -149035,7 +149035,7 @@ html body {
|
|
|
149035
149035
|
//#endregion
|
|
149036
149036
|
//#region node_modules/@rc-component/trigger/es/hooks/useWatch.js
|
|
149037
149037
|
function useWatch(open, target, popup, onAlign, onScroll) {
|
|
149038
|
-
useLayoutEffect$
|
|
149038
|
+
useLayoutEffect$21(() => {
|
|
149039
149039
|
if (open && target && popup) {
|
|
149040
149040
|
const targetElement = target;
|
|
149041
149041
|
const popupElement = popup;
|
|
@@ -149190,7 +149190,7 @@ html body {
|
|
|
149190
149190
|
id,
|
|
149191
149191
|
onEsc
|
|
149192
149192
|
}));
|
|
149193
|
-
useLayoutEffect$
|
|
149193
|
+
useLayoutEffect$21(() => {
|
|
149194
149194
|
if (uniqueContext && unique && targetEle && !openUncontrolled && !parentContext) if (mergedOpen) uniqueContext.show(getUniqueOptions(mouseEnterDelay), isOpen);
|
|
149195
149195
|
else uniqueContext.hide(mouseLeaveDelay);
|
|
149196
149196
|
}, [mergedOpen, targetEle]);
|
|
@@ -149226,7 +149226,7 @@ html body {
|
|
|
149226
149226
|
if (top) triggerOpen(false);
|
|
149227
149227
|
}
|
|
149228
149228
|
const [inMotion, setInMotion] = react.useState(false);
|
|
149229
|
-
useLayoutEffect$
|
|
149229
|
+
useLayoutEffect$21((firstMount) => {
|
|
149230
149230
|
if (!firstMount || mergedOpen) setInMotion(true);
|
|
149231
149231
|
}, [mergedOpen]);
|
|
149232
149232
|
const [motionPrepareResolve, setMotionPrepareResolve] = react.useState(null);
|
|
@@ -149245,10 +149245,10 @@ html body {
|
|
|
149245
149245
|
if (openRef.current && alignPoint && clickToHide) triggerOpen(false);
|
|
149246
149246
|
};
|
|
149247
149247
|
useWatch(mergedOpen, targetEle, popupEle, triggerAlign, onScroll);
|
|
149248
|
-
useLayoutEffect$
|
|
149248
|
+
useLayoutEffect$21(() => {
|
|
149249
149249
|
triggerAlign();
|
|
149250
149250
|
}, [mousePos, popupPlacement]);
|
|
149251
|
-
useLayoutEffect$
|
|
149251
|
+
useLayoutEffect$21(() => {
|
|
149252
149252
|
if (mergedOpen && !builtinPlacements?.[popupPlacement]) triggerAlign();
|
|
149253
149253
|
}, [JSON.stringify(popupAlign)]);
|
|
149254
149254
|
const alignedClassName = react.useMemo(() => {
|
|
@@ -149288,7 +149288,7 @@ html body {
|
|
|
149288
149288
|
syncTargetSize();
|
|
149289
149289
|
setMotionPrepareResolve(() => resolve);
|
|
149290
149290
|
});
|
|
149291
|
-
useLayoutEffect$
|
|
149291
|
+
useLayoutEffect$21(() => {
|
|
149292
149292
|
if (motionPrepareResolve) {
|
|
149293
149293
|
onAlign();
|
|
149294
149294
|
motionPrepareResolve();
|
|
@@ -149495,7 +149495,7 @@ html body {
|
|
|
149495
149495
|
}
|
|
149496
149496
|
function useTarget(target, open, gap, scrollIntoViewOptions, inlineMode, placeholderRef) {
|
|
149497
149497
|
const [targetElement, setTargetElement] = (0, react.useState)(void 0);
|
|
149498
|
-
useLayoutEffect$
|
|
149498
|
+
useLayoutEffect$21(() => {
|
|
149499
149499
|
const nextElement = typeof target === "function" ? target() : target;
|
|
149500
149500
|
setTargetElement(nextElement || null);
|
|
149501
149501
|
});
|
|
@@ -149525,7 +149525,7 @@ html body {
|
|
|
149525
149525
|
} else setPosInfo(null);
|
|
149526
149526
|
});
|
|
149527
149527
|
const getGapOffset = (index) => (Array.isArray(gap?.offset) ? gap?.offset[index] : gap?.offset) ?? 6;
|
|
149528
|
-
useLayoutEffect$
|
|
149528
|
+
useLayoutEffect$21(() => {
|
|
149529
149529
|
updatePos();
|
|
149530
149530
|
window.addEventListener("resize", updatePos);
|
|
149531
149531
|
window.addEventListener("scroll", updatePos);
|
|
@@ -149815,7 +149815,7 @@ html body {
|
|
|
149815
149815
|
const mergedOpen = mergedCurrent < 0 || mergedCurrent >= steps.length ? false : internalOpen ?? true;
|
|
149816
149816
|
const [hasOpened, setHasOpened] = react.useState(mergedOpen);
|
|
149817
149817
|
const openRef = react.useRef(mergedOpen);
|
|
149818
|
-
useLayoutEffect$
|
|
149818
|
+
useLayoutEffect$21(() => {
|
|
149819
149819
|
if (mergedOpen) {
|
|
149820
149820
|
if (!openRef.current) setMergedCurrent(0);
|
|
149821
149821
|
setHasOpened(true);
|
|
@@ -149832,7 +149832,7 @@ html body {
|
|
|
149832
149832
|
const mergedPlacement = getPlacement(targetElement, placement, stepPlacement);
|
|
149833
149833
|
const mergedArrow = targetElement ? typeof stepArrow === "undefined" ? arrow : stepArrow : false;
|
|
149834
149834
|
const arrowPointAtCenter = typeof mergedArrow === "object" ? mergedArrow.pointAtCenter : false;
|
|
149835
|
-
useLayoutEffect$
|
|
149835
|
+
useLayoutEffect$21(() => {
|
|
149836
149836
|
triggerRef.current?.forceAlign();
|
|
149837
149837
|
}, [arrowPointAtCenter, mergedCurrent]);
|
|
149838
149838
|
const onInternalChange = (nextCurrent) => {
|
|
@@ -149870,7 +149870,7 @@ html body {
|
|
|
149870
149870
|
return;
|
|
149871
149871
|
}
|
|
149872
149872
|
});
|
|
149873
|
-
useLayoutEffect$
|
|
149873
|
+
useLayoutEffect$21(() => {
|
|
149874
149874
|
if (!mergedOpen) return;
|
|
149875
149875
|
window.addEventListener("keydown", keyboardHandler);
|
|
149876
149876
|
return () => {
|
|
@@ -163490,1642 +163490,6 @@ html body {
|
|
|
163490
163490
|
});
|
|
163491
163491
|
}
|
|
163492
163492
|
//#endregion
|
|
163493
|
-
//#region src/client/arko-native-transport.ts
|
|
163494
|
-
function record(value) {
|
|
163495
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
163496
|
-
}
|
|
163497
|
-
function requestOf(payload) {
|
|
163498
|
-
return record(record(record(payload).args).request);
|
|
163499
|
-
}
|
|
163500
|
-
function messageKey(message) {
|
|
163501
|
-
return message.presentationKey ?? (message.messageId === void 0 ? message.id : `arko:${String(message.sessionId ?? "")}:${String(message.messageId)}`);
|
|
163502
|
-
}
|
|
163503
|
-
function renderContent(message) {
|
|
163504
|
-
return [...message.reasoning ? [{
|
|
163505
|
-
type: "reasoning",
|
|
163506
|
-
text: message.reasoning
|
|
163507
|
-
}] : [], {
|
|
163508
|
-
type: "text",
|
|
163509
|
-
text: message.text
|
|
163510
|
-
}];
|
|
163511
|
-
}
|
|
163512
|
-
function endReason(message) {
|
|
163513
|
-
if (message.status === "error" || message.runStatus === "failed") return {
|
|
163514
|
-
kind: "error",
|
|
163515
|
-
error: {
|
|
163516
|
-
code: "ARKO_RUN_FAILED",
|
|
163517
|
-
message: message.text || "Arko 运行失败"
|
|
163518
|
-
}
|
|
163519
|
-
};
|
|
163520
|
-
if (message.runStatus === "cancelled") return {
|
|
163521
|
-
kind: "aborted",
|
|
163522
|
-
reason: { kind: "user" }
|
|
163523
|
-
};
|
|
163524
|
-
if (message.runStatus === "waiting_user") return { kind: "blocked" };
|
|
163525
|
-
if (message.runStatus === "expired" || message.runStatus === "partial") return { kind: "interrupted" };
|
|
163526
|
-
return { kind: "completed" };
|
|
163527
|
-
}
|
|
163528
|
-
const ok = (value) => ({
|
|
163529
|
-
ok: true,
|
|
163530
|
-
value
|
|
163531
|
-
});
|
|
163532
|
-
const denied = (message, code = "gateway/bad-request") => ({
|
|
163533
|
-
ok: false,
|
|
163534
|
-
error: {
|
|
163535
|
-
code,
|
|
163536
|
-
message,
|
|
163537
|
-
details: {}
|
|
163538
|
-
}
|
|
163539
|
-
});
|
|
163540
|
-
/**
|
|
163541
|
-
* Render-only protocol adapter. Snapshots and admitted actions remain owned by
|
|
163542
|
-
* ArkmeArkoSurface; this object owns only DSH cursor/identity presentation data.
|
|
163543
|
-
* Unsupported calls never reach the host transport or any Arkme API.
|
|
163544
|
-
*/
|
|
163545
|
-
function createArkoNativeTransport(initial, initialActions) {
|
|
163546
|
-
let snapshot = initial;
|
|
163547
|
-
let actions = initialActions;
|
|
163548
|
-
const accountKey = initial.accountKey;
|
|
163549
|
-
const sessionId = `arko-native-${crypto.randomUUID()}`;
|
|
163550
|
-
const createdAt = Date.now();
|
|
163551
|
-
let disposed = false;
|
|
163552
|
-
let historyRevision = 0;
|
|
163553
|
-
let submitting = false;
|
|
163554
|
-
let changingModel = false;
|
|
163555
|
-
let pendingPrompt;
|
|
163556
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
163557
|
-
const streams = /* @__PURE__ */ new Set();
|
|
163558
|
-
const sequenceOrigin = 2 ** 40;
|
|
163559
|
-
let nextSeq = sequenceOrigin;
|
|
163560
|
-
let pageRequest;
|
|
163561
|
-
let journal = [];
|
|
163562
|
-
let projected = [];
|
|
163563
|
-
let turn = 0;
|
|
163564
|
-
let assistantRevision = 0;
|
|
163565
|
-
let activeAssistant;
|
|
163566
|
-
function emit(endpoint, value) {
|
|
163567
|
-
for (const stream of streams) if (stream.endpoint === endpoint && (endpoint !== "session/follow" || stream.historyRevision === historyRevision)) stream.push(value);
|
|
163568
|
-
}
|
|
163569
|
-
function append(type, data, message, surfaceOp) {
|
|
163570
|
-
const event = {
|
|
163571
|
-
type,
|
|
163572
|
-
seq: nextSeq++,
|
|
163573
|
-
time: Math.max(0, Math.trunc(message.createdAtMillis ?? createdAt)),
|
|
163574
|
-
data,
|
|
163575
|
-
...surfaceOp === void 0 ? {} : { surfaceOp },
|
|
163576
|
-
...type.startsWith("arko/") ? { ignorable: true } : {}
|
|
163577
|
-
};
|
|
163578
|
-
const entry = {
|
|
163579
|
-
type: "event",
|
|
163580
|
-
event
|
|
163581
|
-
};
|
|
163582
|
-
journal.push(entry);
|
|
163583
|
-
emit("session/follow", entry);
|
|
163584
|
-
return event.seq;
|
|
163585
|
-
}
|
|
163586
|
-
function appendMessage(row) {
|
|
163587
|
-
const { message, key, rpcId } = row;
|
|
163588
|
-
const source = message.role === "user" ? {
|
|
163589
|
-
kind: "user",
|
|
163590
|
-
...rpcId === void 0 ? {} : { rpcId }
|
|
163591
|
-
} : message.role === "divider" ? {
|
|
163592
|
-
kind: "plugin",
|
|
163593
|
-
plugin: "arko",
|
|
163594
|
-
form: "notice",
|
|
163595
|
-
summary: message.text
|
|
163596
|
-
} : {
|
|
163597
|
-
kind: "model",
|
|
163598
|
-
provider: "arko",
|
|
163599
|
-
model: "unspecified"
|
|
163600
|
-
};
|
|
163601
|
-
const wire = {
|
|
163602
|
-
id: key,
|
|
163603
|
-
role: message.role === "assistant" ? "assistant" : "user",
|
|
163604
|
-
source,
|
|
163605
|
-
content: renderContent(message)
|
|
163606
|
-
};
|
|
163607
|
-
row.seq = append(message.role === "assistant" ? "assistant/message" : "user/message", message.role === "assistant" ? {
|
|
163608
|
-
turn: row.turn,
|
|
163609
|
-
step: 1,
|
|
163610
|
-
message: wire,
|
|
163611
|
-
stream: activeAssistant?.attemptId === key ? activeAssistant.stream.slice() : [],
|
|
163612
|
-
...[
|
|
163613
|
-
"cancelled",
|
|
163614
|
-
"partial",
|
|
163615
|
-
"expired"
|
|
163616
|
-
].includes(message.runStatus ?? "") ? { interrupted: true } : {}
|
|
163617
|
-
} : wire, message, "append");
|
|
163618
|
-
}
|
|
163619
|
-
function assistantFrame(frame) {
|
|
163620
|
-
emit("session/follow", {
|
|
163621
|
-
type: "assistant-stream",
|
|
163622
|
-
frame: {
|
|
163623
|
-
...frame,
|
|
163624
|
-
revision: ++assistantRevision
|
|
163625
|
-
}
|
|
163626
|
-
});
|
|
163627
|
-
}
|
|
163628
|
-
function assistantChunk(chunk, message) {
|
|
163629
|
-
if (activeAssistant === void 0) return;
|
|
163630
|
-
const time = Math.max(0, Math.trunc(message.createdAtMillis ?? createdAt));
|
|
163631
|
-
const index = activeAssistant.nextIndex++;
|
|
163632
|
-
activeAssistant.stream.push({
|
|
163633
|
-
type: "chunk",
|
|
163634
|
-
time,
|
|
163635
|
-
chunk
|
|
163636
|
-
});
|
|
163637
|
-
assistantFrame({
|
|
163638
|
-
type: "chunk",
|
|
163639
|
-
attemptId: activeAssistant.attemptId,
|
|
163640
|
-
index,
|
|
163641
|
-
time,
|
|
163642
|
-
chunk
|
|
163643
|
-
});
|
|
163644
|
-
}
|
|
163645
|
-
function streamMessage(row, previous) {
|
|
163646
|
-
if (activeAssistant?.attemptId !== row.key) {
|
|
163647
|
-
activeAssistant = {
|
|
163648
|
-
attemptId: row.key,
|
|
163649
|
-
startedAfterSeq: nextSeq - 1,
|
|
163650
|
-
turn: row.turn,
|
|
163651
|
-
step: 1,
|
|
163652
|
-
nextIndex: 0,
|
|
163653
|
-
stream: []
|
|
163654
|
-
};
|
|
163655
|
-
assistantFrame({
|
|
163656
|
-
type: "start",
|
|
163657
|
-
attemptId: row.key,
|
|
163658
|
-
startedAfterSeq: activeAssistant.startedAfterSeq,
|
|
163659
|
-
turn: row.turn,
|
|
163660
|
-
step: 1
|
|
163661
|
-
});
|
|
163662
|
-
}
|
|
163663
|
-
for (const [index, kind] of ["reasoning", "text"].entries()) {
|
|
163664
|
-
const text = kind === "reasoning" ? row.message.reasoning ?? "" : row.message.text;
|
|
163665
|
-
const before = previous === void 0 ? void 0 : kind === "reasoning" ? previous.reasoning ?? "" : previous.text;
|
|
163666
|
-
if (before === void 0 || !text.startsWith(before)) assistantChunk({
|
|
163667
|
-
type: "block-start",
|
|
163668
|
-
index,
|
|
163669
|
-
blockType: kind
|
|
163670
|
-
}, row.message);
|
|
163671
|
-
const delta = before !== void 0 && text.startsWith(before) ? text.slice(before.length) : text;
|
|
163672
|
-
if (delta !== "") assistantChunk({
|
|
163673
|
-
type: `${kind}-delta`,
|
|
163674
|
-
index,
|
|
163675
|
-
text: delta
|
|
163676
|
-
}, row.message);
|
|
163677
|
-
}
|
|
163678
|
-
}
|
|
163679
|
-
function settleAssistant(row) {
|
|
163680
|
-
appendMessage(row);
|
|
163681
|
-
if (activeAssistant?.attemptId === row.key) {
|
|
163682
|
-
assistantFrame({
|
|
163683
|
-
type: "end",
|
|
163684
|
-
attemptId: row.key,
|
|
163685
|
-
index: activeAssistant.nextIndex,
|
|
163686
|
-
outcome: {
|
|
163687
|
-
kind: "committed",
|
|
163688
|
-
eventType: "assistant/message",
|
|
163689
|
-
seq: row.seq
|
|
163690
|
-
}
|
|
163691
|
-
});
|
|
163692
|
-
activeAssistant = void 0;
|
|
163693
|
-
}
|
|
163694
|
-
}
|
|
163695
|
-
function endMessage(row) {
|
|
163696
|
-
if (row.message.role !== "assistant" || row.message.status === "sending" || row.ended) return;
|
|
163697
|
-
append("step/end", {
|
|
163698
|
-
turn: row.turn,
|
|
163699
|
-
step: 1
|
|
163700
|
-
}, row.message);
|
|
163701
|
-
append("turn/end", {
|
|
163702
|
-
turn: row.turn,
|
|
163703
|
-
reason: endReason(row.message)
|
|
163704
|
-
}, row.message);
|
|
163705
|
-
row.ended = true;
|
|
163706
|
-
}
|
|
163707
|
-
function addMessage(message) {
|
|
163708
|
-
if (message.role === "user" || turn === 0 || message.role === "assistant" && projected.at(-1)?.ended === true) {
|
|
163709
|
-
turn++;
|
|
163710
|
-
append("turn/start", { turn }, message);
|
|
163711
|
-
append("step/start", {
|
|
163712
|
-
turn,
|
|
163713
|
-
step: 1
|
|
163714
|
-
}, message);
|
|
163715
|
-
}
|
|
163716
|
-
const row = {
|
|
163717
|
-
message,
|
|
163718
|
-
key: messageKey(message),
|
|
163719
|
-
seq: -1,
|
|
163720
|
-
turn,
|
|
163721
|
-
ended: false
|
|
163722
|
-
};
|
|
163723
|
-
if (message.role === "user" && pendingPrompt !== void 0 && message.text.trim() === pendingPrompt.text) {
|
|
163724
|
-
row.rpcId = pendingPrompt.requestId;
|
|
163725
|
-
pendingPrompt = void 0;
|
|
163726
|
-
}
|
|
163727
|
-
if (message.role === "assistant" && message.status === "sending") streamMessage(row);
|
|
163728
|
-
else appendMessage(row);
|
|
163729
|
-
endMessage(row);
|
|
163730
|
-
projected.push(row);
|
|
163731
|
-
}
|
|
163732
|
-
function historyRecord(message, seq) {
|
|
163733
|
-
const key = messageKey(message);
|
|
163734
|
-
const wire = {
|
|
163735
|
-
id: key,
|
|
163736
|
-
role: message.role === "assistant" ? "assistant" : "user",
|
|
163737
|
-
source: message.role === "assistant" ? {
|
|
163738
|
-
kind: "model",
|
|
163739
|
-
provider: "arko",
|
|
163740
|
-
model: "unspecified"
|
|
163741
|
-
} : message.role === "divider" ? {
|
|
163742
|
-
kind: "plugin",
|
|
163743
|
-
plugin: "arko",
|
|
163744
|
-
form: "notice",
|
|
163745
|
-
summary: message.text
|
|
163746
|
-
} : { kind: "user" },
|
|
163747
|
-
content: renderContent(message)
|
|
163748
|
-
};
|
|
163749
|
-
const presentationTurn = seq + 1;
|
|
163750
|
-
return {
|
|
163751
|
-
entry: {
|
|
163752
|
-
type: "event",
|
|
163753
|
-
event: {
|
|
163754
|
-
type: message.role === "assistant" ? "assistant/message" : "user/message",
|
|
163755
|
-
seq,
|
|
163756
|
-
time: Math.max(0, Math.trunc(message.createdAtMillis ?? createdAt)),
|
|
163757
|
-
surfaceOp: "append",
|
|
163758
|
-
data: message.role === "assistant" ? {
|
|
163759
|
-
turn: presentationTurn,
|
|
163760
|
-
step: 1,
|
|
163761
|
-
message: wire,
|
|
163762
|
-
stream: [],
|
|
163763
|
-
...[
|
|
163764
|
-
"cancelled",
|
|
163765
|
-
"partial",
|
|
163766
|
-
"expired"
|
|
163767
|
-
].includes(message.runStatus ?? "") ? { interrupted: true } : {}
|
|
163768
|
-
} : wire
|
|
163769
|
-
}
|
|
163770
|
-
},
|
|
163771
|
-
row: {
|
|
163772
|
-
message,
|
|
163773
|
-
key,
|
|
163774
|
-
seq,
|
|
163775
|
-
turn: presentationTurn,
|
|
163776
|
-
ended: true
|
|
163777
|
-
}
|
|
163778
|
-
};
|
|
163779
|
-
}
|
|
163780
|
-
function prependHistory(messages) {
|
|
163781
|
-
const known = new Set(projected.map((row) => row.key));
|
|
163782
|
-
const persistedKey = (message) => message.messageId === void 0 ? void 0 : `${message.sessionId}:${message.messageId}`;
|
|
163783
|
-
const persisted = new Set(projected.map((row) => persistedKey(row.message)).filter((key) => key !== void 0));
|
|
163784
|
-
const older = messages.filter((message) => {
|
|
163785
|
-
const key = messageKey(message), identity = persistedKey(message);
|
|
163786
|
-
if (known.has(key) || identity !== void 0 && persisted.has(identity)) return false;
|
|
163787
|
-
known.add(key);
|
|
163788
|
-
if (identity !== void 0) persisted.add(identity);
|
|
163789
|
-
return true;
|
|
163790
|
-
});
|
|
163791
|
-
const base = journal[0]?.event.seq ?? nextSeq;
|
|
163792
|
-
if (older.length > base) throw new Error("Arko 历史窗口边界已变化,请重新打开会话");
|
|
163793
|
-
const entries = older.map((message, index) => historyRecord(message, base - older.length + index));
|
|
163794
|
-
journal = [...entries.map((value) => value.entry), ...journal];
|
|
163795
|
-
projected = [...entries.map((value) => value.row), ...projected];
|
|
163796
|
-
}
|
|
163797
|
-
function seedHistory(messages) {
|
|
163798
|
-
for (const message of messages) {
|
|
163799
|
-
if (message.status === "sending" || message.messageId === void 0) {
|
|
163800
|
-
addMessage(message);
|
|
163801
|
-
continue;
|
|
163802
|
-
}
|
|
163803
|
-
const value = historyRecord(message, nextSeq++);
|
|
163804
|
-
journal.push(value.entry);
|
|
163805
|
-
projected.push(value.row);
|
|
163806
|
-
turn = Math.max(turn, value.row.turn);
|
|
163807
|
-
}
|
|
163808
|
-
}
|
|
163809
|
-
function selectedModel() {
|
|
163810
|
-
const route = snapshot.modelCatalog?.effectiveRouteKey;
|
|
163811
|
-
return route ? {
|
|
163812
|
-
provider: "arko",
|
|
163813
|
-
model: route
|
|
163814
|
-
} : null;
|
|
163815
|
-
}
|
|
163816
|
-
function projectionValues() {
|
|
163817
|
-
return {
|
|
163818
|
-
title: snapshot.displayName,
|
|
163819
|
-
modelSelection: {
|
|
163820
|
-
lastUsed: null,
|
|
163821
|
-
next: selectedModel()
|
|
163822
|
-
},
|
|
163823
|
-
sessionListMetadata: {
|
|
163824
|
-
blank: false,
|
|
163825
|
-
lastPromptAt: snapshot.messages.filter((message) => message.role === "user").at(-1)?.createdAtMillis ?? null
|
|
163826
|
-
}
|
|
163827
|
-
};
|
|
163828
|
-
}
|
|
163829
|
-
function projections() {
|
|
163830
|
-
return {
|
|
163831
|
-
asOfSeq: nextSeq - 1,
|
|
163832
|
-
values: projectionValues()
|
|
163833
|
-
};
|
|
163834
|
-
}
|
|
163835
|
-
function summary() {
|
|
163836
|
-
return {
|
|
163837
|
-
sessionId,
|
|
163838
|
-
updatedAt: snapshot.messages.at(-1)?.createdAtMillis ?? createdAt,
|
|
163839
|
-
running: snapshot.busy,
|
|
163840
|
-
blank: false,
|
|
163841
|
-
projections: projections()
|
|
163842
|
-
};
|
|
163843
|
-
}
|
|
163844
|
-
function checkSession(request) {
|
|
163845
|
-
return request.sessionId === sessionId;
|
|
163846
|
-
}
|
|
163847
|
-
function blocked() {
|
|
163848
|
-
return snapshot.loading ? "Arko 正在加载" : snapshot.inputBlockedReason || (snapshot.busy || submitting || changingModel ? "Arko 正在处理上一项操作" : void 0);
|
|
163849
|
-
}
|
|
163850
|
-
async function dispatch(method, payload) {
|
|
163851
|
-
const request = requestOf(payload);
|
|
163852
|
-
switch (method) {
|
|
163853
|
-
case "settings/describe": return ok({
|
|
163854
|
-
writable: false,
|
|
163855
|
-
hasDocument: false,
|
|
163856
|
-
namespaces: []
|
|
163857
|
-
});
|
|
163858
|
-
case "credentials/describe": return ok({});
|
|
163859
|
-
case "dynamicCordisRunner/syncInspectManifest": return ok(null);
|
|
163860
|
-
case "dynamicCordisRunner/inventory":
|
|
163861
|
-
case "commands/list":
|
|
163862
|
-
case "llm/listConfigurableProviders": return ok([]);
|
|
163863
|
-
case "agentPresets/list": return ok({
|
|
163864
|
-
presets: [],
|
|
163865
|
-
authorable: false
|
|
163866
|
-
});
|
|
163867
|
-
case "subagents/list": return ok({
|
|
163868
|
-
entries: [],
|
|
163869
|
-
parentAvailable: false
|
|
163870
|
-
});
|
|
163871
|
-
case "skills/list": return ok({ skills: [] });
|
|
163872
|
-
case "session/list": return ok({ items: [summary()] });
|
|
163873
|
-
case "llm/listProviders": return ok([{
|
|
163874
|
-
id: "arko",
|
|
163875
|
-
name: snapshot.displayName
|
|
163876
|
-
}]);
|
|
163877
|
-
case "session/modelCatalog": {
|
|
163878
|
-
const catalog = snapshot.modelCatalog;
|
|
163879
|
-
return ok({
|
|
163880
|
-
default: {
|
|
163881
|
-
provider: "arko",
|
|
163882
|
-
model: catalog?.defaultRouteKey || catalog?.effectiveRouteKey || ""
|
|
163883
|
-
},
|
|
163884
|
-
routableProviders: catalog?.options.length ? ["arko"] : [],
|
|
163885
|
-
groups: catalog === null ? [] : [{
|
|
163886
|
-
id: "arko",
|
|
163887
|
-
name: snapshot.displayName,
|
|
163888
|
-
models: catalog.options.map((option) => ({
|
|
163889
|
-
id: option.routeKey,
|
|
163890
|
-
name: option.displayName,
|
|
163891
|
-
description: option.description
|
|
163892
|
-
}))
|
|
163893
|
-
}],
|
|
163894
|
-
failures: []
|
|
163895
|
-
});
|
|
163896
|
-
}
|
|
163897
|
-
case "session/selectModel": {
|
|
163898
|
-
if (!checkSession(request)) return denied("Arko 会话已失效");
|
|
163899
|
-
const reason = blocked();
|
|
163900
|
-
if (reason !== void 0) return denied(reason);
|
|
163901
|
-
if (request.provider !== "arko" || typeof request.model !== "string" || request.reasoningEffort !== void 0 || !snapshot.modelCatalog?.options.some((option) => option.routeKey === request.model)) return denied("此 Arko 模型不可用");
|
|
163902
|
-
if (request.model === snapshot.modelCatalog.effectiveRouteKey) return ok({ selected: selectedModel() });
|
|
163903
|
-
changingModel = true;
|
|
163904
|
-
try {
|
|
163905
|
-
if (await actions.selectModel(request.model) !== true && snapshot.modelCatalog?.effectiveRouteKey !== request.model) return denied(snapshot.error || "Arko 模型切换未确认");
|
|
163906
|
-
return ok({ selected: {
|
|
163907
|
-
provider: "arko",
|
|
163908
|
-
model: request.model
|
|
163909
|
-
} });
|
|
163910
|
-
} finally {
|
|
163911
|
-
changingModel = false;
|
|
163912
|
-
}
|
|
163913
|
-
}
|
|
163914
|
-
case "session/prompt": {
|
|
163915
|
-
if (!checkSession(request)) return denied("Arko 会话已失效");
|
|
163916
|
-
const reason = blocked();
|
|
163917
|
-
if (reason !== void 0) return denied(reason);
|
|
163918
|
-
if (request.mode !== "queue" || typeof request.requestId !== "string" || request.requestId.length === 0) return denied("Arko 不支持此发送方式");
|
|
163919
|
-
if (!Array.isArray(request.content) || request.content.some((part) => record(part).type !== "text" || typeof record(part).text !== "string")) return denied("Arko 当前仅支持文字输入");
|
|
163920
|
-
const text = request.content.map((part) => record(part).text).join("").trim();
|
|
163921
|
-
if (!text || text.length > 60 * 1024) return denied("Arko 输入为空或超过长度上限");
|
|
163922
|
-
submitting = true;
|
|
163923
|
-
pendingPrompt = {
|
|
163924
|
-
requestId: request.requestId,
|
|
163925
|
-
text
|
|
163926
|
-
};
|
|
163927
|
-
try {
|
|
163928
|
-
if (await actions.submit(text) !== true) {
|
|
163929
|
-
pendingPrompt = void 0;
|
|
163930
|
-
return denied(snapshot.error || "Arko 未接受此次发送");
|
|
163931
|
-
}
|
|
163932
|
-
return ok({ accepted: true });
|
|
163933
|
-
} catch (error) {
|
|
163934
|
-
pendingPrompt = void 0;
|
|
163935
|
-
throw error;
|
|
163936
|
-
} finally {
|
|
163937
|
-
submitting = false;
|
|
163938
|
-
}
|
|
163939
|
-
}
|
|
163940
|
-
case "session/cancel":
|
|
163941
|
-
if (!checkSession(request)) return denied("Arko 会话已失效");
|
|
163942
|
-
if (!snapshot.busy) return denied("Arko 当前没有可停止的运行");
|
|
163943
|
-
return await actions.cancel() === true ? ok({ accepted: true }) : denied(snapshot.error || "Arko 停止请求未确认");
|
|
163944
|
-
case "session/page": {
|
|
163945
|
-
if (record(request.address).kind !== "session" || record(request.address).sessionId !== sessionId) return denied("Arko 会话已失效");
|
|
163946
|
-
if (request.beforeSeq !== void 0 && (!Number.isSafeInteger(request.beforeSeq) || Number(request.beforeSeq) < 0)) return denied("Arko 历史边界无效");
|
|
163947
|
-
const before = typeof request.beforeSeq === "number" ? request.beforeSeq : Infinity;
|
|
163948
|
-
const through = typeof request.throughSeq === "number" ? request.throughSeq : nextSeq - 1;
|
|
163949
|
-
if (snapshot.hasMore && before <= (journal[0]?.event.seq ?? nextSeq)) {
|
|
163950
|
-
pageRequest ??= (async () => {
|
|
163951
|
-
const page = await actions.loadEarlier();
|
|
163952
|
-
if (disposed) throw new Error("Arko 原生呈现已关闭");
|
|
163953
|
-
prependHistory(page.messages);
|
|
163954
|
-
snapshot = {
|
|
163955
|
-
...snapshot,
|
|
163956
|
-
hasMore: page.hasMore
|
|
163957
|
-
};
|
|
163958
|
-
})().finally(() => {
|
|
163959
|
-
pageRequest = void 0;
|
|
163960
|
-
});
|
|
163961
|
-
await pageRequest;
|
|
163962
|
-
}
|
|
163963
|
-
const available = journal.filter((entry) => entry.event.seq <= through && entry.event.seq < before);
|
|
163964
|
-
const limit = typeof request.maxMessages === "number" && Number.isSafeInteger(request.maxMessages) ? Math.min(50, Math.max(1, request.maxMessages)) : 50;
|
|
163965
|
-
return ok({
|
|
163966
|
-
records: available.slice(-limit),
|
|
163967
|
-
hasMore: available.length > limit || snapshot.hasMore === true
|
|
163968
|
-
});
|
|
163969
|
-
}
|
|
163970
|
-
default: return denied(`Arko 不支持原生操作:${method}`);
|
|
163971
|
-
}
|
|
163972
|
-
}
|
|
163973
|
-
seedHistory(snapshot.messages);
|
|
163974
|
-
return {
|
|
163975
|
-
sessionId,
|
|
163976
|
-
get historyRevision() {
|
|
163977
|
-
return historyRevision;
|
|
163978
|
-
},
|
|
163979
|
-
getSnapshot: () => snapshot,
|
|
163980
|
-
subscribe(listener) {
|
|
163981
|
-
if (disposed) return () => {};
|
|
163982
|
-
listeners.add(listener);
|
|
163983
|
-
return () => {
|
|
163984
|
-
listeners.delete(listener);
|
|
163985
|
-
};
|
|
163986
|
-
},
|
|
163987
|
-
update(next, nextActions) {
|
|
163988
|
-
if (disposed) throw new Error("Arko 原生呈现已销毁");
|
|
163989
|
-
if (next.accountKey !== accountKey) throw new Error("Arko 账号切换必须建立新的原生呈现");
|
|
163990
|
-
const previous = snapshot;
|
|
163991
|
-
const oldValues = projectionValues();
|
|
163992
|
-
snapshot = next;
|
|
163993
|
-
if (nextActions !== void 0) actions = nextActions;
|
|
163994
|
-
if (projected.length > 0) {
|
|
163995
|
-
const head = next.messages.findIndex((message) => messageKey(message) === projected[0].key);
|
|
163996
|
-
if (head > 0) prependHistory(next.messages.slice(0, head));
|
|
163997
|
-
}
|
|
163998
|
-
if (projected.some((row, index) => {
|
|
163999
|
-
const message = next.messages[index];
|
|
164000
|
-
if (message === void 0 || messageKey(message) !== row.key) return true;
|
|
164001
|
-
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)));
|
|
164002
|
-
})) {
|
|
164003
|
-
historyRevision++;
|
|
164004
|
-
journal = [];
|
|
164005
|
-
projected = [];
|
|
164006
|
-
turn = 0;
|
|
164007
|
-
activeAssistant = void 0;
|
|
164008
|
-
assistantRevision = 0;
|
|
164009
|
-
nextSeq = sequenceOrigin;
|
|
164010
|
-
seedHistory(next.messages);
|
|
164011
|
-
} else for (let index = 0; index < next.messages.length; index++) {
|
|
164012
|
-
const message = next.messages[index];
|
|
164013
|
-
const row = projected[index];
|
|
164014
|
-
if (row === void 0) {
|
|
164015
|
-
addMessage(message);
|
|
164016
|
-
continue;
|
|
164017
|
-
}
|
|
164018
|
-
const previousMessage = row.message;
|
|
164019
|
-
row.message = message;
|
|
164020
|
-
if (message.role === "assistant" && row.seq < 0) if (message.status === "sending") streamMessage(row, previousMessage);
|
|
164021
|
-
else settleAssistant(row);
|
|
164022
|
-
endMessage(row);
|
|
164023
|
-
}
|
|
164024
|
-
const values = projectionValues();
|
|
164025
|
-
const changedKeys = Object.keys(values).filter((key) => JSON.stringify(values[key]) !== JSON.stringify(oldValues[key]));
|
|
164026
|
-
const context = {
|
|
164027
|
-
id: "",
|
|
164028
|
-
role: "divider",
|
|
164029
|
-
text: "",
|
|
164030
|
-
status: "done",
|
|
164031
|
-
createdAtMillis: Date.now()
|
|
164032
|
-
};
|
|
164033
|
-
if (changedKeys.length > 0) append("arko/presentation", Object.fromEntries(changedKeys.map((key) => [key, values[key]])), context);
|
|
164034
|
-
for (const key of changedKeys) emit("session/control", {
|
|
164035
|
-
type: "projection",
|
|
164036
|
-
sessionId,
|
|
164037
|
-
key,
|
|
164038
|
-
value: values[key],
|
|
164039
|
-
seq: nextSeq - 1
|
|
164040
|
-
});
|
|
164041
|
-
if (previous.busy !== next.busy) emit("$events", {
|
|
164042
|
-
type: "emit",
|
|
164043
|
-
event: "api-session/status",
|
|
164044
|
-
args: [sessionId, next.busy]
|
|
164045
|
-
});
|
|
164046
|
-
if (next.error && previous.error !== next.error) emit("$events", {
|
|
164047
|
-
type: "emit",
|
|
164048
|
-
event: "api-session/error",
|
|
164049
|
-
args: [sessionId, next.error]
|
|
164050
|
-
});
|
|
164051
|
-
if (JSON.stringify(previous.modelCatalog) !== JSON.stringify(next.modelCatalog)) emit("$events", {
|
|
164052
|
-
type: "emit",
|
|
164053
|
-
event: "llm/adapters-updated",
|
|
164054
|
-
args: []
|
|
164055
|
-
});
|
|
164056
|
-
for (const listener of listeners) listener();
|
|
164057
|
-
},
|
|
164058
|
-
async fetch(_input, init) {
|
|
164059
|
-
let rpcId = "";
|
|
164060
|
-
let result;
|
|
164061
|
-
try {
|
|
164062
|
-
if (typeof init.body !== "string") throw new Error("Arko 原生请求格式无效");
|
|
164063
|
-
const envelope = record(JSON.parse(init.body));
|
|
164064
|
-
rpcId = typeof envelope.rpcId === "string" ? envelope.rpcId : "";
|
|
164065
|
-
if (envelope.type !== "client-request" || typeof envelope.method !== "string" || rpcId === "") throw new Error("Arko 原生请求格式无效");
|
|
164066
|
-
if (disposed || init.signal?.aborted) result = denied("Arko 原生呈现已关闭");
|
|
164067
|
-
else {
|
|
164068
|
-
result = await dispatch(envelope.method, envelope.payload);
|
|
164069
|
-
if (disposed || init.signal?.aborted) result = denied("Arko 原生呈现已关闭");
|
|
164070
|
-
}
|
|
164071
|
-
} catch (error) {
|
|
164072
|
-
result = denied(error instanceof Error ? error.message : "Arko 原生请求失败");
|
|
164073
|
-
}
|
|
164074
|
-
return new Response(JSON.stringify({
|
|
164075
|
-
type: "server-response",
|
|
164076
|
-
rpcId,
|
|
164077
|
-
result
|
|
164078
|
-
}), { headers: { "content-type": "application/json" } });
|
|
164079
|
-
},
|
|
164080
|
-
async *openStream(endpoint, payload, signal) {
|
|
164081
|
-
if (disposed || signal.aborted) return;
|
|
164082
|
-
if (![
|
|
164083
|
-
"$events",
|
|
164084
|
-
"session/control",
|
|
164085
|
-
"session/follow",
|
|
164086
|
-
"workspace/follow"
|
|
164087
|
-
].includes(endpoint)) throw new Error(`Arko 不支持原生流:${endpoint}`);
|
|
164088
|
-
if (endpoint === "session/follow") {
|
|
164089
|
-
const address = record(requestOf(payload).address);
|
|
164090
|
-
if (address.kind !== "session" || address.sessionId !== sessionId) throw new Error("Arko 会话已失效");
|
|
164091
|
-
}
|
|
164092
|
-
const queue = [];
|
|
164093
|
-
let wake;
|
|
164094
|
-
let ended = false;
|
|
164095
|
-
const sink = {
|
|
164096
|
-
endpoint,
|
|
164097
|
-
historyRevision,
|
|
164098
|
-
push(value) {
|
|
164099
|
-
if (!ended) {
|
|
164100
|
-
queue.push(value);
|
|
164101
|
-
wake?.();
|
|
164102
|
-
}
|
|
164103
|
-
},
|
|
164104
|
-
close() {
|
|
164105
|
-
ended = true;
|
|
164106
|
-
wake?.();
|
|
164107
|
-
}
|
|
164108
|
-
};
|
|
164109
|
-
streams.add(sink);
|
|
164110
|
-
const abort = () => sink.close();
|
|
164111
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
164112
|
-
try {
|
|
164113
|
-
if (endpoint === "$events") yield {
|
|
164114
|
-
type: "ready",
|
|
164115
|
-
clientId: crypto.randomUUID(),
|
|
164116
|
-
host: { home: "" }
|
|
164117
|
-
};
|
|
164118
|
-
if (endpoint === "workspace/follow") yield {
|
|
164119
|
-
type: "baseline",
|
|
164120
|
-
value: {
|
|
164121
|
-
items: [],
|
|
164122
|
-
archivedSessionIds: []
|
|
164123
|
-
}
|
|
164124
|
-
};
|
|
164125
|
-
if (endpoint === "session/control") yield {
|
|
164126
|
-
type: "baseline",
|
|
164127
|
-
value: {
|
|
164128
|
-
queues: { [sessionId]: [] },
|
|
164129
|
-
jobs: { [sessionId]: [] },
|
|
164130
|
-
projections: { [sessionId]: projections() }
|
|
164131
|
-
}
|
|
164132
|
-
};
|
|
164133
|
-
if (endpoint === "session/follow") yield {
|
|
164134
|
-
type: "snapshot",
|
|
164135
|
-
header: {
|
|
164136
|
-
version: 3,
|
|
164137
|
-
id: sessionId,
|
|
164138
|
-
createdAt,
|
|
164139
|
-
isSeeded: false
|
|
164140
|
-
},
|
|
164141
|
-
cursor: nextSeq - 1,
|
|
164142
|
-
records: journal.slice(),
|
|
164143
|
-
hasMore: snapshot.hasMore === true,
|
|
164144
|
-
projections: projections(),
|
|
164145
|
-
assistantStream: {
|
|
164146
|
-
revision: assistantRevision,
|
|
164147
|
-
...activeAssistant === void 0 ? {} : { activeAttempt: {
|
|
164148
|
-
...activeAssistant,
|
|
164149
|
-
stream: activeAssistant.stream.slice()
|
|
164150
|
-
} }
|
|
164151
|
-
}
|
|
164152
|
-
};
|
|
164153
|
-
while (!ended) {
|
|
164154
|
-
if (queue.length > 0) {
|
|
164155
|
-
yield queue.shift();
|
|
164156
|
-
continue;
|
|
164157
|
-
}
|
|
164158
|
-
await new Promise((resolve) => {
|
|
164159
|
-
wake = resolve;
|
|
164160
|
-
});
|
|
164161
|
-
wake = void 0;
|
|
164162
|
-
}
|
|
164163
|
-
} finally {
|
|
164164
|
-
streams.delete(sink);
|
|
164165
|
-
signal.removeEventListener("abort", abort);
|
|
164166
|
-
queue.length = 0;
|
|
164167
|
-
}
|
|
164168
|
-
},
|
|
164169
|
-
dispose() {
|
|
164170
|
-
if (disposed) return;
|
|
164171
|
-
disposed = true;
|
|
164172
|
-
for (const stream of streams) stream.close();
|
|
164173
|
-
streams.clear();
|
|
164174
|
-
listeners.clear();
|
|
164175
|
-
journal = [];
|
|
164176
|
-
projected = [];
|
|
164177
|
-
pendingPrompt = void 0;
|
|
164178
|
-
activeAssistant = void 0;
|
|
164179
|
-
}
|
|
164180
|
-
};
|
|
164181
|
-
}
|
|
164182
|
-
//#endregion
|
|
164183
|
-
//#region src/client/arko-native-frame.ts
|
|
164184
|
-
const conversationOnlyLayout = `
|
|
164185
|
-
button[aria-haspopup="listbox"][aria-label="指令"],
|
|
164186
|
-
button[aria-haspopup="listbox"][aria-label="Commands"] {
|
|
164187
|
-
display: none !important;
|
|
164188
|
-
}
|
|
164189
|
-
body div:has(> :first-child > [data-slot="sidebar"]):has(> [data-rightbar-col]) > :first-child,
|
|
164190
|
-
body div:has(> :first-child > [data-slot="sidebar"]):has(> [data-rightbar-col]) > [data-side="sidebar"] {
|
|
164191
|
-
display: none !important;
|
|
164192
|
-
}
|
|
164193
|
-
body div:has(> :first-child > [data-slot="sidebar"]):has(> [data-rightbar-col]) > :nth-child(2) {
|
|
164194
|
-
grid-column: 1 / 3; grid-row: 1;
|
|
164195
|
-
}
|
|
164196
|
-
body div:has(> :first-child > [data-slot="sidebar"]):has(> [data-rightbar-col]) > [data-rightbar-col] {
|
|
164197
|
-
grid-column: 3; grid-row: 1;
|
|
164198
|
-
}
|
|
164199
|
-
`;
|
|
164200
|
-
/** The owning parent installs a per-frame carrier before any native DSH code executes. */
|
|
164201
|
-
function arkoNativeFrameDocument(html, key, origin) {
|
|
164202
|
-
if (!/^[a-zA-Z0-9-]+$/.test(key) || !/<head(?:\s[^>]*)?>/i.test(html)) throw new Error("Arko 原生页面启动配置无效");
|
|
164203
|
-
const base = new URL("/", origin).href.replaceAll("&", "&").replaceAll("\"", """);
|
|
164204
|
-
return html.replace(/<head(?:\s[^>]*)?>/i, (head) => `${head}<base href="${base}"><style data-arkme-arko-layout>${conversationOnlyLayout}</style><script>
|
|
164205
|
-
const carrier = parent.__arkmeArkoNativeFrames?.get(${JSON.stringify(key)});
|
|
164206
|
-
if (!carrier) throw new Error('Arko native carrier unavailable');
|
|
164207
|
-
// Session selection belongs to this document, not the ordinary DSH tab.
|
|
164208
|
-
const storage = globalThis.localStorage;
|
|
164209
|
-
const isolated = new Map();
|
|
164210
|
-
const conversationKey = 'dsh.conversation.' + carrier.sessionId;
|
|
164211
|
-
for (const method of ['getItem', 'setItem', 'removeItem']) {
|
|
164212
|
-
const original = Storage.prototype[method];
|
|
164213
|
-
Storage.prototype[method] = function(key, value) {
|
|
164214
|
-
if (this !== storage || (key !== 'dsh.sessions.current' && key !== conversationKey)) return original.apply(this, arguments);
|
|
164215
|
-
if (method === 'getItem') return isolated.get(key) ?? null;
|
|
164216
|
-
if (method === 'removeItem') isolated.delete(key);
|
|
164217
|
-
else isolated.set(key, String(value));
|
|
164218
|
-
};
|
|
164219
|
-
}
|
|
164220
|
-
globalThis.__DSH_TRANSPORT__ = {
|
|
164221
|
-
async fetch(...args) {
|
|
164222
|
-
const response = await carrier.fetch(...args);
|
|
164223
|
-
return new Response(await response.text(), { status: response.status, headers: { 'content-type': 'application/json' } });
|
|
164224
|
-
},
|
|
164225
|
-
async *openStream(...args) {
|
|
164226
|
-
for await (const value of carrier.openStream(...args)) yield JSON.parse(JSON.stringify(value));
|
|
164227
|
-
},
|
|
164228
|
-
};
|
|
164229
|
-
globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
164230
|
-
<\/script>`);
|
|
164231
|
-
}
|
|
164232
|
-
//#endregion
|
|
164233
|
-
//#region src/client/ArkoNativeSurface.tsx
|
|
164234
|
-
/** This component owns only the native document and its disposable presentation carrier. */
|
|
164235
|
-
function ArkoNativeSurface({ snapshot, actions, ui }) {
|
|
164236
|
-
const latest = (0, react$1.useRef)({
|
|
164237
|
-
snapshot,
|
|
164238
|
-
actions,
|
|
164239
|
-
ui
|
|
164240
|
-
});
|
|
164241
|
-
latest.current = {
|
|
164242
|
-
snapshot,
|
|
164243
|
-
actions,
|
|
164244
|
-
ui
|
|
164245
|
-
};
|
|
164246
|
-
const carrier = (0, react$1.useRef)();
|
|
164247
|
-
const [html, setHtml] = (0, react$1.useState)("");
|
|
164248
|
-
const [error, setError] = (0, react$1.useState)("");
|
|
164249
|
-
const [ready, setReady] = (0, react$1.useState)(false);
|
|
164250
|
-
const [attempt, setAttempt] = (0, react$1.useState)(0);
|
|
164251
|
-
(0, react$1.useLayoutEffect)(() => {
|
|
164252
|
-
const transport = carrier.current;
|
|
164253
|
-
if (!transport || transport.getSnapshot().accountKey !== snapshot.accountKey) return;
|
|
164254
|
-
const revision = transport.historyRevision;
|
|
164255
|
-
transport.ui = ui;
|
|
164256
|
-
transport.update(snapshot, actions);
|
|
164257
|
-
if (transport.historyRevision !== revision) setAttempt((value) => value + 1);
|
|
164258
|
-
}, [
|
|
164259
|
-
snapshot,
|
|
164260
|
-
actions,
|
|
164261
|
-
ui
|
|
164262
|
-
]);
|
|
164263
|
-
(0, react$1.useEffect)(() => {
|
|
164264
|
-
if (snapshot.loading) return;
|
|
164265
|
-
const controller = new AbortController();
|
|
164266
|
-
const key = crypto.randomUUID();
|
|
164267
|
-
const current = latest.current;
|
|
164268
|
-
const transport = Object.assign(createArkoNativeTransport(current.snapshot, current.actions), {
|
|
164269
|
-
ui: current.ui,
|
|
164270
|
-
ready: () => {
|
|
164271
|
-
if (!controller.signal.aborted) {
|
|
164272
|
-
setError("");
|
|
164273
|
-
setReady(true);
|
|
164274
|
-
}
|
|
164275
|
-
}
|
|
164276
|
-
});
|
|
164277
|
-
carrier.current = transport;
|
|
164278
|
-
const frames = window.__arkmeArkoNativeFrames ??= /* @__PURE__ */ new Map();
|
|
164279
|
-
frames.set(key, transport);
|
|
164280
|
-
setError("");
|
|
164281
|
-
setHtml("");
|
|
164282
|
-
setReady(false);
|
|
164283
|
-
fetch("/arkme-self/harness-frame?arkme-arko=1", {
|
|
164284
|
-
signal: controller.signal,
|
|
164285
|
-
credentials: "same-origin"
|
|
164286
|
-
}).then(async (response) => {
|
|
164287
|
-
if (!response.ok) throw new Error(`原生页面加载失败(${response.status})`);
|
|
164288
|
-
const source = await response.text();
|
|
164289
|
-
if (!controller.signal.aborted) setHtml(arkoNativeFrameDocument(source, key, location.origin));
|
|
164290
|
-
}).catch((caught) => {
|
|
164291
|
-
if (!controller.signal.aborted) setError(caught instanceof Error ? caught.message : String(caught));
|
|
164292
|
-
});
|
|
164293
|
-
const deadline = window.setTimeout(() => {
|
|
164294
|
-
if (!controller.signal.aborted) setReady((value) => {
|
|
164295
|
-
if (!value) setError("原生页面启动超时,请重试");
|
|
164296
|
-
return value;
|
|
164297
|
-
});
|
|
164298
|
-
}, 3e4);
|
|
164299
|
-
return () => {
|
|
164300
|
-
controller.abort();
|
|
164301
|
-
clearTimeout(deadline);
|
|
164302
|
-
transport.dispose();
|
|
164303
|
-
frames.delete(key);
|
|
164304
|
-
if (carrier.current === transport) carrier.current = void 0;
|
|
164305
|
-
};
|
|
164306
|
-
}, [
|
|
164307
|
-
snapshot.accountKey,
|
|
164308
|
-
attempt,
|
|
164309
|
-
snapshot.loading
|
|
164310
|
-
]);
|
|
164311
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
164312
|
-
"data-arkme-owned": "arko-native-surface",
|
|
164313
|
-
style: {
|
|
164314
|
-
height: "100%",
|
|
164315
|
-
minHeight: 0,
|
|
164316
|
-
position: "relative",
|
|
164317
|
-
display: "flex",
|
|
164318
|
-
flexDirection: "column"
|
|
164319
|
-
},
|
|
164320
|
-
children: [
|
|
164321
|
-
error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
164322
|
-
role: "alert",
|
|
164323
|
-
children: [error, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
164324
|
-
onClick: () => setAttempt((value) => value + 1),
|
|
164325
|
-
children: "重新加载原生页面"
|
|
164326
|
-
})]
|
|
164327
|
-
}),
|
|
164328
|
-
!ready && !error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
164329
|
-
role: "status",
|
|
164330
|
-
"aria-label": "正在加载 Arko 对话",
|
|
164331
|
-
"data-arko-loading-skeleton": true,
|
|
164332
|
-
style: {
|
|
164333
|
-
position: "absolute",
|
|
164334
|
-
inset: 0,
|
|
164335
|
-
display: "flex",
|
|
164336
|
-
flexDirection: "column",
|
|
164337
|
-
background: arkmeTheme.base
|
|
164338
|
-
},
|
|
164339
|
-
children: [
|
|
164340
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
164341
|
-
style: {
|
|
164342
|
-
display: "flex",
|
|
164343
|
-
alignItems: "center",
|
|
164344
|
-
gap: 10,
|
|
164345
|
-
padding: "16px 24px",
|
|
164346
|
-
borderBottom: `1px solid ${arkmeTheme.border}`
|
|
164347
|
-
},
|
|
164348
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeArkoAvatar, { size: 30 }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
164349
|
-
style: { color: arkmeTheme.text },
|
|
164350
|
-
children: snapshot.displayName
|
|
164351
|
-
})]
|
|
164352
|
-
}),
|
|
164353
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
164354
|
-
"aria-hidden": true,
|
|
164355
|
-
style: {
|
|
164356
|
-
flex: 1,
|
|
164357
|
-
width: "min(720px, 86%)",
|
|
164358
|
-
margin: "24px auto",
|
|
164359
|
-
display: "flex",
|
|
164360
|
-
flexDirection: "column",
|
|
164361
|
-
gap: 20
|
|
164362
|
-
},
|
|
164363
|
-
children: [
|
|
164364
|
-
70,
|
|
164365
|
-
45,
|
|
164366
|
-
82
|
|
164367
|
-
].map((width, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
164368
|
-
width: `${width}%`,
|
|
164369
|
-
height: index === 1 ? 40 : 64,
|
|
164370
|
-
alignSelf: index === 1 ? "flex-end" : "flex-start",
|
|
164371
|
-
borderRadius: 12,
|
|
164372
|
-
background: arkmeTheme.hover
|
|
164373
|
-
} }, index))
|
|
164374
|
-
}),
|
|
164375
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
164376
|
-
style: {
|
|
164377
|
-
width: "min(720px, 86%)",
|
|
164378
|
-
margin: "0 auto 24px"
|
|
164379
|
-
},
|
|
164380
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
164381
|
-
"aria-hidden": true,
|
|
164382
|
-
style: {
|
|
164383
|
-
height: 92,
|
|
164384
|
-
border: `1px solid ${arkmeTheme.border}`,
|
|
164385
|
-
borderRadius: 16,
|
|
164386
|
-
background: arkmeTheme.hover
|
|
164387
|
-
}
|
|
164388
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
164389
|
-
style: {
|
|
164390
|
-
textAlign: "center",
|
|
164391
|
-
color: arkmeTheme.secondary,
|
|
164392
|
-
fontSize: 12,
|
|
164393
|
-
paddingTop: 10
|
|
164394
|
-
},
|
|
164395
|
-
children: "正在加载对话…"
|
|
164396
|
-
})]
|
|
164397
|
-
})
|
|
164398
|
-
]
|
|
164399
|
-
}),
|
|
164400
|
-
html && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
|
|
164401
|
-
name: "arkme-arko-native",
|
|
164402
|
-
title: "Arko 原生 DSH 页面",
|
|
164403
|
-
srcDoc: html,
|
|
164404
|
-
style: {
|
|
164405
|
-
border: 0,
|
|
164406
|
-
width: "100%",
|
|
164407
|
-
flex: 1,
|
|
164408
|
-
minHeight: 0,
|
|
164409
|
-
visibility: ready && !error ? "visible" : "hidden"
|
|
164410
|
-
},
|
|
164411
|
-
"aria-hidden": !ready || !!error,
|
|
164412
|
-
allow: "clipboard-read; clipboard-write"
|
|
164413
|
-
})
|
|
164414
|
-
]
|
|
164415
|
-
});
|
|
164416
|
-
}
|
|
164417
|
-
//#endregion
|
|
164418
|
-
//#region src/client/arko-pending-turn-store.ts
|
|
164419
|
-
const STORAGE_KEY_PREFIX = "arkme:arko:pending-turn:v1:";
|
|
164420
|
-
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;
|
|
164421
|
-
function defaultStorage() {
|
|
164422
|
-
try {
|
|
164423
|
-
return typeof globalThis.sessionStorage === "undefined" ? void 0 : globalThis.sessionStorage;
|
|
164424
|
-
} catch {
|
|
164425
|
-
return;
|
|
164426
|
-
}
|
|
164427
|
-
}
|
|
164428
|
-
function storageKey(userId) {
|
|
164429
|
-
return `${STORAGE_KEY_PREFIX}${String(userId)}`;
|
|
164430
|
-
}
|
|
164431
|
-
function optionalTrimmedString(value) {
|
|
164432
|
-
if (typeof value !== "string") return void 0;
|
|
164433
|
-
const normalized = value.trim();
|
|
164434
|
-
return normalized === "" ? void 0 : normalized;
|
|
164435
|
-
}
|
|
164436
|
-
function isValidArkoPendingTurn(value, expectedUserId) {
|
|
164437
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
164438
|
-
const turn = value;
|
|
164439
|
-
const hasContinuationRun = optionalTrimmedString(turn.replyToRunUid) !== void 0;
|
|
164440
|
-
const hasContinuationMessage = Number.isSafeInteger(turn.replyToAssistantMsgId) && (turn.replyToAssistantMsgId ?? 0) > 0;
|
|
164441
|
-
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);
|
|
164442
|
-
}
|
|
164443
|
-
function readArkoPendingTurn(userId, storage = defaultStorage()) {
|
|
164444
|
-
if (!Number.isSafeInteger(userId) || userId <= 0 || storage === void 0) return void 0;
|
|
164445
|
-
try {
|
|
164446
|
-
const encoded = storage.getItem(storageKey(userId));
|
|
164447
|
-
if (encoded === null) return void 0;
|
|
164448
|
-
const value = JSON.parse(encoded);
|
|
164449
|
-
if (!isValidArkoPendingTurn(value, userId)) {
|
|
164450
|
-
storage.removeItem(storageKey(userId));
|
|
164451
|
-
return;
|
|
164452
|
-
}
|
|
164453
|
-
return value;
|
|
164454
|
-
} catch {
|
|
164455
|
-
return;
|
|
164456
|
-
}
|
|
164457
|
-
}
|
|
164458
|
-
function writeArkoPendingTurn(turn, storage = defaultStorage()) {
|
|
164459
|
-
if (!isValidArkoPendingTurn(turn) || storage === void 0) return false;
|
|
164460
|
-
try {
|
|
164461
|
-
storage.setItem(storageKey(turn.userId), JSON.stringify(turn));
|
|
164462
|
-
return true;
|
|
164463
|
-
} catch {
|
|
164464
|
-
return false;
|
|
164465
|
-
}
|
|
164466
|
-
}
|
|
164467
|
-
function removeArkoPendingTurn(userId, storage = defaultStorage()) {
|
|
164468
|
-
if (!Number.isSafeInteger(userId) || userId <= 0 || storage === void 0) return;
|
|
164469
|
-
try {
|
|
164470
|
-
storage.removeItem(storageKey(userId));
|
|
164471
|
-
} catch {}
|
|
164472
|
-
}
|
|
164473
|
-
//#endregion
|
|
164474
|
-
//#region src/client/useArkoConversationController.ts
|
|
164475
|
-
const arkoQuestionMaxLength = 60 * 1024;
|
|
164476
|
-
const ACTIVE_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
164477
|
-
"accepted",
|
|
164478
|
-
"queued",
|
|
164479
|
-
"running",
|
|
164480
|
-
"stream_timeout",
|
|
164481
|
-
"waiting_tool"
|
|
164482
|
-
]);
|
|
164483
|
-
function errorMessage$8(error) {
|
|
164484
|
-
if (error instanceof ArkmeClientError) return error.body.message;
|
|
164485
|
-
return error instanceof Error ? error.message : String(error);
|
|
164486
|
-
}
|
|
164487
|
-
function isActiveRunStatus(status) {
|
|
164488
|
-
return status !== void 0 && ACTIVE_RUN_STATUSES.has(status);
|
|
164489
|
-
}
|
|
164490
|
-
function isActivityPlaceholderText(value) {
|
|
164491
|
-
return /^(正在)?(思考|处理)(中)?[.。…]*$/.test(value.trim());
|
|
164492
|
-
}
|
|
164493
|
-
function isActiveHistoryRun(item) {
|
|
164494
|
-
const placeholder = isActivityPlaceholderText(item.text);
|
|
164495
|
-
return item.role === "assistant" && (isActiveRunStatus(item.runStatus) || item.runStatus === void 0 && item.status === 2 && (item.text.trim() === "" || placeholder));
|
|
164496
|
-
}
|
|
164497
|
-
function arkoHistoryHasTerminalRun(items, sessionId, assistantMsgId, runUid) {
|
|
164498
|
-
const matchingItem = items.find((item) => item.role === "assistant" && item.sessionId === sessionId && item.messageId === assistantMsgId && (item.runUid === void 0 || item.runUid === runUid));
|
|
164499
|
-
return matchingItem !== void 0 && !isActiveHistoryRun(matchingItem);
|
|
164500
|
-
}
|
|
164501
|
-
function waitForNextPoll(signal, delayMillis = 1200) {
|
|
164502
|
-
return new Promise((resolve) => {
|
|
164503
|
-
if (signal.aborted) {
|
|
164504
|
-
resolve();
|
|
164505
|
-
return;
|
|
164506
|
-
}
|
|
164507
|
-
const finish = () => {
|
|
164508
|
-
clearTimeout(timeout);
|
|
164509
|
-
signal.removeEventListener("abort", finish);
|
|
164510
|
-
resolve();
|
|
164511
|
-
};
|
|
164512
|
-
const timeout = setTimeout(finish, delayMillis);
|
|
164513
|
-
signal.addEventListener("abort", finish, { once: true });
|
|
164514
|
-
});
|
|
164515
|
-
}
|
|
164516
|
-
function historyMessage(item) {
|
|
164517
|
-
const placeholder = isActivityPlaceholderText(item.text);
|
|
164518
|
-
const reasoningPlaceholder = isActivityPlaceholderText(item.reasoning);
|
|
164519
|
-
const active = isActiveHistoryRun(item);
|
|
164520
|
-
return {
|
|
164521
|
-
id: `history:${String(item.messageId)}`,
|
|
164522
|
-
messageId: item.messageId,
|
|
164523
|
-
sessionId: item.sessionId,
|
|
164524
|
-
role: item.role,
|
|
164525
|
-
text: active && placeholder ? "" : item.text,
|
|
164526
|
-
status: active ? "sending" : item.runStatus === "failed" ? "error" : "done",
|
|
164527
|
-
createdAtMillis: item.createdAtMillis,
|
|
164528
|
-
...item.reasoning.trim() === "" || !active && reasoningPlaceholder ? {} : { reasoning: item.reasoning },
|
|
164529
|
-
...item.role !== "assistant" ? {} : { assistantMsgId: item.messageId },
|
|
164530
|
-
...item.runUid === void 0 ? {} : { runUid: item.runUid },
|
|
164531
|
-
...item.runStatus === void 0 ? {} : { runStatus: item.runStatus },
|
|
164532
|
-
...item.messageActionRef === void 0 ? {} : {
|
|
164533
|
-
messageActionRef: item.messageActionRef,
|
|
164534
|
-
...item.messageActionConversationRef === void 0 ? {} : { messageActionConversationRef: item.messageActionConversationRef },
|
|
164535
|
-
copyLinkAvailable: item.messageActionCapabilities?.copyLink === true,
|
|
164536
|
-
forwardAvailable: item.messageActionCapabilities?.forward === true
|
|
164537
|
-
}
|
|
164538
|
-
};
|
|
164539
|
-
}
|
|
164540
|
-
function latestActiveRun(items, sessionId) {
|
|
164541
|
-
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];
|
|
164542
|
-
if (item?.runUid === void 0) return void 0;
|
|
164543
|
-
return {
|
|
164544
|
-
sessionId: item.sessionId,
|
|
164545
|
-
assistantMsgId: item.messageId,
|
|
164546
|
-
runUid: item.runUid
|
|
164547
|
-
};
|
|
164548
|
-
}
|
|
164549
|
-
function mergeHistory(current, items) {
|
|
164550
|
-
const byId = new Map(current.map((item) => [item.id, item]));
|
|
164551
|
-
for (const item of items) {
|
|
164552
|
-
const key = `history:${String(item.messageId)}`;
|
|
164553
|
-
const prior = byId.get(key);
|
|
164554
|
-
byId.set(key, {
|
|
164555
|
-
...historyMessage(item),
|
|
164556
|
-
...prior?.presentationKey ? { presentationKey: prior.presentationKey } : {}
|
|
164557
|
-
});
|
|
164558
|
-
}
|
|
164559
|
-
return [...byId.values()].sort((left, right) => {
|
|
164560
|
-
const leftAt = left.createdAtMillis ?? Number.MAX_SAFE_INTEGER;
|
|
164561
|
-
const rightAt = right.createdAtMillis ?? Number.MAX_SAFE_INTEGER;
|
|
164562
|
-
if (leftAt !== rightAt) return leftAt - rightAt;
|
|
164563
|
-
return (left.messageId ?? Number.MAX_SAFE_INTEGER) - (right.messageId ?? Number.MAX_SAFE_INTEGER);
|
|
164564
|
-
});
|
|
164565
|
-
}
|
|
164566
|
-
function resultText(result) {
|
|
164567
|
-
if (result.text.trim() !== "") return result.text.trim();
|
|
164568
|
-
if (result.errorMessage?.trim()) return result.errorMessage.trim();
|
|
164569
|
-
if (isActiveRunStatus(result.run?.status ?? result.status)) return "";
|
|
164570
|
-
return "任务已处理。";
|
|
164571
|
-
}
|
|
164572
|
-
function latestContinuation(messages, sessionId) {
|
|
164573
|
-
if (sessionId === void 0) return void 0;
|
|
164574
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
164575
|
-
const message = messages[index];
|
|
164576
|
-
if (message === void 0) continue;
|
|
164577
|
-
if (message.role === "divider") return void 0;
|
|
164578
|
-
if (message.sessionId !== sessionId) continue;
|
|
164579
|
-
if (message.role === "user") return void 0;
|
|
164580
|
-
if (message.runStatus !== "waiting_user" || message.runUid === void 0 || message.assistantMsgId === void 0) return;
|
|
164581
|
-
return {
|
|
164582
|
-
runUid: message.runUid,
|
|
164583
|
-
assistantMsgId: message.assistantMsgId
|
|
164584
|
-
};
|
|
164585
|
-
}
|
|
164586
|
-
}
|
|
164587
|
-
function selectedModelName(catalog) {
|
|
164588
|
-
return catalog?.options.find((option) => option.routeKey === catalog.effectiveRouteKey)?.displayName ?? "模型目录暂不可用";
|
|
164589
|
-
}
|
|
164590
|
-
function useArkoConversationController() {
|
|
164591
|
-
const alive = (0, react$1.useRef)(true);
|
|
164592
|
-
(0, react$1.useEffect)(() => {
|
|
164593
|
-
alive.current = true;
|
|
164594
|
-
return () => {
|
|
164595
|
-
alive.current = false;
|
|
164596
|
-
};
|
|
164597
|
-
}, []);
|
|
164598
|
-
useArkmeLocale();
|
|
164599
|
-
const historyLoadInFlightRef = (0, react$1.useRef)(false);
|
|
164600
|
-
const sendInFlightRef = (0, react$1.useRef)(false);
|
|
164601
|
-
const authSnapshot = (0, react$1.useSyncExternalStore)(arkmeAuthStore.subscribe, arkmeAuthStore.getSnapshot, arkmeAuthStore.getSnapshot);
|
|
164602
|
-
const profileSnapshot = (0, react$1.useSyncExternalStore)(arkmeArkoProfileStore.subscribe, arkmeArkoProfileStore.getSnapshot, arkmeArkoProfileStore.getSnapshot);
|
|
164603
|
-
const profileUserId = authSnapshot.auth?.status === "authenticated" ? authSnapshot.auth.userId : void 0;
|
|
164604
|
-
const composerDraftKey = arkmeArkoComposerDraftKey(profileUserId);
|
|
164605
|
-
(0, react$1.useSyncExternalStore)(arkmeComposerDraftStore.subscribe, arkmeComposerDraftStore.getRevision, arkmeComposerDraftStore.getRevision);
|
|
164606
|
-
const draftSnapshot = arkmeComposerDraftStore.get(composerDraftKey);
|
|
164607
|
-
const draft = draftSnapshot.text;
|
|
164608
|
-
const accountKey = authSnapshot.auth?.status === "authenticated" && profileUserId !== void 0 ? `${authSnapshot.auth.environment}:${String(profileUserId)}` : void 0;
|
|
164609
|
-
const profile = profileSnapshot.userId === profileUserId ? profileSnapshot.profile : void 0;
|
|
164610
|
-
const [userProfile, setUserProfile] = (0, react$1.useState)(null);
|
|
164611
|
-
const [session, setSession] = (0, react$1.useState)();
|
|
164612
|
-
const [catalog, setCatalog] = (0, react$1.useState)();
|
|
164613
|
-
const [messages, setMessages] = (0, react$1.useState)([]);
|
|
164614
|
-
const [historyOffset, setHistoryOffset] = (0, react$1.useState)(null);
|
|
164615
|
-
const [historyError, setHistoryError] = (0, react$1.useState)("");
|
|
164616
|
-
const [historyPageError, setHistoryPageError] = (0, react$1.useState)("");
|
|
164617
|
-
const historyPageAbort = (0, react$1.useRef)();
|
|
164618
|
-
(0, react$1.useEffect)(() => () => {
|
|
164619
|
-
historyPageAbort.current?.abort();
|
|
164620
|
-
}, [accountKey]);
|
|
164621
|
-
const [loading, setLoading] = (0, react$1.useState)(true);
|
|
164622
|
-
const [historyLoading, setHistoryLoading] = (0, react$1.useState)(false);
|
|
164623
|
-
const [sending, setSending] = (0, react$1.useState)(false);
|
|
164624
|
-
const [clearing, setClearing] = (0, react$1.useState)(false);
|
|
164625
|
-
const clearInFlightRef = (0, react$1.useRef)(false);
|
|
164626
|
-
const [selectingModel, setSelectingModel] = (0, react$1.useState)(false);
|
|
164627
|
-
const modelSelectionInFlightRef = (0, react$1.useRef)(false);
|
|
164628
|
-
const [cancelling, setCancelling] = (0, react$1.useState)(false);
|
|
164629
|
-
const [error, setError] = (0, react$1.useState)("");
|
|
164630
|
-
const [notice, setNotice] = (0, react$1.useState)("");
|
|
164631
|
-
const [activeRun, setActiveRun] = (0, react$1.useState)();
|
|
164632
|
-
const [pendingTurn, setPendingTurn] = (0, react$1.useState)();
|
|
164633
|
-
(0, react$1.useEffect)(() => {
|
|
164634
|
-
arkmeArkoProfileStore.activateUser(profileUserId);
|
|
164635
|
-
arkmeArkoConversationPreviewStore.activateUser(profileUserId);
|
|
164636
|
-
}, [profileUserId]);
|
|
164637
|
-
(0, react$1.useEffect)(() => {
|
|
164638
|
-
if (profileUserId === void 0) return;
|
|
164639
|
-
arkmeArkoConversationPreviewStore.setLatestFromSurface(profileUserId, messages.filter((message) => message.role !== "divider").map((message) => ({
|
|
164640
|
-
key: message.id,
|
|
164641
|
-
text: message.text,
|
|
164642
|
-
...message.messageId === void 0 ? {} : { messageId: message.messageId },
|
|
164643
|
-
...message.createdAtMillis === void 0 ? {} : { createdAtMillis: message.createdAtMillis }
|
|
164644
|
-
})));
|
|
164645
|
-
}, [messages, profileUserId]);
|
|
164646
|
-
(0, react$1.useEffect)(() => {
|
|
164647
|
-
if (profileUserId === void 0) {
|
|
164648
|
-
setPendingTurn(void 0);
|
|
164649
|
-
return;
|
|
164650
|
-
}
|
|
164651
|
-
const restored = readArkoPendingTurn(profileUserId);
|
|
164652
|
-
setPendingTurn(restored);
|
|
164653
|
-
if (restored === void 0) return;
|
|
164654
|
-
setMessages((current) => {
|
|
164655
|
-
if (current.some((item) => item.id === restored.localAssistantMessageId)) return current;
|
|
164656
|
-
return [
|
|
164657
|
-
...current,
|
|
164658
|
-
{
|
|
164659
|
-
id: restored.localUserMessageId,
|
|
164660
|
-
presentationKey: restored.localUserMessageId,
|
|
164661
|
-
sessionId: restored.sessionId,
|
|
164662
|
-
role: "user",
|
|
164663
|
-
text: restored.text,
|
|
164664
|
-
status: "done",
|
|
164665
|
-
createdAtMillis: restored.createdAtMillis
|
|
164666
|
-
},
|
|
164667
|
-
{
|
|
164668
|
-
id: restored.localAssistantMessageId,
|
|
164669
|
-
presentationKey: restored.localAssistantMessageId,
|
|
164670
|
-
sessionId: restored.sessionId,
|
|
164671
|
-
role: "assistant",
|
|
164672
|
-
text: "",
|
|
164673
|
-
status: "error",
|
|
164674
|
-
createdAtMillis: restored.createdAtMillis + 1
|
|
164675
|
-
}
|
|
164676
|
-
];
|
|
164677
|
-
});
|
|
164678
|
-
}, [profileUserId]);
|
|
164679
|
-
(0, react$1.useEffect)(() => {
|
|
164680
|
-
const controller = new AbortController();
|
|
164681
|
-
setLoading(true);
|
|
164682
|
-
setError("");
|
|
164683
|
-
setHistoryError("");
|
|
164684
|
-
Promise.allSettled([
|
|
164685
|
-
callArkme("arko.session", void 0, controller.signal),
|
|
164686
|
-
callArkme("arko.profile", void 0, controller.signal),
|
|
164687
|
-
callArkme("arko.models", void 0, controller.signal),
|
|
164688
|
-
callArkme("arko.history", {
|
|
164689
|
-
limit: 50,
|
|
164690
|
-
offset: 0
|
|
164691
|
-
}, controller.signal),
|
|
164692
|
-
callArkme("user.profile", void 0, controller.signal).then(async (snapshot) => snapshot.profile === null ? await callArkme("user.profile.refresh", void 0, controller.signal) : snapshot)
|
|
164693
|
-
]).then(([sessionResult, profileResult, modelResult, historyResult, userProfileResult]) => {
|
|
164694
|
-
if (controller.signal.aborted) return;
|
|
164695
|
-
if (sessionResult.status === "rejected") {
|
|
164696
|
-
setError(errorMessage$8(sessionResult.reason));
|
|
164697
|
-
return;
|
|
164698
|
-
}
|
|
164699
|
-
setSession(sessionResult.value);
|
|
164700
|
-
if (profileResult.status === "fulfilled" && profileUserId !== void 0) arkmeArkoProfileStore.setProfile(profileUserId, profileResult.value);
|
|
164701
|
-
if (modelResult.status === "fulfilled") setCatalog(modelResult.value);
|
|
164702
|
-
if (userProfileResult.status === "fulfilled") setUserProfile(userProfileResult.value.profile);
|
|
164703
|
-
if (historyResult.status === "fulfilled") {
|
|
164704
|
-
setMessages((current) => mergeHistory(current, historyResult.value.items));
|
|
164705
|
-
setHistoryOffset(historyResult.value.nextOffset);
|
|
164706
|
-
const restoredRun = latestActiveRun(historyResult.value.items, sessionResult.value.sessionId);
|
|
164707
|
-
if (restoredRun !== void 0) {
|
|
164708
|
-
setActiveRun(restoredRun);
|
|
164709
|
-
setSending(true);
|
|
164710
|
-
}
|
|
164711
|
-
} else setHistoryError(tr$1("加载 Arko 对话记录失败:{v0}", { v0: errorMessage$8(historyResult.reason) }));
|
|
164712
|
-
}).finally(() => {
|
|
164713
|
-
if (!controller.signal.aborted) setLoading(false);
|
|
164714
|
-
});
|
|
164715
|
-
return () => {
|
|
164716
|
-
controller.abort();
|
|
164717
|
-
};
|
|
164718
|
-
}, [profileUserId]);
|
|
164719
|
-
(0, react$1.useEffect)(() => {
|
|
164720
|
-
if (activeRun === void 0) return;
|
|
164721
|
-
const controller = new AbortController();
|
|
164722
|
-
let consecutiveFailures = 0;
|
|
164723
|
-
const finishRun = async (knownHistory) => {
|
|
164724
|
-
const [historyResult, profileResult] = await Promise.allSettled([knownHistory === void 0 ? callArkme("arko.history", {
|
|
164725
|
-
limit: 50,
|
|
164726
|
-
offset: 0
|
|
164727
|
-
}, controller.signal) : Promise.resolve(knownHistory), callArkme("arko.profile", void 0, controller.signal)]);
|
|
164728
|
-
if (controller.signal.aborted) return;
|
|
164729
|
-
if (historyResult.status === "fulfilled") {
|
|
164730
|
-
setMessages((current) => mergeHistory(current, historyResult.value.items));
|
|
164731
|
-
setHistoryOffset((current) => current === null ? historyResult.value.nextOffset : current);
|
|
164732
|
-
setHistoryError("");
|
|
164733
|
-
} else setHistoryError(tr$1("刷新 Arko 对话记录失败:{v0}", { v0: errorMessage$8(historyResult.reason) }));
|
|
164734
|
-
if (profileResult.status === "fulfilled" && profileUserId !== void 0) arkmeArkoProfileStore.setProfile(profileUserId, profileResult.value);
|
|
164735
|
-
setActiveRun((current) => current?.runUid === activeRun.runUid ? void 0 : current);
|
|
164736
|
-
setSending(false);
|
|
164737
|
-
};
|
|
164738
|
-
const poll = async () => {
|
|
164739
|
-
await waitForNextPoll(controller.signal);
|
|
164740
|
-
while (!controller.signal.aborted) {
|
|
164741
|
-
try {
|
|
164742
|
-
const status = await callArkme("arko.run.status", {
|
|
164743
|
-
sessionId: activeRun.sessionId,
|
|
164744
|
-
runUid: activeRun.runUid
|
|
164745
|
-
}, controller.signal);
|
|
164746
|
-
if (controller.signal.aborted) return;
|
|
164747
|
-
consecutiveFailures = 0;
|
|
164748
|
-
if (status.status === "waiting_tool") setNotice("当前任务需要 DSH 尚未支持的客户端操作,可以停止任务后换一种方式重试");
|
|
164749
|
-
setMessages((current) => current.map((item) => item.assistantMsgId === activeRun.assistantMsgId ? {
|
|
164750
|
-
...item,
|
|
164751
|
-
runStatus: status.status,
|
|
164752
|
-
status: isActiveRunStatus(status.status) ? "sending" : status.status === "failed" ? "error" : "done"
|
|
164753
|
-
} : item));
|
|
164754
|
-
if (!isActiveRunStatus(status.status)) {
|
|
164755
|
-
await finishRun();
|
|
164756
|
-
return;
|
|
164757
|
-
}
|
|
164758
|
-
} catch {
|
|
164759
|
-
if (controller.signal.aborted) return;
|
|
164760
|
-
consecutiveFailures += 1;
|
|
164761
|
-
try {
|
|
164762
|
-
const history = await callArkme("arko.history", {
|
|
164763
|
-
limit: 50,
|
|
164764
|
-
offset: 0
|
|
164765
|
-
}, controller.signal);
|
|
164766
|
-
if (controller.signal.aborted) return;
|
|
164767
|
-
if (arkoHistoryHasTerminalRun(history.items, activeRun.sessionId, activeRun.assistantMsgId, activeRun.runUid)) {
|
|
164768
|
-
await finishRun(history);
|
|
164769
|
-
return;
|
|
164770
|
-
}
|
|
164771
|
-
} catch {
|
|
164772
|
-
if (controller.signal.aborted) return;
|
|
164773
|
-
}
|
|
164774
|
-
}
|
|
164775
|
-
const retryDelay = consecutiveFailures === 0 ? 1200 : Math.min(1e4, 1200 * 2 ** Math.min(consecutiveFailures - 1, 3));
|
|
164776
|
-
await waitForNextPoll(controller.signal, retryDelay);
|
|
164777
|
-
}
|
|
164778
|
-
};
|
|
164779
|
-
poll();
|
|
164780
|
-
return () => {
|
|
164781
|
-
controller.abort();
|
|
164782
|
-
};
|
|
164783
|
-
}, [activeRun, profileUserId]);
|
|
164784
|
-
const loadEarlier = (0, react$1.useCallback)(async () => {
|
|
164785
|
-
const offset = historyOffset;
|
|
164786
|
-
if (typeof offset !== "number") return {
|
|
164787
|
-
messages: [],
|
|
164788
|
-
hasMore: false
|
|
164789
|
-
};
|
|
164790
|
-
if (historyLoadInFlightRef.current) throw new Error("正在加载更早记录");
|
|
164791
|
-
const controller = new AbortController();
|
|
164792
|
-
historyPageAbort.current = controller;
|
|
164793
|
-
historyLoadInFlightRef.current = true;
|
|
164794
|
-
setHistoryPageError("");
|
|
164795
|
-
setHistoryLoading(true);
|
|
164796
|
-
try {
|
|
164797
|
-
const page = await callArkme("arko.history", {
|
|
164798
|
-
limit: 50,
|
|
164799
|
-
offset
|
|
164800
|
-
}, controller.signal);
|
|
164801
|
-
if (controller.signal.aborted) throw new Error("Arko 历史读取已取消");
|
|
164802
|
-
if (page.hasMore && (page.nextOffset === void 0 || page.nextOffset <= offset)) throw new Error("历史分页未前进,请重试");
|
|
164803
|
-
setMessages((current) => {
|
|
164804
|
-
const ids = new Set(current.map((item) => item.messageId));
|
|
164805
|
-
return [...page.items.filter((item) => {
|
|
164806
|
-
if (ids.has(item.messageId)) return false;
|
|
164807
|
-
ids.add(item.messageId);
|
|
164808
|
-
return true;
|
|
164809
|
-
}).reverse().map(historyMessage), ...current];
|
|
164810
|
-
});
|
|
164811
|
-
setHistoryOffset(page.nextOffset);
|
|
164812
|
-
return {
|
|
164813
|
-
messages: [...page.items].reverse().map(historyMessage),
|
|
164814
|
-
hasMore: page.hasMore
|
|
164815
|
-
};
|
|
164816
|
-
} catch (caught) {
|
|
164817
|
-
if (!controller.signal.aborted) setHistoryPageError(`加载更早记录失败:${errorMessage$8(caught)}。请重试。`);
|
|
164818
|
-
throw caught;
|
|
164819
|
-
} finally {
|
|
164820
|
-
if (historyPageAbort.current === controller) {
|
|
164821
|
-
historyLoadInFlightRef.current = false;
|
|
164822
|
-
setHistoryLoading(false);
|
|
164823
|
-
historyPageAbort.current = void 0;
|
|
164824
|
-
}
|
|
164825
|
-
}
|
|
164826
|
-
}, [historyOffset]);
|
|
164827
|
-
const retryHistory = (0, react$1.useCallback)(async () => {
|
|
164828
|
-
if (historyLoadInFlightRef.current) return;
|
|
164829
|
-
const controller = new AbortController();
|
|
164830
|
-
historyPageAbort.current = controller;
|
|
164831
|
-
historyLoadInFlightRef.current = true;
|
|
164832
|
-
setHistoryLoading(true);
|
|
164833
|
-
setHistoryError("");
|
|
164834
|
-
try {
|
|
164835
|
-
const page = await callArkme("arko.history", {
|
|
164836
|
-
limit: 50,
|
|
164837
|
-
offset: 0
|
|
164838
|
-
}, controller.signal);
|
|
164839
|
-
if (controller.signal.aborted) return;
|
|
164840
|
-
setMessages((current) => mergeHistory(current, page.items));
|
|
164841
|
-
setHistoryOffset((current) => current === null ? page.nextOffset : current);
|
|
164842
|
-
if (session !== void 0) {
|
|
164843
|
-
const restoredRun = latestActiveRun(page.items, session.sessionId);
|
|
164844
|
-
if (restoredRun !== void 0) {
|
|
164845
|
-
setActiveRun(restoredRun);
|
|
164846
|
-
setSending(true);
|
|
164847
|
-
}
|
|
164848
|
-
}
|
|
164849
|
-
} catch (caught) {
|
|
164850
|
-
if (!controller.signal.aborted) setHistoryError(tr$1("加载 Arko 对话记录失败:{v0}", { v0: errorMessage$8(caught) }));
|
|
164851
|
-
} finally {
|
|
164852
|
-
if (historyPageAbort.current === controller) {
|
|
164853
|
-
historyLoadInFlightRef.current = false;
|
|
164854
|
-
historyPageAbort.current = void 0;
|
|
164855
|
-
setHistoryLoading(false);
|
|
164856
|
-
}
|
|
164857
|
-
}
|
|
164858
|
-
}, [session]);
|
|
164859
|
-
const submitTurn = (0, react$1.useCallback)(async (turn) => {
|
|
164860
|
-
if (sendInFlightRef.current || sending || activeRun !== void 0) return false;
|
|
164861
|
-
sendInFlightRef.current = true;
|
|
164862
|
-
let handedOffToPolling = false;
|
|
164863
|
-
setSending(true);
|
|
164864
|
-
setError("");
|
|
164865
|
-
setNotice("");
|
|
164866
|
-
setMessages((current) => current.map((item) => item.id === turn.localAssistantMessageId ? {
|
|
164867
|
-
...item,
|
|
164868
|
-
text: "",
|
|
164869
|
-
status: "sending",
|
|
164870
|
-
runStatus: "accepted"
|
|
164871
|
-
} : item));
|
|
164872
|
-
try {
|
|
164873
|
-
const result = await callArkme("arko.ask", {
|
|
164874
|
-
text: turn.text,
|
|
164875
|
-
sessionId: turn.sessionId,
|
|
164876
|
-
clientTurnUid: turn.clientTurnUid,
|
|
164877
|
-
waitSeconds: 1,
|
|
164878
|
-
...turn.modelRouteKey === void 0 ? {} : { modelRouteKey: turn.modelRouteKey },
|
|
164879
|
-
...turn.replyToRunUid === void 0 ? {} : { replyToRunUid: turn.replyToRunUid },
|
|
164880
|
-
...turn.replyToAssistantMsgId === void 0 ? {} : { replyToAssistantMsgId: turn.replyToAssistantMsgId }
|
|
164881
|
-
});
|
|
164882
|
-
if (!alive.current) return false;
|
|
164883
|
-
removeArkoPendingTurn(turn.userId);
|
|
164884
|
-
setPendingTurn((current) => current?.clientTurnUid === turn.clientTurnUid ? void 0 : current);
|
|
164885
|
-
setSession((current) => current === void 0 ? current : {
|
|
164886
|
-
...current,
|
|
164887
|
-
sessionId: result.sessionId
|
|
164888
|
-
});
|
|
164889
|
-
if (result.profile !== void 0 && profileUserId !== void 0) arkmeArkoProfileStore.setProfile(profileUserId, result.profile);
|
|
164890
|
-
const runStatus = result.run?.status ?? result.status;
|
|
164891
|
-
const runActive = isActiveRunStatus(runStatus);
|
|
164892
|
-
const hasVisibleReasoning = result.reasoning.trim() !== "" && (runActive || !isActivityPlaceholderText(result.reasoning));
|
|
164893
|
-
setMessages((current) => mergeHistory(current.map((item) => item.id === turn.localUserMessageId ? {
|
|
164894
|
-
...item,
|
|
164895
|
-
id: `history:${String(result.userMsgId)}`,
|
|
164896
|
-
messageId: result.userMsgId,
|
|
164897
|
-
sessionId: result.sessionId
|
|
164898
|
-
} : item.id === turn.localAssistantMessageId ? {
|
|
164899
|
-
id: `history:${String(result.assistantMsgId)}`,
|
|
164900
|
-
presentationKey: item.presentationKey ?? item.id,
|
|
164901
|
-
messageId: result.assistantMsgId,
|
|
164902
|
-
sessionId: result.sessionId,
|
|
164903
|
-
role: "assistant",
|
|
164904
|
-
text: resultText(result),
|
|
164905
|
-
status: runActive ? "sending" : result.errorMessage === void 0 ? "done" : "error",
|
|
164906
|
-
assistantMsgId: result.assistantMsgId,
|
|
164907
|
-
...item.createdAtMillis === void 0 ? {} : { createdAtMillis: item.createdAtMillis },
|
|
164908
|
-
...hasVisibleReasoning ? { reasoning: result.reasoning } : {},
|
|
164909
|
-
...result.runUid === void 0 ? {} : { runUid: result.runUid },
|
|
164910
|
-
runStatus
|
|
164911
|
-
} : item), []));
|
|
164912
|
-
if (runActive && result.runUid !== void 0) {
|
|
164913
|
-
handedOffToPolling = true;
|
|
164914
|
-
setActiveRun({
|
|
164915
|
-
sessionId: result.sessionId,
|
|
164916
|
-
assistantMsgId: result.assistantMsgId,
|
|
164917
|
-
runUid: result.runUid
|
|
164918
|
-
});
|
|
164919
|
-
}
|
|
164920
|
-
return true;
|
|
164921
|
-
} catch (caught) {
|
|
164922
|
-
if (!alive.current) return false;
|
|
164923
|
-
const message = errorMessage$8(caught);
|
|
164924
|
-
if (!(caught instanceof ArkmeClientError) || caught.body.retryable) {
|
|
164925
|
-
setPendingTurn(turn);
|
|
164926
|
-
writeArkoPendingTurn(turn);
|
|
164927
|
-
setError(`Arko 发送结果暂未确认:${message}。请重试确认,系统会复用同一次请求,不会重复执行。`);
|
|
164928
|
-
setMessages((current) => current.map((item) => item.id === turn.localAssistantMessageId ? {
|
|
164929
|
-
...item,
|
|
164930
|
-
role: "assistant",
|
|
164931
|
-
text: "",
|
|
164932
|
-
status: "error"
|
|
164933
|
-
} : item));
|
|
164934
|
-
} else {
|
|
164935
|
-
removeArkoPendingTurn(turn.userId);
|
|
164936
|
-
setPendingTurn((current) => current?.clientTurnUid === turn.clientTurnUid ? void 0 : current);
|
|
164937
|
-
setError(message);
|
|
164938
|
-
setMessages((current) => current.map((item) => item.id === turn.localAssistantMessageId ? {
|
|
164939
|
-
...item,
|
|
164940
|
-
role: "assistant",
|
|
164941
|
-
text: message,
|
|
164942
|
-
status: "error"
|
|
164943
|
-
} : item));
|
|
164944
|
-
}
|
|
164945
|
-
return false;
|
|
164946
|
-
} finally {
|
|
164947
|
-
sendInFlightRef.current = false;
|
|
164948
|
-
if (!handedOffToPolling) setSending(false);
|
|
164949
|
-
}
|
|
164950
|
-
}, [
|
|
164951
|
-
activeRun,
|
|
164952
|
-
composerDraftKey,
|
|
164953
|
-
profileUserId,
|
|
164954
|
-
sending
|
|
164955
|
-
]);
|
|
164956
|
-
const interactionLocked = sending || pendingTurn !== void 0 || activeRun !== void 0;
|
|
164957
|
-
const sendDisabled = loading || interactionLocked || clearing || selectingModel || session === void 0 || profileUserId === void 0;
|
|
164958
|
-
const inputDisabled = loading || interactionLocked || session === void 0 || profileUserId === void 0;
|
|
164959
|
-
const send = (0, react$1.useCallback)(async (presetText) => {
|
|
164960
|
-
const text = (presetText ?? serializeArkmeComposerDraft(arkmeComposerDraftStore.get(composerDraftKey)).text).trim();
|
|
164961
|
-
if (text === "" || sendInFlightRef.current || modelSelectionInFlightRef.current || clearInFlightRef.current || sendDisabled || session === void 0 || profileUserId === void 0 || composerDraftKey === void 0) return false;
|
|
164962
|
-
if (text.length > 61440) {
|
|
164963
|
-
setError("内容长度超过上限,请删减后再发送");
|
|
164964
|
-
return false;
|
|
164965
|
-
}
|
|
164966
|
-
const continuation = latestContinuation(messages, session.sessionId);
|
|
164967
|
-
const createdAtMillis = Date.now();
|
|
164968
|
-
const turn = {
|
|
164969
|
-
userId: profileUserId,
|
|
164970
|
-
sessionId: session.sessionId,
|
|
164971
|
-
clientTurnUid: crypto.randomUUID(),
|
|
164972
|
-
text,
|
|
164973
|
-
createdAtMillis,
|
|
164974
|
-
localUserMessageId: crypto.randomUUID(),
|
|
164975
|
-
localAssistantMessageId: crypto.randomUUID(),
|
|
164976
|
-
...continuation === void 0 ? { ...catalog === void 0 ? {} : { modelRouteKey: catalog.effectiveRouteKey } } : {
|
|
164977
|
-
replyToRunUid: continuation.runUid,
|
|
164978
|
-
replyToAssistantMsgId: continuation.assistantMsgId
|
|
164979
|
-
}
|
|
164980
|
-
};
|
|
164981
|
-
writeArkoPendingTurn(turn);
|
|
164982
|
-
setPendingTurn(turn);
|
|
164983
|
-
if (presetText === void 0) arkmeComposerDraftStore.clear(composerDraftKey);
|
|
164984
|
-
setMessages((current) => [
|
|
164985
|
-
...current,
|
|
164986
|
-
{
|
|
164987
|
-
id: turn.localUserMessageId,
|
|
164988
|
-
presentationKey: turn.localUserMessageId,
|
|
164989
|
-
sessionId: turn.sessionId,
|
|
164990
|
-
role: "user",
|
|
164991
|
-
text,
|
|
164992
|
-
status: "done",
|
|
164993
|
-
createdAtMillis
|
|
164994
|
-
},
|
|
164995
|
-
{
|
|
164996
|
-
id: turn.localAssistantMessageId,
|
|
164997
|
-
presentationKey: turn.localAssistantMessageId,
|
|
164998
|
-
sessionId: turn.sessionId,
|
|
164999
|
-
role: "assistant",
|
|
165000
|
-
text: "",
|
|
165001
|
-
status: "sending",
|
|
165002
|
-
runStatus: "accepted",
|
|
165003
|
-
createdAtMillis: createdAtMillis + 1
|
|
165004
|
-
}
|
|
165005
|
-
]);
|
|
165006
|
-
return await submitTurn(turn);
|
|
165007
|
-
}, [
|
|
165008
|
-
catalog,
|
|
165009
|
-
composerDraftKey,
|
|
165010
|
-
messages,
|
|
165011
|
-
profileUserId,
|
|
165012
|
-
sendDisabled,
|
|
165013
|
-
session,
|
|
165014
|
-
submitTurn
|
|
165015
|
-
]);
|
|
165016
|
-
const selectModel = (0, react$1.useCallback)(async (routeKey) => {
|
|
165017
|
-
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;
|
|
165018
|
-
modelSelectionInFlightRef.current = true;
|
|
165019
|
-
setSelectingModel(true);
|
|
165020
|
-
setError("");
|
|
165021
|
-
try {
|
|
165022
|
-
const next = await callArkme("arko.model.activate", { routeKey });
|
|
165023
|
-
if (!alive.current) return false;
|
|
165024
|
-
setCatalog(next);
|
|
165025
|
-
return true;
|
|
165026
|
-
} catch (caught) {
|
|
165027
|
-
setError(errorMessage$8(caught));
|
|
165028
|
-
return false;
|
|
165029
|
-
} finally {
|
|
165030
|
-
modelSelectionInFlightRef.current = false;
|
|
165031
|
-
setSelectingModel(false);
|
|
165032
|
-
}
|
|
165033
|
-
}, [
|
|
165034
|
-
catalog,
|
|
165035
|
-
clearing,
|
|
165036
|
-
interactionLocked,
|
|
165037
|
-
loading
|
|
165038
|
-
]);
|
|
165039
|
-
const cancelActiveRun = (0, react$1.useCallback)(async () => {
|
|
165040
|
-
if (activeRun === void 0 || cancelling) return false;
|
|
165041
|
-
setCancelling(true);
|
|
165042
|
-
setError("");
|
|
165043
|
-
try {
|
|
165044
|
-
await callArkme("arko.cancel", {
|
|
165045
|
-
sessionId: activeRun.sessionId,
|
|
165046
|
-
assistantMsgId: activeRun.assistantMsgId,
|
|
165047
|
-
runUid: activeRun.runUid
|
|
165048
|
-
});
|
|
165049
|
-
setNotice("已请求停止当前任务,正在确认最终状态");
|
|
165050
|
-
return true;
|
|
165051
|
-
} catch (caught) {
|
|
165052
|
-
setError(tr$1("停止 Arko 任务失败:{v0}", { v0: errorMessage$8(caught) }));
|
|
165053
|
-
return false;
|
|
165054
|
-
} finally {
|
|
165055
|
-
setCancelling(false);
|
|
165056
|
-
}
|
|
165057
|
-
}, [activeRun, cancelling]);
|
|
165058
|
-
const clearContext = (0, react$1.useCallback)(async () => {
|
|
165059
|
-
if (clearInFlightRef.current || sendInFlightRef.current || modelSelectionInFlightRef.current || loading || interactionLocked || clearing) return;
|
|
165060
|
-
clearInFlightRef.current = true;
|
|
165061
|
-
setClearing(true);
|
|
165062
|
-
setError("");
|
|
165063
|
-
setNotice("");
|
|
165064
|
-
try {
|
|
165065
|
-
const nextSession = await callArkme("arko.new-session");
|
|
165066
|
-
if (!alive.current) return;
|
|
165067
|
-
setSession(nextSession);
|
|
165068
|
-
setMessages((current) => [...current, {
|
|
165069
|
-
id: crypto.randomUUID(),
|
|
165070
|
-
role: "divider",
|
|
165071
|
-
text: "新的对话",
|
|
165072
|
-
status: "done",
|
|
165073
|
-
createdAtMillis: Date.now()
|
|
165074
|
-
}]);
|
|
165075
|
-
setNotice("上下文已清除,历史记录仍然保留");
|
|
165076
|
-
} catch (caught) {
|
|
165077
|
-
setError(errorMessage$8(caught));
|
|
165078
|
-
} finally {
|
|
165079
|
-
clearInFlightRef.current = false;
|
|
165080
|
-
setClearing(false);
|
|
165081
|
-
}
|
|
165082
|
-
}, [
|
|
165083
|
-
clearing,
|
|
165084
|
-
interactionLocked,
|
|
165085
|
-
loading
|
|
165086
|
-
]);
|
|
165087
|
-
return {
|
|
165088
|
-
accountKey,
|
|
165089
|
-
profileUserId,
|
|
165090
|
-
composerDraftKey,
|
|
165091
|
-
draftSnapshot,
|
|
165092
|
-
draft,
|
|
165093
|
-
userProfile,
|
|
165094
|
-
session,
|
|
165095
|
-
catalog,
|
|
165096
|
-
messages,
|
|
165097
|
-
historyOffset,
|
|
165098
|
-
historyError,
|
|
165099
|
-
historyPageError,
|
|
165100
|
-
loading,
|
|
165101
|
-
historyLoading,
|
|
165102
|
-
sending,
|
|
165103
|
-
clearing,
|
|
165104
|
-
selectingModel,
|
|
165105
|
-
cancelling,
|
|
165106
|
-
error,
|
|
165107
|
-
notice,
|
|
165108
|
-
activeRun,
|
|
165109
|
-
pendingTurn,
|
|
165110
|
-
interactionLocked,
|
|
165111
|
-
sendDisabled,
|
|
165112
|
-
inputDisabled,
|
|
165113
|
-
displayName: arkoPresentationName(profile),
|
|
165114
|
-
selectedModel: selectedModelName(catalog),
|
|
165115
|
-
canChooseModel: (catalog?.options.length ?? 0) > 1,
|
|
165116
|
-
continuation: (0, react$1.useMemo)(() => latestContinuation(messages, session?.sessionId), [messages, session?.sessionId]),
|
|
165117
|
-
send,
|
|
165118
|
-
submitTurn,
|
|
165119
|
-
selectModel,
|
|
165120
|
-
cancelActiveRun,
|
|
165121
|
-
clearContext,
|
|
165122
|
-
loadEarlier,
|
|
165123
|
-
retryHistory,
|
|
165124
|
-
setDraft: (text) => arkmeComposerDraftStore.setText(composerDraftKey, text),
|
|
165125
|
-
feedback: setError
|
|
165126
|
-
};
|
|
165127
|
-
}
|
|
165128
|
-
//#endregion
|
|
165129
163493
|
//#region src/harness-conversation-layout-contract.ts
|
|
165130
163494
|
/** Optional, presentation-only exports from the installed Harness runtime. */
|
|
165131
163495
|
const HARNESS_LAYOUT_MODULES = {
|
|
@@ -165595,6 +163959,62 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
165595
163959
|
r$3.displayName = "ArrowsClockwiseIcon";
|
|
165596
163960
|
const m$4 = r$3;
|
|
165597
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
|
|
165598
164018
|
//#region src/client/conversation-composer-presentation.ts
|
|
165599
164019
|
const arkmeConversationComposerMaxHeight = 336;
|
|
165600
164020
|
/** Keep each border property present across target and resize transitions. */
|
|
@@ -166953,7 +165373,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
166953
165373
|
}]))
|
|
166954
165374
|
};
|
|
166955
165375
|
}
|
|
166956
|
-
function errorMessage$
|
|
165376
|
+
function errorMessage$8(error) {
|
|
166957
165377
|
if (error instanceof ArkmeClientError) return error.body.message;
|
|
166958
165378
|
return error instanceof Error ? error.message : String(error);
|
|
166959
165379
|
}
|
|
@@ -167268,7 +165688,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
167268
165688
|
await copyText$3(value);
|
|
167269
165689
|
showStatus("已复制", revision);
|
|
167270
165690
|
} catch (error) {
|
|
167271
|
-
showStatus(errorMessage$
|
|
165691
|
+
showStatus(errorMessage$8(error) || "复制失败,请稍后重试", revision);
|
|
167272
165692
|
}
|
|
167273
165693
|
}, [showStatus]);
|
|
167274
165694
|
const copyLink = (0, react$1.useCallback)(async (items) => {
|
|
@@ -167296,7 +165716,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
167296
165716
|
setSelectedIds(void 0);
|
|
167297
165717
|
showStatus("已复制链接");
|
|
167298
165718
|
} catch (error) {
|
|
167299
|
-
if (revision === revisionRef.current) showStatus(controller.signal.aborted ? "复制链接超时,请重试" : errorMessage$
|
|
165719
|
+
if (revision === revisionRef.current) showStatus(controller.signal.aborted ? "复制链接超时,请重试" : errorMessage$8(error) || "分享失败,请重试");
|
|
167300
165720
|
} finally {
|
|
167301
165721
|
window.clearTimeout(timeout);
|
|
167302
165722
|
if (revision === revisionRef.current) setBusy(void 0);
|
|
@@ -167359,7 +165779,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
167359
165779
|
setPicker((current) => current === void 0 ? current : {
|
|
167360
165780
|
...current,
|
|
167361
165781
|
loading: false,
|
|
167362
|
-
error: controller.signal.aborted ? "转发对象加载超时" : errorMessage$
|
|
165782
|
+
error: controller.signal.aborted ? "转发对象加载超时" : errorMessage$8(error) || "转发对象加载失败"
|
|
167363
165783
|
});
|
|
167364
165784
|
} finally {
|
|
167365
165785
|
window.clearTimeout(timeout);
|
|
@@ -167426,7 +165846,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
167426
165846
|
const warningText = successes.map((success) => success.value.result.warningText?.trim() ?? "").find((value) => value !== "") ?? "转发已完成,附言发送失败";
|
|
167427
165847
|
for (const success of successes) input.onForwarded?.(success.value.target, success.value.result);
|
|
167428
165848
|
if (successes.length === 0) {
|
|
167429
|
-
const message = controller.signal.aborted ? "转发超时,请重试" : errorMessage$
|
|
165849
|
+
const message = controller.signal.aborted ? "转发超时,请重试" : errorMessage$8(results[0]?.reason) || "发送失败,请重试";
|
|
167430
165850
|
setPicker((current) => current === void 0 ? current : {
|
|
167431
165851
|
...current,
|
|
167432
165852
|
error: message
|
|
@@ -167798,6 +166218,14 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
167798
166218
|
}
|
|
167799
166219
|
//#endregion
|
|
167800
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
|
+
]);
|
|
167801
166229
|
const colors$5 = {
|
|
167802
166230
|
text: arkmeTheme.text,
|
|
167803
166231
|
secondary: arkmeTheme.secondary,
|
|
@@ -168300,6 +166728,10 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168300
166728
|
},
|
|
168301
166729
|
stop: { background: colors$5.danger }
|
|
168302
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
|
+
}
|
|
168303
166735
|
function arkoRunActivityLabel(status) {
|
|
168304
166736
|
if (status === "accepted" || status === "queued") return "正在思考";
|
|
168305
166737
|
if (status === "running" || status === "stream_timeout") return tr$1("正在处理");
|
|
@@ -168317,6 +166749,29 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168317
166749
|
function arkoPreservedScrollTop(previousScrollTop, previousScrollHeight, nextScrollHeight) {
|
|
168318
166750
|
return Math.max(0, previousScrollTop + (nextScrollHeight - previousScrollHeight));
|
|
168319
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
|
+
}
|
|
168320
166775
|
function ArkoThinkingPanel({ reasoning, activity }) {
|
|
168321
166776
|
useArkmeLocale();
|
|
168322
166777
|
const [expanded, setExpanded] = (0, react$1.useState)(true);
|
|
@@ -168363,37 +166818,115 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168363
166818
|
})]
|
|
168364
166819
|
});
|
|
168365
166820
|
}
|
|
168366
|
-
function
|
|
168367
|
-
const
|
|
168368
|
-
|
|
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
|
+
};
|
|
168369
166844
|
}
|
|
168370
|
-
function
|
|
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 "任务已处理。";
|
|
166869
|
+
}
|
|
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() {
|
|
168371
166889
|
useArkmeLocale();
|
|
168372
|
-
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;
|
|
168373
166890
|
const bodyRef = (0, react$1.useRef)(null);
|
|
168374
166891
|
const historySentinelRef = (0, react$1.useRef)(null);
|
|
166892
|
+
const historyLoadInFlightRef = (0, react$1.useRef)(false);
|
|
168375
166893
|
const composerInputBoundaryRef = (0, react$1.useRef)(null);
|
|
168376
166894
|
const composerRef = (0, react$1.useRef)(null);
|
|
168377
166895
|
const textareaRef = (0, react$1.useRef)(null);
|
|
168378
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);
|
|
168379
166919
|
const [modelDialogOpen, setModelDialogOpen] = (0, react$1.useState)(false);
|
|
168380
166920
|
const [clearConfirmOpen, setClearConfirmOpen] = (0, react$1.useState)(false);
|
|
168381
|
-
const
|
|
168382
|
-
|
|
168383
|
-
|
|
168384
|
-
|
|
168385
|
-
const selectModel = async (routeKey) => {
|
|
168386
|
-
if (await controller.selectModel(routeKey)) setModelDialogOpen(false);
|
|
168387
|
-
};
|
|
168388
|
-
const clearContext = async () => {
|
|
168389
|
-
setClearConfirmOpen(false);
|
|
168390
|
-
await controller.clearContext();
|
|
168391
|
-
};
|
|
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)();
|
|
168392
166925
|
const detailTriggerRef = (0, react$1.useRef)(null);
|
|
168393
166926
|
const detailBodyRef = (0, react$1.useRef)(null);
|
|
168394
|
-
const detailScope = `${
|
|
166927
|
+
const detailScope = `${authSnapshot.auth?.environment ?? ""}:${String(profileUserId)}:${String(session?.sessionId)}`;
|
|
168395
166928
|
const [detailSelection, setDetailSelection] = (0, react$1.useState)();
|
|
168396
|
-
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;
|
|
168397
166930
|
const detailActivity = detailMessage?.status === "sending" ? arkoRunActivityLabel(detailMessage.runStatus) ?? "等待回复" : detailMessage?.status === "error" ? pendingTurn?.localAssistantMessageId === detailMessage.id ? "发送结果待确认" : "消息处理失败" : void 0;
|
|
168398
166931
|
(0, react$1.useEffect)(() => {
|
|
168399
166932
|
setDetailSelection(void 0);
|
|
@@ -168404,7 +166937,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168404
166937
|
trigger.focus({ preventScroll: true });
|
|
168405
166938
|
setDetailSelection({
|
|
168406
166939
|
scope: detailScope,
|
|
168407
|
-
id
|
|
166940
|
+
id
|
|
168408
166941
|
});
|
|
168409
166942
|
};
|
|
168410
166943
|
const messageActionItems = (0, react$1.useMemo)(() => messages.flatMap((message) => message.role === "divider" || message.messageActionRef === void 0 || message.messageActionConversationRef === void 0 ? [] : [{
|
|
@@ -168433,33 +166966,195 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168433
166966
|
if (bodyRef.current !== null) bodyRef.current.scrollTop = bodyRef.current.scrollHeight;
|
|
168434
166967
|
});
|
|
168435
166968
|
}, []);
|
|
168436
|
-
const lastMessage = messages.at(-1);
|
|
168437
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
|
+
});
|
|
168438
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
|
+
};
|
|
168439
167120
|
}, [
|
|
168440
|
-
|
|
168441
|
-
|
|
168442
|
-
lastMessage?.reasoning,
|
|
167121
|
+
activeRun,
|
|
167122
|
+
profileUserId,
|
|
168443
167123
|
scrollToBottom
|
|
168444
167124
|
]);
|
|
168445
167125
|
const loadEarlier = (0, react$1.useCallback)(async () => {
|
|
167126
|
+
if (historyOffset === void 0 || historyLoadInFlightRef.current) return;
|
|
168446
167127
|
const body = bodyRef.current;
|
|
168447
167128
|
const previousScrollHeight = body?.scrollHeight ?? 0;
|
|
168448
167129
|
const previousScrollTop = body?.scrollTop ?? 0;
|
|
167130
|
+
historyLoadInFlightRef.current = true;
|
|
167131
|
+
setHistoryLoading(true);
|
|
168449
167132
|
try {
|
|
168450
|
-
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("");
|
|
168451
167140
|
requestAnimationFrame(() => {
|
|
168452
167141
|
const target = bodyRef.current;
|
|
168453
|
-
if (target
|
|
167142
|
+
if (target === null) return;
|
|
167143
|
+
target.scrollTop = arkoPreservedScrollTop(previousScrollTop, previousScrollHeight, target.scrollHeight);
|
|
168454
167144
|
});
|
|
168455
|
-
} catch {
|
|
168456
|
-
|
|
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]);
|
|
168457
167152
|
(0, react$1.useEffect)(() => {
|
|
168458
167153
|
const root = bodyRef.current;
|
|
168459
167154
|
const sentinel = historySentinelRef.current;
|
|
168460
|
-
if (loading || historyLoading || historyError !== "" ||
|
|
167155
|
+
if (loading || historyLoading || historyError !== "" || root === null || sentinel === null || historyOffset === void 0) return;
|
|
168461
167156
|
const observer = new IntersectionObserver((entries) => {
|
|
168462
|
-
if (entries[0]?.isIntersecting !== true) return;
|
|
167157
|
+
if (entries[0]?.isIntersecting !== true || historyLoadInFlightRef.current) return;
|
|
168463
167158
|
loadEarlier();
|
|
168464
167159
|
}, {
|
|
168465
167160
|
root,
|
|
@@ -168470,19 +167165,280 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168470
167165
|
observer.disconnect();
|
|
168471
167166
|
};
|
|
168472
167167
|
}, [
|
|
168473
|
-
historyPageError,
|
|
168474
167168
|
historyError,
|
|
168475
167169
|
historyLoading,
|
|
168476
167170
|
historyOffset,
|
|
168477
167171
|
loadEarlier,
|
|
168478
167172
|
loading
|
|
168479
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;
|
|
168480
167308
|
const insertEmoji = (0, react$1.useCallback)((emoji) => {
|
|
168481
167309
|
if (inputDisabled || composerDraftKey === void 0) return false;
|
|
168482
167310
|
const result = textareaRef.current?.insertEmoji(emoji);
|
|
168483
167311
|
if (result === "length-limit") setError("内容长度已达上限,请删减后再添加表情");
|
|
168484
167312
|
return result === "inserted";
|
|
168485
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]);
|
|
168486
167442
|
(0, react$1.useEffect)(() => {
|
|
168487
167443
|
if (!pendingComposerFocusRef.current || loading || interactionLocked || session === void 0 || profileUserId === void 0) return;
|
|
168488
167444
|
pendingComposerFocusRef.current = false;
|
|
@@ -168605,23 +167561,6 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168605
167561
|
"data-arko-message-viewport": true,
|
|
168606
167562
|
style: styles$24.body,
|
|
168607
167563
|
children: [
|
|
168608
|
-
historyPageError && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
168609
|
-
role: "alert",
|
|
168610
|
-
style: {
|
|
168611
|
-
...styles$24.error,
|
|
168612
|
-
...styles$24.feedbackRow
|
|
168613
|
-
},
|
|
168614
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: historyPageError }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
168615
|
-
"data-arkme-feedback": "neutral",
|
|
168616
|
-
type: "button",
|
|
168617
|
-
style: styles$24.retryButton,
|
|
168618
|
-
disabled: historyLoading,
|
|
168619
|
-
onClick: () => {
|
|
168620
|
-
loadEarlier();
|
|
168621
|
-
},
|
|
168622
|
-
children: tr$1("重试加载更早记录")
|
|
168623
|
-
})]
|
|
168624
|
-
}),
|
|
168625
167564
|
notice !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
168626
167565
|
style: styles$24.notice,
|
|
168627
167566
|
children: notice
|
|
@@ -168641,7 +167580,7 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
168641
167580
|
style: styles$24.retryButton,
|
|
168642
167581
|
disabled: historyLoading,
|
|
168643
167582
|
onClick: () => {
|
|
168644
|
-
if (
|
|
167583
|
+
if (historyOffset === void 0) retryHistory();
|
|
168645
167584
|
else loadEarlier();
|
|
168646
167585
|
},
|
|
168647
167586
|
children: historyLoading ? tr$1("加载中...") : tr$1("重新加载")
|
|
@@ -169124,89 +168063,6 @@ globalThis.__ARKME_NATIVE_ARKO__ = carrier;
|
|
|
169124
168063
|
})]
|
|
169125
168064
|
});
|
|
169126
168065
|
}
|
|
169127
|
-
function ArkoNativeConversation({ controller }) {
|
|
169128
|
-
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;
|
|
169129
|
-
const [clearConfirmOpen, setClearConfirmOpen] = (0, react$1.useState)(false);
|
|
169130
|
-
const clearContext = async () => {
|
|
169131
|
-
setClearConfirmOpen(false);
|
|
169132
|
-
await controller.clearContext();
|
|
169133
|
-
};
|
|
169134
|
-
const hint = loading ? "正在恢复会话" : clearing ? "正在清除上下文" : selectingModel ? "正在切换模型" : pendingTurn !== void 0 && !sending ? "请先确认上一次发送结果" : sending ? "等待回复" : continuation === void 0 ? "" : "继续当前任务";
|
|
169135
|
-
if (accountKey === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
169136
|
-
role: "status",
|
|
169137
|
-
children: "正在恢复账号…"
|
|
169138
|
-
});
|
|
169139
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkoNativeSurface, {
|
|
169140
|
-
snapshot: {
|
|
169141
|
-
accountKey,
|
|
169142
|
-
displayName,
|
|
169143
|
-
...session ? { sessionId: session.sessionId } : {},
|
|
169144
|
-
messages,
|
|
169145
|
-
modelCatalog: catalog ?? null,
|
|
169146
|
-
loading,
|
|
169147
|
-
busy: sending || activeRun !== void 0,
|
|
169148
|
-
draft,
|
|
169149
|
-
error: error || historyError,
|
|
169150
|
-
notice: notice || hint,
|
|
169151
|
-
hasMore: typeof historyOffset === "number",
|
|
169152
|
-
historyError: historyPageError,
|
|
169153
|
-
...inputDisabled && activeRun === void 0 ? { inputBlockedReason: hint || "当前输入暂不可用" } : {}
|
|
169154
|
-
},
|
|
169155
|
-
actions: {
|
|
169156
|
-
submit: async (text) => {
|
|
169157
|
-
if (sendDisabled || text.trim() === "" || text.length > 61440) return false;
|
|
169158
|
-
setDraft(text);
|
|
169159
|
-
return await send() === true;
|
|
169160
|
-
},
|
|
169161
|
-
selectModel,
|
|
169162
|
-
cancel: cancelActiveRun,
|
|
169163
|
-
loadEarlier
|
|
169164
|
-
},
|
|
169165
|
-
ui: {
|
|
169166
|
-
clearDisabled: sendDisabled,
|
|
169167
|
-
setDraft: (text) => setDraft(text),
|
|
169168
|
-
clearContext: () => setClearConfirmOpen(true),
|
|
169169
|
-
retry: async () => {
|
|
169170
|
-
if (pendingTurn) await submitTurn(pendingTurn);
|
|
169171
|
-
else await retryHistory();
|
|
169172
|
-
},
|
|
169173
|
-
...pendingTurn ? { retryLabel: "重试确认" } : historyError ? { retryLabel: "重试加载记录" } : {},
|
|
169174
|
-
feedback: setError
|
|
169175
|
-
}
|
|
169176
|
-
}), clearConfirmOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
169177
|
-
role: "dialog",
|
|
169178
|
-
"aria-label": "清除上下文",
|
|
169179
|
-
style: {
|
|
169180
|
-
position: "absolute",
|
|
169181
|
-
inset: 0,
|
|
169182
|
-
zIndex: 30,
|
|
169183
|
-
display: "grid",
|
|
169184
|
-
placeItems: "center",
|
|
169185
|
-
background: "#0004"
|
|
169186
|
-
},
|
|
169187
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
169188
|
-
style: {
|
|
169189
|
-
background: arkmeTheme.base,
|
|
169190
|
-
padding: 24,
|
|
169191
|
-
borderRadius: 12
|
|
169192
|
-
},
|
|
169193
|
-
children: [
|
|
169194
|
-
"清除当前上下文?历史记录仍然保留。",
|
|
169195
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
169196
|
-
onClick: () => setClearConfirmOpen(false),
|
|
169197
|
-
children: "取消"
|
|
169198
|
-
}),
|
|
169199
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
169200
|
-
disabled: sendDisabled,
|
|
169201
|
-
onClick: () => {
|
|
169202
|
-
clearContext();
|
|
169203
|
-
},
|
|
169204
|
-
children: "确认清除"
|
|
169205
|
-
})
|
|
169206
|
-
]
|
|
169207
|
-
})
|
|
169208
|
-
})] });
|
|
169209
|
-
}
|
|
169210
168066
|
//#endregion
|
|
169211
168067
|
//#region src/client/ArkmePrivateCallMenu.tsx
|
|
169212
168068
|
const maskStyle = {
|
|
@@ -201417,7 +200273,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
201417
200273
|
const c$3 = e$24;
|
|
201418
200274
|
//#endregion
|
|
201419
200275
|
//#region package.json
|
|
201420
|
-
var version = "0.1.
|
|
200276
|
+
var version = "0.1.74";
|
|
201421
200277
|
//#endregion
|
|
201422
200278
|
//#region src/client/profile-change-store.ts
|
|
201423
200279
|
let revision = 0;
|
|
@@ -222338,7 +221194,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
|
|
|
222338
221194
|
onPrivateChatOpened: activateSource
|
|
222339
221195
|
}) : ui.mode === "voiceprint" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeVoiceprintSurface, { onBack: () => {
|
|
222340
221196
|
arkmeUi.showRecordings();
|
|
222341
|
-
} }) : 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, {
|
|
222342
221198
|
bot: ui.selectedBot,
|
|
222343
221199
|
onConversationActivity: (bot) => {
|
|
222344
221200
|
arkmeUi.openBotConversation(bot);
|
|
@@ -236869,29 +235725,6 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
|
|
|
236869
235725
|
};
|
|
236870
235726
|
}
|
|
236871
235727
|
//#endregion
|
|
236872
|
-
//#region src/client/ArkmeArkoPanel.tsx
|
|
236873
|
-
/** The workspace keys this single retained panel by authenticated account scope. */
|
|
236874
|
-
function ArkmeArkoPanel({ visible }) {
|
|
236875
|
-
const [visited, setVisited] = (0, react$1.useState)(false);
|
|
236876
|
-
(0, react$1.useEffect)(() => {
|
|
236877
|
-
if (visible) setVisited(true);
|
|
236878
|
-
}, [visible]);
|
|
236879
|
-
if (!visible && !visited) return null;
|
|
236880
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
236881
|
-
"data-arkme-owned": "arko-panel",
|
|
236882
|
-
"aria-hidden": !visible || void 0,
|
|
236883
|
-
...!visible ? { inert: "" } : {},
|
|
236884
|
-
style: {
|
|
236885
|
-
position: "absolute",
|
|
236886
|
-
inset: 0,
|
|
236887
|
-
visibility: visible ? "visible" : "hidden",
|
|
236888
|
-
pointerEvents: visible ? "auto" : "none",
|
|
236889
|
-
zIndex: visible ? 1 : 0
|
|
236890
|
-
},
|
|
236891
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeArkoSurface, { native: true })
|
|
236892
|
-
});
|
|
236893
|
-
}
|
|
236894
|
-
//#endregion
|
|
236895
235728
|
//#region src/client/redesign/contacts/ContactDirectoryAddDialog.tsx
|
|
236896
235729
|
const styles$4 = {
|
|
236897
235730
|
backdrop: {
|
|
@@ -240897,8 +239730,7 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
|
|
|
240897
239730
|
const contactsMode = ui.mode === "source" && ui.productMode === "contacts";
|
|
240898
239731
|
const webLockedHarness = !startupAuthGateEnabled() && authState.auth?.status !== "authenticated";
|
|
240899
239732
|
const harnessVisible = ui.mode === "harness" || webLockedHarness;
|
|
240900
|
-
const
|
|
240901
|
-
const conversationHidden = harnessVisible || contactsMode || arkoVisible;
|
|
239733
|
+
const conversationHidden = harnessVisible || contactsMode;
|
|
240902
239734
|
const conversationActive = !conversationHidden && ui.calendarOpen !== true;
|
|
240903
239735
|
const contactsContextRef = (0, react$1.useRef)({
|
|
240904
239736
|
accountKey: contactsAccountKey,
|
|
@@ -240931,7 +239763,6 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
|
|
|
240931
239763
|
accountScope: contactsAccountKey,
|
|
240932
239764
|
followSession: ui.mode === "harness"
|
|
240933
239765
|
}, contactsAccountKey ?? "guest"),
|
|
240934
|
-
contactsAccountKey !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeArkoPanel, { visible: arkoVisible }, contactsAccountKey),
|
|
240935
239766
|
!webLockedHarness && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
240936
239767
|
"data-arkme-owned": "arkme-conversation-layer",
|
|
240937
239768
|
style: {
|