@makerbi/remodex 2.5.6 → 3.2.0
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/package.json
CHANGED
|
@@ -443,7 +443,8 @@ function createDesktopIpcActionFollower({
|
|
|
443
443
|
// stays idle after opening never delivers them.
|
|
444
444
|
emitNormalizedReviewOverlays(
|
|
445
445
|
threadId,
|
|
446
|
-
normalizedLiveIndexesByThreadId.get(threadId)
|
|
446
|
+
normalizedLiveIndexesByThreadId.get(threadId),
|
|
447
|
+
liveState
|
|
447
448
|
);
|
|
448
449
|
const output = conversationProjector.project(threadId, liveState, {
|
|
449
450
|
includeAllActiveTurns: true,
|
|
@@ -1516,7 +1517,8 @@ function createDesktopIpcActionFollower({
|
|
|
1516
1517
|
}));
|
|
1517
1518
|
emitNormalizedReviewOverlays(
|
|
1518
1519
|
threadId,
|
|
1519
|
-
normalizedLiveIndexesByThreadId.get(threadId)
|
|
1520
|
+
normalizedLiveIndexesByThreadId.get(threadId),
|
|
1521
|
+
liveState
|
|
1520
1522
|
);
|
|
1521
1523
|
emitDesktopSnapshotLifecycleTransition(threadId, liveState);
|
|
1522
1524
|
for (const notification of bootstrapOutput.notifications || []) {
|
|
@@ -1535,7 +1537,8 @@ function createDesktopIpcActionFollower({
|
|
|
1535
1537
|
emitDesktopSnapshotLifecycleTransition(threadId, liveState);
|
|
1536
1538
|
emitNormalizedReviewOverlays(
|
|
1537
1539
|
threadId,
|
|
1538
|
-
normalizedLiveIndexesByThreadId.get(threadId)
|
|
1540
|
+
normalizedLiveIndexesByThreadId.get(threadId),
|
|
1541
|
+
liveState
|
|
1539
1542
|
);
|
|
1540
1543
|
conversationProjector.seed(threadId, liveState);
|
|
1541
1544
|
rememberDesktopLiveProjection(threadId, liveState);
|
|
@@ -1548,7 +1551,8 @@ function createDesktopIpcActionFollower({
|
|
|
1548
1551
|
}
|
|
1549
1552
|
emitNormalizedReviewOverlays(
|
|
1550
1553
|
threadId,
|
|
1551
|
-
normalizedLiveIndexesByThreadId.get(threadId)
|
|
1554
|
+
normalizedLiveIndexesByThreadId.get(threadId),
|
|
1555
|
+
liveState
|
|
1552
1556
|
);
|
|
1553
1557
|
const output = conversationProjector.project(threadId, liveState);
|
|
1554
1558
|
if (resumedAfterStaleYield || output.type === "fullReplace" || output.type === "baseline") {
|
|
@@ -1605,11 +1609,16 @@ function createDesktopIpcActionFollower({
|
|
|
1605
1609
|
rememberDesktopLiveProjection(threadId, liveState);
|
|
1606
1610
|
}
|
|
1607
1611
|
|
|
1608
|
-
function emitNormalizedReviewOverlays(threadId, index) {
|
|
1612
|
+
function emitNormalizedReviewOverlays(threadId, index, projectedState) {
|
|
1609
1613
|
if (!index || !Array.isArray(index.pendingReviewOverlays)) {
|
|
1610
1614
|
return;
|
|
1611
1615
|
}
|
|
1612
1616
|
const overlays = index.pendingReviewOverlays.splice(0);
|
|
1617
|
+
const projectedTurnIds = new Set(
|
|
1618
|
+
(Array.isArray(projectedState?.turns) ? projectedState.turns : [])
|
|
1619
|
+
.map(turnIdOf)
|
|
1620
|
+
.filter(Boolean)
|
|
1621
|
+
);
|
|
1613
1622
|
const fingerprints = normalizedReviewFingerprintsByThreadId.get(threadId) || new Map();
|
|
1614
1623
|
for (const overlay of overlays) {
|
|
1615
1624
|
// Reviews on turns in the projected live tail may also be emitted by
|
|
@@ -1626,6 +1635,16 @@ function createDesktopIpcActionFollower({
|
|
|
1626
1635
|
if (!reviewId || !status || !item?.action) {
|
|
1627
1636
|
continue;
|
|
1628
1637
|
}
|
|
1638
|
+
// Completed approved reviews are ordinary tool history. Replaying every
|
|
1639
|
+
// normalized-history review after a bounded canonical read appends old
|
|
1640
|
+
// rows at the phone's live tail, detached from their original disclosure.
|
|
1641
|
+
// The projected tail still emits its approvals so they reconcile in the
|
|
1642
|
+
// owning turn; non-approved outcomes remain global because they may need
|
|
1643
|
+
// the user's attention.
|
|
1644
|
+
if (normalizeToken(status) === "approved"
|
|
1645
|
+
&& !projectedTurnIds.has(readString(overlay.turnId))) {
|
|
1646
|
+
continue;
|
|
1647
|
+
}
|
|
1629
1648
|
const fingerprint = createHash("sha256")
|
|
1630
1649
|
.update(JSON.stringify({ status, item }))
|
|
1631
1650
|
.digest("hex");
|
|
@@ -1846,11 +1865,9 @@ function createDesktopIpcActionFollower({
|
|
|
1846
1865
|
return {
|
|
1847
1866
|
threadId,
|
|
1848
1867
|
method: "thread-follower-start-turn",
|
|
1849
|
-
params: {
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
turnStartParams: params,
|
|
1853
|
-
},
|
|
1868
|
+
params: { conversationId: threadId },
|
|
1869
|
+
senderRequestId: requestId,
|
|
1870
|
+
turnStartParams: params,
|
|
1854
1871
|
};
|
|
1855
1872
|
}
|
|
1856
1873
|
if (method === "turn/steer") {
|
|
@@ -1870,7 +1887,8 @@ function createDesktopIpcActionFollower({
|
|
|
1870
1887
|
method: "thread-follower-interrupt-turn",
|
|
1871
1888
|
params: {
|
|
1872
1889
|
conversationId: threadId,
|
|
1873
|
-
|
|
1890
|
+
mode: "user-stop",
|
|
1891
|
+
expectedTurnId: readString(params.turnId) || readString(params.turn_id),
|
|
1874
1892
|
},
|
|
1875
1893
|
};
|
|
1876
1894
|
}
|
|
@@ -1889,11 +1907,11 @@ function createDesktopIpcActionFollower({
|
|
|
1889
1907
|
|
|
1890
1908
|
function submitDesktopFollowerRequest(route, originalMessage) {
|
|
1891
1909
|
Promise.resolve()
|
|
1892
|
-
.then(() =>
|
|
1893
|
-
.then(async (
|
|
1910
|
+
.then(() => resolveFollowerRequest(route))
|
|
1911
|
+
.then(async (resolvedRequest) => {
|
|
1894
1912
|
if (route.method === "thread-follower-start-turn") {
|
|
1895
1913
|
try {
|
|
1896
|
-
await syncDesktopOwnerRuntimeSettings(route.threadId,
|
|
1914
|
+
await syncDesktopOwnerRuntimeSettings(route.threadId, resolvedRequest.turnStartParams);
|
|
1897
1915
|
} catch (error) {
|
|
1898
1916
|
// The actual turn has not reached Desktop yet. Even if the settings
|
|
1899
1917
|
// request timed out after being applied, continuing through the local
|
|
@@ -1902,16 +1920,16 @@ function createDesktopIpcActionFollower({
|
|
|
1902
1920
|
}
|
|
1903
1921
|
}
|
|
1904
1922
|
return {
|
|
1905
|
-
|
|
1906
|
-
result: await ipc.sendRequest(route.method,
|
|
1923
|
+
resolvedRequest,
|
|
1924
|
+
result: await ipc.sendRequest(route.method, resolvedRequest.params),
|
|
1907
1925
|
};
|
|
1908
1926
|
})
|
|
1909
|
-
.then(({
|
|
1927
|
+
.then(({ resolvedRequest, result }) => {
|
|
1910
1928
|
const appServerResult = appServerResultForFollowerRequest(route.method, result);
|
|
1911
1929
|
if (route.method === "thread-follower-start-turn") {
|
|
1912
1930
|
commitPhoneRuntimeSettings(
|
|
1913
1931
|
route.threadId,
|
|
1914
|
-
|
|
1932
|
+
resolvedRequest.turnStartParams,
|
|
1915
1933
|
readTurnIdFromAppServerResult(appServerResult)
|
|
1916
1934
|
);
|
|
1917
1935
|
}
|
|
@@ -2007,19 +2025,34 @@ function createDesktopIpcActionFollower({
|
|
|
2007
2025
|
|
|
2008
2026
|
// Desktop-followed turn starts must apply the same param normalization as
|
|
2009
2027
|
// requests forwarded straight to the local app-server.
|
|
2010
|
-
async function
|
|
2028
|
+
async function resolveFollowerRequest(route) {
|
|
2011
2029
|
if (route.method !== "thread-follower-start-turn") {
|
|
2012
|
-
return
|
|
2030
|
+
return {
|
|
2031
|
+
params: route.params,
|
|
2032
|
+
turnStartParams: null,
|
|
2033
|
+
};
|
|
2013
2034
|
}
|
|
2014
2035
|
|
|
2015
2036
|
const normalized = await Promise.resolve(
|
|
2016
|
-
normalizeTurnStartParams(cloneJSON(route.
|
|
2037
|
+
normalizeTurnStartParams(cloneJSON(route.turnStartParams))
|
|
2017
2038
|
);
|
|
2018
2039
|
const turnStartParams = normalized && typeof normalized === "object" && !Array.isArray(normalized)
|
|
2019
2040
|
? normalized
|
|
2020
|
-
: route.
|
|
2041
|
+
: route.turnStartParams;
|
|
2042
|
+
const request = cloneJSON(turnStartParams);
|
|
2043
|
+
if (!readString(request.clientUserMessageId)) {
|
|
2044
|
+
request.clientUserMessageId = route.senderRequestId;
|
|
2045
|
+
}
|
|
2021
2046
|
return {
|
|
2022
|
-
|
|
2047
|
+
params: {
|
|
2048
|
+
...route.params,
|
|
2049
|
+
turnStart: {
|
|
2050
|
+
request,
|
|
2051
|
+
context: {
|
|
2052
|
+
inheritThreadSettings: true,
|
|
2053
|
+
},
|
|
2054
|
+
},
|
|
2055
|
+
},
|
|
2023
2056
|
turnStartParams,
|
|
2024
2057
|
};
|
|
2025
2058
|
}
|
|
@@ -454,14 +454,24 @@ function buildConversationStateFromThread(thread, {
|
|
|
454
454
|
now,
|
|
455
455
|
});
|
|
456
456
|
|
|
457
|
-
|
|
457
|
+
const state = {
|
|
458
458
|
id: threadId,
|
|
459
|
+
forkedFromId: previous?.forkedFromId || null,
|
|
459
460
|
hostId,
|
|
460
461
|
turns,
|
|
461
462
|
requests: cloneJSON(previous?.requests || []),
|
|
462
463
|
createdAt: createdAtMs,
|
|
463
464
|
updatedAt: updatedAtMs,
|
|
465
|
+
recencyAt: updatedAtMs,
|
|
464
466
|
title: readString(thread?.name) || previous?.title || null,
|
|
467
|
+
source: readString(thread?.source) || previous?.source || "vscode",
|
|
468
|
+
agentNickname: previous?.agentNickname || null,
|
|
469
|
+
threadSource: readString(thread?.threadSource) || previous?.threadSource || "user",
|
|
470
|
+
historyMode: previous?.historyMode || "legacy",
|
|
471
|
+
parentThreadId: previous?.parentThreadId || null,
|
|
472
|
+
mode: previous?.mode || "default",
|
|
473
|
+
threadStartKind: previous?.threadStartKind || "default",
|
|
474
|
+
modelProvider: readString(thread?.modelProvider) || previous?.modelProvider || "openai",
|
|
465
475
|
latestModel,
|
|
466
476
|
latestReasoningEffort: previous?.latestReasoningEffort || null,
|
|
467
477
|
latestServiceTier: previous?.latestServiceTier || null,
|
|
@@ -488,7 +498,10 @@ function buildConversationStateFromThread(thread, {
|
|
|
488
498
|
workspaceBrowserRoot: previous?.workspaceBrowserRoot || null,
|
|
489
499
|
projectlessOutputDirectory: previous?.projectlessOutputDirectory || null,
|
|
490
500
|
currentPermissions: cloneJSON(previous?.currentPermissions || null),
|
|
501
|
+
sessionId: readString(thread?.sessionId) || previous?.sessionId || null,
|
|
491
502
|
};
|
|
503
|
+
synchronizeDesktopConversationCompatibility(state);
|
|
504
|
+
return state;
|
|
492
505
|
}
|
|
493
506
|
|
|
494
507
|
function mergeConversationTurnsFromThread(threadTurns, {
|
|
@@ -552,7 +565,7 @@ function createEmptyConversationState(threadId, {
|
|
|
552
565
|
cwd = "",
|
|
553
566
|
} = {}) {
|
|
554
567
|
const timestamp = now();
|
|
555
|
-
|
|
568
|
+
const state = {
|
|
556
569
|
id: threadId,
|
|
557
570
|
hostId,
|
|
558
571
|
turns: [],
|
|
@@ -587,6 +600,189 @@ function createEmptyConversationState(threadId, {
|
|
|
587
600
|
projectlessOutputDirectory: null,
|
|
588
601
|
currentPermissions: null,
|
|
589
602
|
};
|
|
603
|
+
synchronizeDesktopConversationCompatibility(state);
|
|
604
|
+
return state;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Desktop 26.825 moved rendered history to a canonical entity graph. It still
|
|
608
|
+
// accepts legacy turns during normalization, but unified-timeline selectors now
|
|
609
|
+
// assume the graph and several nested collections exist. Keep the bridge's
|
|
610
|
+
// mutable legacy turns for app-server event handling, and mirror them into the
|
|
611
|
+
// current Desktop shape before every stream broadcast.
|
|
612
|
+
function synchronizeDesktopConversationCompatibility(state) {
|
|
613
|
+
if (!state || typeof state !== "object" || Array.isArray(state)) {
|
|
614
|
+
return state;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const turns = Array.isArray(state.turns) ? state.turns : [];
|
|
618
|
+
const entries = [];
|
|
619
|
+
const entitiesByKey = {};
|
|
620
|
+
for (const turn of turns) {
|
|
621
|
+
const turnId = readString(turn?.turnId) || readString(turn?.id);
|
|
622
|
+
if (!turnId) {
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
turn.params = normalizeTurnParamsCompatibility(turn.params, {
|
|
626
|
+
cwd: readString(turn.params?.cwd) || readString(state.cwd),
|
|
627
|
+
});
|
|
628
|
+
turn.items = Array.isArray(turn.items) ? turn.items : [];
|
|
629
|
+
turn.hookRuns = Array.isArray(turn.hookRuns) ? turn.hookRuns : [];
|
|
630
|
+
const key = `turn:${turnId}`;
|
|
631
|
+
entries.push({ key, value: key });
|
|
632
|
+
const { id: _legacyId, ...canonicalTurn } = turn;
|
|
633
|
+
entitiesByKey[key] = {
|
|
634
|
+
...canonicalTurn,
|
|
635
|
+
turnId,
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
const islandId = "tail:0";
|
|
640
|
+
state.turnHistory = {
|
|
641
|
+
kind: "canonical",
|
|
642
|
+
history: {
|
|
643
|
+
entitiesByKey,
|
|
644
|
+
generation: 0,
|
|
645
|
+
isComplete: true,
|
|
646
|
+
islands: [{
|
|
647
|
+
id: islandId,
|
|
648
|
+
entries,
|
|
649
|
+
olderBoundary: {
|
|
650
|
+
status: "exhausted",
|
|
651
|
+
boundaryId: `${islandId}:older`,
|
|
652
|
+
},
|
|
653
|
+
newerBoundary: {
|
|
654
|
+
status: "exhausted",
|
|
655
|
+
boundaryId: `${islandId}:newer`,
|
|
656
|
+
},
|
|
657
|
+
}],
|
|
658
|
+
},
|
|
659
|
+
};
|
|
660
|
+
state.turnsPagination = {
|
|
661
|
+
olderCursor: null,
|
|
662
|
+
oldestLoadedTurnId: readString(turns[0]?.turnId) || readString(turns[0]?.id) || null,
|
|
663
|
+
isLoadingOlder: false,
|
|
664
|
+
hasLoadedOldest: true,
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
const latestParams = [...turns]
|
|
668
|
+
.reverse()
|
|
669
|
+
.map((turn) => turn?.params)
|
|
670
|
+
.find((params) => params && typeof params === "object") || null;
|
|
671
|
+
const sandboxPolicy = normalizeSandboxPolicyCompatibility(
|
|
672
|
+
latestParams?.sandboxPolicy || state.currentPermissions?.sandboxPolicy
|
|
673
|
+
);
|
|
674
|
+
if (sandboxPolicy) {
|
|
675
|
+
const runtimeWorkspaceRoots = Array.isArray(latestParams?.runtimeWorkspaceRoots)
|
|
676
|
+
? cloneJSON(latestParams.runtimeWorkspaceRoots)
|
|
677
|
+
: Array.isArray(state.currentPermissions?.runtimeWorkspaceRoots)
|
|
678
|
+
? cloneJSON(state.currentPermissions.runtimeWorkspaceRoots)
|
|
679
|
+
: [];
|
|
680
|
+
state.currentPermissions = {
|
|
681
|
+
activePermissionProfile: cloneJSON(
|
|
682
|
+
latestParams?.activePermissionProfile
|
|
683
|
+
?? state.currentPermissions?.activePermissionProfile
|
|
684
|
+
?? permissionProfileFromId(latestParams?.permissions)
|
|
685
|
+
),
|
|
686
|
+
approvalPolicy: latestParams?.approvalPolicy
|
|
687
|
+
?? state.currentPermissions?.approvalPolicy
|
|
688
|
+
?? "on-request",
|
|
689
|
+
approvalsReviewer: latestParams?.approvalsReviewer
|
|
690
|
+
?? state.currentPermissions?.approvalsReviewer
|
|
691
|
+
?? "user",
|
|
692
|
+
runtimeWorkspaceRoots,
|
|
693
|
+
sandboxPolicy,
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
state.recencyAt = Number.isFinite(state.recencyAt) ? state.recencyAt : state.updatedAt;
|
|
698
|
+
state.source ||= "vscode";
|
|
699
|
+
state.threadSource ||= "user";
|
|
700
|
+
state.historyMode ||= "legacy";
|
|
701
|
+
state.mode ||= "default";
|
|
702
|
+
state.threadStartKind ||= "default";
|
|
703
|
+
state.modelProvider ||= "openai";
|
|
704
|
+
state.latestThreadSettings = {
|
|
705
|
+
cwd: readString(latestParams?.cwd) || readString(state.cwd) || null,
|
|
706
|
+
approvalPolicy: latestParams?.approvalPolicy ?? state.currentPermissions?.approvalPolicy ?? null,
|
|
707
|
+
approvalsReviewer: latestParams?.approvalsReviewer
|
|
708
|
+
?? state.currentPermissions?.approvalsReviewer
|
|
709
|
+
?? null,
|
|
710
|
+
...(sandboxPolicy ? { sandboxPolicy } : {}),
|
|
711
|
+
activePermissionProfile: cloneJSON(state.currentPermissions?.activePermissionProfile ?? null),
|
|
712
|
+
model: readString(state.latestThreadSettings?.model)
|
|
713
|
+
|| readString(latestParams?.model)
|
|
714
|
+
|| readString(state.latestModel)
|
|
715
|
+
|| null,
|
|
716
|
+
modelProvider: readString(state.latestThreadSettings?.modelProvider)
|
|
717
|
+
|| readString(state.modelProvider)
|
|
718
|
+
|| "openai",
|
|
719
|
+
serviceTier: readString(state.latestThreadSettings?.serviceTier)
|
|
720
|
+
|| readString(latestParams?.serviceTier)
|
|
721
|
+
|| readString(state.latestServiceTier)
|
|
722
|
+
|| null,
|
|
723
|
+
effort: state.latestThreadSettings?.effort
|
|
724
|
+
?? latestParams?.effort
|
|
725
|
+
?? state.latestReasoningEffort
|
|
726
|
+
?? null,
|
|
727
|
+
summary: latestParams?.summary ?? state.latestThreadSettings?.summary ?? "none",
|
|
728
|
+
collaborationMode: cloneJSON(
|
|
729
|
+
state.latestThreadSettings?.collaborationMode
|
|
730
|
+
|| latestParams?.collaborationMode
|
|
731
|
+
|| state.latestCollaborationMode
|
|
732
|
+
|| null
|
|
733
|
+
),
|
|
734
|
+
multiAgentMode: latestParams?.multiAgentMode
|
|
735
|
+
?? state.latestThreadSettings?.multiAgentMode
|
|
736
|
+
?? null,
|
|
737
|
+
personality: latestParams?.personality
|
|
738
|
+
?? state.latestThreadSettings?.personality
|
|
739
|
+
?? null,
|
|
740
|
+
};
|
|
741
|
+
return state;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
function normalizeTurnParamsCompatibility(params, { cwd = "" } = {}) {
|
|
745
|
+
const normalized = params && typeof params === "object" && !Array.isArray(params)
|
|
746
|
+
? params
|
|
747
|
+
: {};
|
|
748
|
+
normalized.input = Array.isArray(normalized.input) ? normalized.input : [];
|
|
749
|
+
normalized.attachments = Array.isArray(normalized.attachments) ? normalized.attachments : [];
|
|
750
|
+
normalized.cwd = readString(normalized.cwd) || readString(cwd) || null;
|
|
751
|
+
normalized.summary ??= "none";
|
|
752
|
+
normalized.personality ??= null;
|
|
753
|
+
normalized.outputSchema ??= null;
|
|
754
|
+
normalized.collaborationMode ??= null;
|
|
755
|
+
const sandboxPolicy = normalizeSandboxPolicyCompatibility(normalized.sandboxPolicy);
|
|
756
|
+
if (sandboxPolicy) {
|
|
757
|
+
normalized.sandboxPolicy = sandboxPolicy;
|
|
758
|
+
}
|
|
759
|
+
return normalized;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function normalizeSandboxPolicyCompatibility(policy) {
|
|
763
|
+
if (!policy || typeof policy !== "object" || Array.isArray(policy)) {
|
|
764
|
+
return null;
|
|
765
|
+
}
|
|
766
|
+
const normalized = cloneJSON(policy);
|
|
767
|
+
if (normalizeToken(normalized.type) === "workspacewrite") {
|
|
768
|
+
normalized.type = "workspaceWrite";
|
|
769
|
+
normalized.writableRoots = Array.isArray(normalized.writableRoots)
|
|
770
|
+
? normalized.writableRoots
|
|
771
|
+
: [];
|
|
772
|
+
normalized.excludeSlashTmp = Boolean(normalized.excludeSlashTmp);
|
|
773
|
+
normalized.excludeTmpdirEnvVar = Boolean(normalized.excludeTmpdirEnvVar);
|
|
774
|
+
normalized.networkAccess = Boolean(normalized.networkAccess);
|
|
775
|
+
}
|
|
776
|
+
if (normalizeToken(normalized.type) === "readonly") {
|
|
777
|
+
normalized.type = "readOnly";
|
|
778
|
+
normalized.networkAccess = Boolean(normalized.networkAccess);
|
|
779
|
+
}
|
|
780
|
+
return normalized;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
function permissionProfileFromId(value) {
|
|
784
|
+
const id = readString(value);
|
|
785
|
+
return id ? { id, extends: null } : null;
|
|
590
786
|
}
|
|
591
787
|
|
|
592
788
|
function buildConversationTurn(turn, {
|
|
@@ -596,7 +792,7 @@ function buildConversationTurn(turn, {
|
|
|
596
792
|
now = () => Date.now(),
|
|
597
793
|
} = {}) {
|
|
598
794
|
const turnId = readString(turn?.id) || readString(turn?.turnId) || readString(turn?.turn_id);
|
|
599
|
-
const params = cloneJSON(previousTurn?.params || {
|
|
795
|
+
const params = normalizeTurnParamsCompatibility(cloneJSON(previousTurn?.params || {
|
|
600
796
|
threadId,
|
|
601
797
|
input: [],
|
|
602
798
|
cwd: cwd || null,
|
|
@@ -611,7 +807,7 @@ function buildConversationTurn(turn, {
|
|
|
611
807
|
outputSchema: null,
|
|
612
808
|
collaborationMode: null,
|
|
613
809
|
attachments: [],
|
|
614
|
-
});
|
|
810
|
+
}), { cwd });
|
|
615
811
|
const builtTurn = {
|
|
616
812
|
id: turnId,
|
|
617
813
|
turnId,
|
|
@@ -678,6 +874,9 @@ function applyPendingTurnStartParams(
|
|
|
678
874
|
...turn.params,
|
|
679
875
|
...cloneJSON(pendingParams),
|
|
680
876
|
};
|
|
877
|
+
turn.params = normalizeTurnParamsCompatibility(turn.params, {
|
|
878
|
+
cwd: readString(turn.params?.cwd) || readString(conversation?.cwd),
|
|
879
|
+
});
|
|
681
880
|
normalizeTurnInitialPrompt(turn);
|
|
682
881
|
}
|
|
683
882
|
|
|
@@ -1262,6 +1461,7 @@ module.exports = {
|
|
|
1262
1461
|
readThreadIdFromParams,
|
|
1263
1462
|
readTurnIdFromParams,
|
|
1264
1463
|
readTurnIdFromTurn,
|
|
1464
|
+
synchronizeDesktopConversationCompatibility,
|
|
1265
1465
|
timestampSecondsToMs,
|
|
1266
1466
|
upsertItem,
|
|
1267
1467
|
upsertTurn,
|
|
@@ -27,6 +27,7 @@ const {
|
|
|
27
27
|
buildConversationStateFromThread,
|
|
28
28
|
createEmptyConversationState,
|
|
29
29
|
readThreadIdFromParams,
|
|
30
|
+
synchronizeDesktopConversationCompatibility,
|
|
30
31
|
} = require("./desktop-ipc-conversation-adapter");
|
|
31
32
|
const {
|
|
32
33
|
DEFAULT_MAX_PATCH_BYTES,
|
|
@@ -94,20 +95,33 @@ const OWNER_INBOUND_METHODS = new Set([
|
|
|
94
95
|
|
|
95
96
|
const THREAD_READ_METHODS = new Set(["thread/read", "thread/resume"]);
|
|
96
97
|
|
|
97
|
-
|
|
98
|
+
// Current app-server v2 TurnStartParams fields. Desktop's adjacent turnStart.context
|
|
99
|
+
// is presentation state, not part of this RPC shape, so it stays outside the request.
|
|
100
|
+
const APP_SERVER_TURN_START_PARAM_KEYS = new Set([
|
|
98
101
|
"threadId",
|
|
99
102
|
"input",
|
|
103
|
+
"additionalContext",
|
|
100
104
|
"cwd",
|
|
101
105
|
"approvalPolicy",
|
|
102
106
|
"approvalsReviewer",
|
|
103
107
|
"sandboxPolicy",
|
|
104
108
|
"model",
|
|
105
109
|
"serviceTier",
|
|
110
|
+
"serviceTierForTurn",
|
|
106
111
|
"effort",
|
|
107
112
|
"summary",
|
|
108
113
|
"personality",
|
|
109
114
|
"outputSchema",
|
|
110
115
|
"collaborationMode",
|
|
116
|
+
"clientUserMessageId",
|
|
117
|
+
"cyberAccessProgram",
|
|
118
|
+
"environments",
|
|
119
|
+
"multiAgentMode",
|
|
120
|
+
"permissions",
|
|
121
|
+
"responsesapiClientMetadata",
|
|
122
|
+
"runtimeWorkspaceRoots",
|
|
123
|
+
"toolOutput",
|
|
124
|
+
"turnTrigger",
|
|
111
125
|
]);
|
|
112
126
|
|
|
113
127
|
function createDesktopIpcLiveOwner({
|
|
@@ -1104,6 +1118,7 @@ function createDesktopIpcLiveOwner({
|
|
|
1104
1118
|
return true;
|
|
1105
1119
|
}
|
|
1106
1120
|
runtimeSettingsStore?.attachToConversation?.(threadId, conversationState);
|
|
1121
|
+
synchronizeDesktopConversationCompatibility(conversationState);
|
|
1107
1122
|
if (shouldDelayInitialSnapshotForHistory(threadId)) {
|
|
1108
1123
|
return false;
|
|
1109
1124
|
}
|
|
@@ -1367,10 +1382,7 @@ function createDesktopIpcLiveOwner({
|
|
|
1367
1382
|
}
|
|
1368
1383
|
|
|
1369
1384
|
async function handleFollowerStartTurn(conversationId, params) {
|
|
1370
|
-
const rawTurnStartParams = params
|
|
1371
|
-
|| params.turn_start_params
|
|
1372
|
-
|| params.turnStart
|
|
1373
|
-
|| params;
|
|
1385
|
+
const rawTurnStartParams = readFollowerTurnStartParams(params);
|
|
1374
1386
|
const codexParams = mergeFollowerRuntimeOverrides(conversationId, sanitizeTurnStartParams({
|
|
1375
1387
|
...rawTurnStartParams,
|
|
1376
1388
|
threadId: conversationId,
|
|
@@ -1380,7 +1392,9 @@ function createDesktopIpcLiveOwner({
|
|
|
1380
1392
|
? normalizedParams
|
|
1381
1393
|
: codexParams;
|
|
1382
1394
|
markOwnedThread(conversationId);
|
|
1383
|
-
const senderRequestId = params.senderRequestId
|
|
1395
|
+
const senderRequestId = params.senderRequestId
|
|
1396
|
+
|| params.sender_request_id
|
|
1397
|
+
|| rawTurnStartParams.clientUserMessageId;
|
|
1384
1398
|
const isKnownHeldPhoneStart = Boolean(
|
|
1385
1399
|
requestIdKey(senderRequestId)
|
|
1386
1400
|
&& pendingTurnStartEntriesByRequestId.has(requestIdKey(senderRequestId))
|
|
@@ -1417,6 +1431,17 @@ function createDesktopIpcLiveOwner({
|
|
|
1417
1431
|
}
|
|
1418
1432
|
}
|
|
1419
1433
|
|
|
1434
|
+
function readFollowerTurnStartParams(params) {
|
|
1435
|
+
const turnStart = isPlainJSONObject(params.turnStart) ? params.turnStart : null;
|
|
1436
|
+
if (isPlainJSONObject(turnStart?.request)) {
|
|
1437
|
+
return turnStart.request;
|
|
1438
|
+
}
|
|
1439
|
+
return params.turnStartParams
|
|
1440
|
+
|| params.turn_start_params
|
|
1441
|
+
|| params.turnStart
|
|
1442
|
+
|| params;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1420
1445
|
function mirrorFollowerUserPromptToPhone(threadId, turnStartParams, turnStartResult = null) {
|
|
1421
1446
|
const text = visibleUserPromptFromInputEntries(turnStartParams?.input);
|
|
1422
1447
|
if (!text) {
|
|
@@ -1461,16 +1486,50 @@ function createDesktopIpcLiveOwner({
|
|
|
1461
1486
|
}
|
|
1462
1487
|
|
|
1463
1488
|
async function handleFollowerInterruptTurn(conversationId, params) {
|
|
1464
|
-
const
|
|
1465
|
-
|| readString(params.
|
|
1466
|
-
||
|
|
1489
|
+
const requestedTurnId = readString(params.expectedTurnId)
|
|
1490
|
+
|| readString(params.expected_turn_id)
|
|
1491
|
+
|| readString(params.turnId)
|
|
1492
|
+
|| readString(params.turn_id);
|
|
1493
|
+
const activeTurnId = activeTurnIdForConversation(conversationId);
|
|
1494
|
+
if (requestedTurnId && requestedTurnId !== activeTurnId) {
|
|
1495
|
+
return {
|
|
1496
|
+
interruptedTurnId: null,
|
|
1497
|
+
ok: true,
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
const goalPauseError = await pauseActiveGoalForUserStop(
|
|
1502
|
+
conversationId,
|
|
1503
|
+
params.mode,
|
|
1504
|
+
Boolean(requestedTurnId)
|
|
1505
|
+
);
|
|
1506
|
+
const turnId = requestedTurnId || activeTurnId;
|
|
1467
1507
|
if (!turnId) {
|
|
1468
|
-
|
|
1508
|
+
return followerInterruptResult(null, goalPauseError);
|
|
1469
1509
|
}
|
|
1470
|
-
|
|
1510
|
+
await sendCodexRequest("turn/interrupt", {
|
|
1471
1511
|
threadId: conversationId,
|
|
1472
1512
|
turnId,
|
|
1473
1513
|
});
|
|
1514
|
+
return followerInterruptResult(turnId, goalPauseError);
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
async function pauseActiveGoalForUserStop(conversationId, mode, hasRequestedTurnId) {
|
|
1518
|
+
if (mode !== "user-stop" || hasRequestedTurnId) {
|
|
1519
|
+
return "";
|
|
1520
|
+
}
|
|
1521
|
+
if (conversations.get(conversationId)?.threadGoal?.status !== "active") {
|
|
1522
|
+
return "";
|
|
1523
|
+
}
|
|
1524
|
+
try {
|
|
1525
|
+
await sendCodexRequest("thread/goal/set", {
|
|
1526
|
+
threadId: conversationId,
|
|
1527
|
+
status: "paused",
|
|
1528
|
+
});
|
|
1529
|
+
return "";
|
|
1530
|
+
} catch (error) {
|
|
1531
|
+
return error?.message || "Failed to pause thread goal.";
|
|
1532
|
+
}
|
|
1474
1533
|
}
|
|
1475
1534
|
|
|
1476
1535
|
// Desktop follower approvals only carry decision-style payloads, but app-server
|
|
@@ -1786,8 +1845,7 @@ function createDesktopIpcLiveOwner({
|
|
|
1786
1845
|
return turnId;
|
|
1787
1846
|
}
|
|
1788
1847
|
}
|
|
1789
|
-
|
|
1790
|
-
return readString(latestTurn?.turnId) || readString(latestTurn?.id);
|
|
1848
|
+
return "";
|
|
1791
1849
|
}
|
|
1792
1850
|
|
|
1793
1851
|
return {
|
|
@@ -1881,7 +1939,7 @@ function normalizeInputEntriesForDesktop(input) {
|
|
|
1881
1939
|
function sanitizeTurnStartParams(params) {
|
|
1882
1940
|
const sanitized = {};
|
|
1883
1941
|
for (const [key, value] of Object.entries(params || {})) {
|
|
1884
|
-
if (
|
|
1942
|
+
if (APP_SERVER_TURN_START_PARAM_KEYS.has(key)) {
|
|
1885
1943
|
sanitized[key] = value;
|
|
1886
1944
|
}
|
|
1887
1945
|
}
|
|
@@ -1891,6 +1949,14 @@ function sanitizeTurnStartParams(params) {
|
|
|
1891
1949
|
return sanitized;
|
|
1892
1950
|
}
|
|
1893
1951
|
|
|
1952
|
+
function followerInterruptResult(interruptedTurnId, goalPauseError) {
|
|
1953
|
+
return {
|
|
1954
|
+
interruptedTurnId,
|
|
1955
|
+
...(goalPauseError ? { goalPauseError } : {}),
|
|
1956
|
+
ok: true,
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1959
|
+
|
|
1894
1960
|
function readThreadFromResponse(message) {
|
|
1895
1961
|
const result = message?.result || message?.payload || {};
|
|
1896
1962
|
return readThreadFromPayload(result);
|
|
@@ -28,12 +28,12 @@ const DESKTOP_IPC_METHOD_VERSIONS = new Map([
|
|
|
28
28
|
["thread-unarchived", 1],
|
|
29
29
|
["thread-read-state-changed", 2],
|
|
30
30
|
["thread-queued-followups-changed", 1],
|
|
31
|
-
["thread-follower-start-turn",
|
|
31
|
+
["thread-follower-start-turn", 2],
|
|
32
32
|
["thread-follower-load-complete-history", 1],
|
|
33
33
|
["thread-follower-update-thread-settings", 1],
|
|
34
34
|
["thread-follower-compact-thread", 1],
|
|
35
35
|
["thread-follower-steer-turn", 1],
|
|
36
|
-
["thread-follower-interrupt-turn",
|
|
36
|
+
["thread-follower-interrupt-turn", 4],
|
|
37
37
|
["thread-follower-set-model-and-reasoning", 1],
|
|
38
38
|
["thread-follower-set-collaboration-mode", 1],
|
|
39
39
|
["thread-follower-edit-last-user-turn", 2],
|
|
@@ -1476,6 +1476,8 @@ function toolStartNotifications(state, payload) {
|
|
|
1476
1476
|
threadId: state.threadId,
|
|
1477
1477
|
turnId: state.activeTurnId,
|
|
1478
1478
|
call_id: callId,
|
|
1479
|
+
itemId: callId,
|
|
1480
|
+
status: "inProgress",
|
|
1479
1481
|
message: activityMessage,
|
|
1480
1482
|
}),
|
|
1481
1483
|
];
|
|
@@ -1536,6 +1538,10 @@ function customToolStartNotifications(state, payload) {
|
|
|
1536
1538
|
threadId: state.threadId,
|
|
1537
1539
|
turnId: state.activeTurnId,
|
|
1538
1540
|
call_id: callId,
|
|
1541
|
+
...(!state.applyPatchCalls.has(callId) ? {
|
|
1542
|
+
itemId: callId,
|
|
1543
|
+
status: "inProgress",
|
|
1544
|
+
} : {}),
|
|
1539
1545
|
message: activityMessage,
|
|
1540
1546
|
}),
|
|
1541
1547
|
];
|
|
@@ -1641,6 +1647,8 @@ function toolOutputNotifications(state, payload) {
|
|
|
1641
1647
|
threadId: state.threadId,
|
|
1642
1648
|
turnId: state.activeTurnId,
|
|
1643
1649
|
call_id: callId,
|
|
1650
|
+
itemId: callId,
|
|
1651
|
+
status: "completed",
|
|
1644
1652
|
message: genericToolCompletionMessage(toolCall.toolName),
|
|
1645
1653
|
}));
|
|
1646
1654
|
state.commandCalls.delete(callId);
|