@ottocode/web-sdk 0.1.273 → 0.1.275
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/dist/components/file-browser/FileViewerPanel.d.ts +2 -1
- package/dist/components/file-browser/FileViewerPanel.d.ts.map +1 -1
- package/dist/components/index.js +3172 -2632
- package/dist/components/index.js.map +20 -19
- package/dist/components/messages/ActionToolBox.d.ts.map +1 -1
- package/dist/components/messages/AssistantMessageGroup.d.ts.map +1 -1
- package/dist/components/messages/CompactActivityGroup.d.ts.map +1 -1
- package/dist/components/messages/MessagePartItem.d.ts.map +1 -1
- package/dist/components/messages/MessageThread.d.ts.map +1 -1
- package/dist/components/messages/compactActivity.d.ts.map +1 -1
- package/dist/components/messages/renderers/CopyIntoRenderer.d.ts +3 -0
- package/dist/components/messages/renderers/CopyIntoRenderer.d.ts.map +1 -0
- package/dist/components/messages/renderers/DatabaseToolRenderer.d.ts.map +1 -1
- package/dist/components/messages/renderers/index.d.ts.map +1 -1
- package/dist/components/messages/renderers/types.d.ts +22 -0
- package/dist/components/messages/renderers/types.d.ts.map +1 -1
- package/dist/components/ui/CodeMirrorViewer.d.ts.map +1 -1
- package/dist/components/workspace/ViewerTabs.d.ts.map +1 -1
- package/dist/hooks/index.js +255 -118
- package/dist/hooks/index.js.map +7 -7
- package/dist/hooks/useMessages.d.ts.map +1 -1
- package/dist/hooks/useQueueState.d.ts +2 -0
- package/dist/hooks/useQueueState.d.ts.map +1 -1
- package/dist/hooks/useSessionStream.d.ts.map +1 -1
- package/dist/index.js +3189 -2648
- package/dist/index.js.map +20 -19
- package/dist/stores/index.js +87 -36
- package/dist/stores/index.js.map +3 -3
- package/dist/stores/viewerTabsStore.d.ts +4 -0
- package/dist/stores/viewerTabsStore.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/hooks/index.js
CHANGED
|
@@ -1239,8 +1239,16 @@ import { create } from "zustand";
|
|
|
1239
1239
|
function titleFromPath(path) {
|
|
1240
1240
|
return path.split("/").pop() || path;
|
|
1241
1241
|
}
|
|
1242
|
+
function normalizeViewerPath(path) {
|
|
1243
|
+
return path.trim().replace(/^a\//, "").replace(/^b\//, "").replace(/^\.\//, "").replace(/\/+/g, "/").replace(/\/+$/, "");
|
|
1244
|
+
}
|
|
1245
|
+
function viewerPathsMatch(left, right) {
|
|
1246
|
+
const normalizedLeft = normalizeViewerPath(left);
|
|
1247
|
+
const normalizedRight = normalizeViewerPath(right);
|
|
1248
|
+
return normalizedLeft === normalizedRight || normalizedLeft.endsWith(`/${normalizedRight}`) || normalizedRight.endsWith(`/${normalizedLeft}`);
|
|
1249
|
+
}
|
|
1242
1250
|
function fileTabId(path) {
|
|
1243
|
-
return `file:${path}`;
|
|
1251
|
+
return `file:${normalizeViewerPath(path)}`;
|
|
1244
1252
|
}
|
|
1245
1253
|
function upsertTab(tabs, tab) {
|
|
1246
1254
|
const existingIndex = tabs.findIndex((item) => item.id === tab.id);
|
|
@@ -1264,6 +1272,13 @@ function isSamePatchCall(existing, preview) {
|
|
|
1264
1272
|
return existing.status === "streaming";
|
|
1265
1273
|
return preview.patch === existing.patch || preview.patch.startsWith(existing.patch) || existing.patch.startsWith(preview.patch);
|
|
1266
1274
|
}
|
|
1275
|
+
function mergeChangedLines(existing, incoming) {
|
|
1276
|
+
if (!existing?.length)
|
|
1277
|
+
return incoming;
|
|
1278
|
+
if (!incoming?.length)
|
|
1279
|
+
return existing;
|
|
1280
|
+
return [...new Set([...existing, ...incoming])].sort((a, b) => a - b);
|
|
1281
|
+
}
|
|
1267
1282
|
var useViewerTabsStore = create((set) => ({
|
|
1268
1283
|
tabs: [],
|
|
1269
1284
|
activeTabId: null,
|
|
@@ -1300,55 +1315,73 @@ var useViewerTabsStore = create((set) => ({
|
|
|
1300
1315
|
openFileTab: (path) => {
|
|
1301
1316
|
const id = fileTabId(path);
|
|
1302
1317
|
set((state) => {
|
|
1303
|
-
const
|
|
1318
|
+
const matchingFileTabs = state.tabs.filter((tab) => tab.type === "file" && viewerPathsMatch(tab.path, path));
|
|
1319
|
+
const existingFile = matchingFileTabs.find((tab) => tab.id === state.activeTabId) ?? matchingFileTabs[0];
|
|
1320
|
+
const targetId = existingFile?.id ?? id;
|
|
1321
|
+
const targetPath = existingFile?.path ?? path;
|
|
1322
|
+
const tabs = state.tabs.filter((tab) => !((tab.type === "tool-preview" || tab.type === "file") && tab.id !== targetId && viewerPathsMatch(tab.path, path)));
|
|
1304
1323
|
return {
|
|
1305
1324
|
tabs: upsertTab(tabs, {
|
|
1306
|
-
id,
|
|
1325
|
+
id: targetId,
|
|
1307
1326
|
type: "file",
|
|
1308
|
-
title: titleFromPath(
|
|
1309
|
-
path
|
|
1327
|
+
title: existingFile?.title ?? titleFromPath(targetPath),
|
|
1328
|
+
path: targetPath
|
|
1310
1329
|
}),
|
|
1311
|
-
activeTabId:
|
|
1330
|
+
activeTabId: targetId
|
|
1312
1331
|
};
|
|
1313
1332
|
});
|
|
1314
1333
|
},
|
|
1315
1334
|
openToolReadTab: (path, highlight) => {
|
|
1316
1335
|
const id = fileTabId(path);
|
|
1317
1336
|
set((state) => {
|
|
1318
|
-
const
|
|
1337
|
+
const matchingFileTabs = state.tabs.filter((tab) => tab.type === "file" && viewerPathsMatch(tab.path, path));
|
|
1338
|
+
const existingFile = matchingFileTabs.find((tab) => tab.id === state.activeTabId) ?? matchingFileTabs[0];
|
|
1339
|
+
const targetId = existingFile?.id ?? id;
|
|
1340
|
+
const targetPath = existingFile?.path ?? path;
|
|
1341
|
+
const tabs = state.tabs.filter((tab) => !((tab.type === "tool-preview" || tab.type === "file") && tab.id !== targetId && viewerPathsMatch(tab.path, path)));
|
|
1319
1342
|
return {
|
|
1320
1343
|
tabs: upsertTab(tabs, {
|
|
1321
|
-
id,
|
|
1344
|
+
id: targetId,
|
|
1322
1345
|
type: "file",
|
|
1323
|
-
title: titleFromPath(
|
|
1324
|
-
path,
|
|
1325
|
-
highlight
|
|
1346
|
+
title: existingFile?.title ?? titleFromPath(targetPath),
|
|
1347
|
+
path: targetPath,
|
|
1348
|
+
highlight,
|
|
1349
|
+
patchPreview: undefined,
|
|
1350
|
+
writePreview: undefined
|
|
1326
1351
|
}),
|
|
1327
|
-
activeTabId:
|
|
1352
|
+
activeTabId: targetId
|
|
1328
1353
|
};
|
|
1329
1354
|
});
|
|
1330
1355
|
},
|
|
1331
1356
|
openToolPreviewTab: (preview) => {
|
|
1332
1357
|
const id = fileTabId(preview.path);
|
|
1333
1358
|
set((state) => {
|
|
1334
|
-
const
|
|
1335
|
-
const
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1359
|
+
const matchingFileTabs = state.tabs.filter((tab) => tab.type === "file" && viewerPathsMatch(tab.path, preview.path));
|
|
1360
|
+
const existingFile = matchingFileTabs.find((tab) => tab.id === state.activeTabId) ?? matchingFileTabs[0];
|
|
1361
|
+
const targetId = existingFile?.id ?? id;
|
|
1362
|
+
const targetPath = existingFile?.path ?? preview.path;
|
|
1363
|
+
const existing = state.tabs.find((tab) => tab.type === "tool-preview" && viewerPathsMatch(tab.path, preview.path));
|
|
1364
|
+
const tabs = state.tabs.filter((tab) => !((tab.type === "tool-preview" || tab.type === "file") && tab.id !== targetId && (viewerPathsMatch(tab.path, preview.path) || Boolean(preview.callId && "toolName" in tab && tab.callId === preview.callId))));
|
|
1365
|
+
if (preview.toolName === "apply_patch") {
|
|
1366
|
+
const existingPatchPreview = existingFile?.patchPreview ?? (existing?.toolName === "apply_patch" ? existing : undefined);
|
|
1339
1367
|
const samePatchCall = isSamePatchCall(existingPatchPreview, preview);
|
|
1340
|
-
const
|
|
1368
|
+
const baseContent = preview.baseContent ?? (samePatchCall ? existingPatchPreview?.baseContent : existingPatchPreview?.resultContent ?? existingPatchPreview?.baseContent);
|
|
1369
|
+
const changedLines = samePatchCall ? preview.changedLines ?? existingPatchPreview?.changedLines : mergeChangedLines(existingPatchPreview?.changedLines, preview.changedLines);
|
|
1341
1370
|
return {
|
|
1342
1371
|
tabs: upsertTab(tabs, {
|
|
1343
|
-
|
|
1372
|
+
id: targetId,
|
|
1373
|
+
type: "file",
|
|
1374
|
+
title: existingFile?.title ?? titleFromPath(targetPath),
|
|
1375
|
+
path: targetPath,
|
|
1344
1376
|
highlight: undefined,
|
|
1377
|
+
writePreview: undefined,
|
|
1345
1378
|
patchPreview: {
|
|
1346
|
-
path:
|
|
1379
|
+
path: targetPath,
|
|
1347
1380
|
toolName: "apply_patch",
|
|
1348
1381
|
callId: preview.callId ?? existingPatchPreview?.callId,
|
|
1349
|
-
baseContent
|
|
1382
|
+
baseContent,
|
|
1350
1383
|
patch: preview.patch ?? existingPatchPreview?.patch,
|
|
1351
|
-
changedLines
|
|
1384
|
+
changedLines,
|
|
1352
1385
|
previewContent: preview.previewContent ?? (samePatchCall ? existingPatchPreview?.previewContent : undefined),
|
|
1353
1386
|
resultContent: preview.resultContent ?? (samePatchCall ? existingPatchPreview?.resultContent : undefined),
|
|
1354
1387
|
previewLineTones: preview.previewLineTones ?? (samePatchCall ? existingPatchPreview?.previewLineTones : undefined),
|
|
@@ -1358,11 +1391,29 @@ var useViewerTabsStore = create((set) => ({
|
|
|
1358
1391
|
error: preview.error ?? existingPatchPreview?.error
|
|
1359
1392
|
}
|
|
1360
1393
|
}),
|
|
1361
|
-
activeTabId:
|
|
1394
|
+
activeTabId: targetId
|
|
1362
1395
|
};
|
|
1363
1396
|
}
|
|
1364
|
-
|
|
1365
|
-
|
|
1397
|
+
if (existingFile) {
|
|
1398
|
+
const existingWritePreview = existingFile.writePreview;
|
|
1399
|
+
return {
|
|
1400
|
+
tabs: upsertTab(tabs, {
|
|
1401
|
+
...existingFile,
|
|
1402
|
+
highlight: undefined,
|
|
1403
|
+
patchPreview: undefined,
|
|
1404
|
+
writePreview: {
|
|
1405
|
+
path: targetPath,
|
|
1406
|
+
toolName: "write",
|
|
1407
|
+
callId: preview.callId ?? existingWritePreview?.callId,
|
|
1408
|
+
content: preview.content ?? existingWritePreview?.content,
|
|
1409
|
+
status: preview.status,
|
|
1410
|
+
error: preview.error ?? existingWritePreview?.error
|
|
1411
|
+
}
|
|
1412
|
+
}),
|
|
1413
|
+
activeTabId: targetId
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
const existingWrite = existing?.toolName === "write" ? existing : undefined;
|
|
1366
1417
|
return {
|
|
1367
1418
|
tabs: upsertTab(tabs, {
|
|
1368
1419
|
id,
|
|
@@ -1371,17 +1422,17 @@ var useViewerTabsStore = create((set) => ({
|
|
|
1371
1422
|
path: preview.path,
|
|
1372
1423
|
toolName: preview.toolName,
|
|
1373
1424
|
callId: preview.callId,
|
|
1374
|
-
content: preview.content ??
|
|
1375
|
-
baseContent,
|
|
1376
|
-
patch:
|
|
1377
|
-
changedLines:
|
|
1378
|
-
previewContent:
|
|
1379
|
-
resultContent:
|
|
1380
|
-
previewLineTones:
|
|
1381
|
-
previewFirstLine:
|
|
1382
|
-
previewLatestLine:
|
|
1425
|
+
content: preview.content ?? existingWrite?.content,
|
|
1426
|
+
baseContent: undefined,
|
|
1427
|
+
patch: undefined,
|
|
1428
|
+
changedLines: undefined,
|
|
1429
|
+
previewContent: undefined,
|
|
1430
|
+
resultContent: undefined,
|
|
1431
|
+
previewLineTones: undefined,
|
|
1432
|
+
previewFirstLine: undefined,
|
|
1433
|
+
previewLatestLine: undefined,
|
|
1383
1434
|
status: preview.status,
|
|
1384
|
-
error: preview.error ??
|
|
1435
|
+
error: preview.error ?? existingWrite?.error
|
|
1385
1436
|
}),
|
|
1386
1437
|
activeTabId: id
|
|
1387
1438
|
};
|
|
@@ -1977,7 +2028,71 @@ function useRemoveRemote() {
|
|
|
1977
2028
|
});
|
|
1978
2029
|
}
|
|
1979
2030
|
// src/hooks/useMessages.ts
|
|
1980
|
-
import { useQuery as
|
|
2031
|
+
import { useQuery as useQuery5, useMutation as useMutation4, useQueryClient as useQueryClient4 } from "@tanstack/react-query";
|
|
2032
|
+
|
|
2033
|
+
// src/hooks/useQueueState.ts
|
|
2034
|
+
import { useQuery as useQuery4 } from "@tanstack/react-query";
|
|
2035
|
+
var defaultQueueState = {
|
|
2036
|
+
currentMessageId: null,
|
|
2037
|
+
queuedMessages: [],
|
|
2038
|
+
queueLength: 0
|
|
2039
|
+
};
|
|
2040
|
+
function optimisticallyQueueMessage(queryClient, sessionId, messageId) {
|
|
2041
|
+
queryClient.setQueryData(["queueState", sessionId], (current) => {
|
|
2042
|
+
if (!current)
|
|
2043
|
+
return current;
|
|
2044
|
+
const isBusy = Boolean(current.currentMessageId) || current.queuedMessages.length > 0 || current.queueLength > 0;
|
|
2045
|
+
if (!isBusy)
|
|
2046
|
+
return current;
|
|
2047
|
+
if (current.currentMessageId === messageId)
|
|
2048
|
+
return current;
|
|
2049
|
+
if (current.queuedMessages.some((item) => item.messageId === messageId)) {
|
|
2050
|
+
return current;
|
|
2051
|
+
}
|
|
2052
|
+
const queuedMessages = [
|
|
2053
|
+
...current.queuedMessages,
|
|
2054
|
+
{ messageId, position: current.queuedMessages.length }
|
|
2055
|
+
];
|
|
2056
|
+
return {
|
|
2057
|
+
...current,
|
|
2058
|
+
queuedMessages,
|
|
2059
|
+
queueLength: queuedMessages.length
|
|
2060
|
+
};
|
|
2061
|
+
});
|
|
2062
|
+
}
|
|
2063
|
+
function useQueueState(sessionId) {
|
|
2064
|
+
const { data } = useQuery4({
|
|
2065
|
+
queryKey: ["queueState", sessionId],
|
|
2066
|
+
queryFn: async () => {
|
|
2067
|
+
if (!sessionId)
|
|
2068
|
+
return defaultQueueState;
|
|
2069
|
+
const queueState = await apiClient.getQueueState(sessionId);
|
|
2070
|
+
return {
|
|
2071
|
+
currentMessageId: queueState.currentMessageId,
|
|
2072
|
+
queuedMessages: queueState.queuedMessages,
|
|
2073
|
+
queueLength: queueState.queuedMessages.length
|
|
2074
|
+
};
|
|
2075
|
+
},
|
|
2076
|
+
enabled: !!sessionId,
|
|
2077
|
+
placeholderData: defaultQueueState,
|
|
2078
|
+
staleTime: Infinity
|
|
2079
|
+
});
|
|
2080
|
+
return data ?? defaultQueueState;
|
|
2081
|
+
}
|
|
2082
|
+
function useMessageQueuePosition(sessionId, messageId) {
|
|
2083
|
+
const queueState = useQueueState(sessionId);
|
|
2084
|
+
if (!sessionId || !queueState) {
|
|
2085
|
+
return { isQueued: false, isRunning: false, position: null };
|
|
2086
|
+
}
|
|
2087
|
+
if (queueState.currentMessageId === messageId) {
|
|
2088
|
+
return { isQueued: false, isRunning: true, position: null };
|
|
2089
|
+
}
|
|
2090
|
+
const queuedItem = queueState.queuedMessages.find((item) => item.messageId === messageId);
|
|
2091
|
+
if (queuedItem) {
|
|
2092
|
+
return { isQueued: true, isRunning: false, position: queuedItem.position };
|
|
2093
|
+
}
|
|
2094
|
+
return { isQueued: false, isRunning: false, position: null };
|
|
2095
|
+
}
|
|
1981
2096
|
|
|
1982
2097
|
// src/hooks/useSessions.ts
|
|
1983
2098
|
import {
|
|
@@ -2088,7 +2203,7 @@ function useDeleteSession() {
|
|
|
2088
2203
|
// src/hooks/useMessages.ts
|
|
2089
2204
|
function useMessages(sessionId, options = {}) {
|
|
2090
2205
|
const { enabled = true, staleTime = 15000 } = options;
|
|
2091
|
-
return
|
|
2206
|
+
return useQuery5({
|
|
2092
2207
|
queryKey: ["messages", sessionId],
|
|
2093
2208
|
queryFn: () => {
|
|
2094
2209
|
if (!sessionId) {
|
|
@@ -2110,7 +2225,8 @@ function useSendMessage(sessionId) {
|
|
|
2110
2225
|
});
|
|
2111
2226
|
return apiClient.sendMessage(sessionId, data);
|
|
2112
2227
|
},
|
|
2113
|
-
onSuccess: () => {
|
|
2228
|
+
onSuccess: (result) => {
|
|
2229
|
+
optimisticallyQueueMessage(queryClient, sessionId, result.messageId);
|
|
2114
2230
|
queryClient.invalidateQueries({ queryKey: ["messages", sessionId] });
|
|
2115
2231
|
queryClient.invalidateQueries({ queryKey: sessionsQueryKey });
|
|
2116
2232
|
}
|
|
@@ -2303,7 +2419,7 @@ function useSessionStream(sessionId, enabled = true) {
|
|
|
2303
2419
|
}
|
|
2304
2420
|
for (let i = messages.length - 1;i >= 0; i -= 1) {
|
|
2305
2421
|
const candidate = messages[i];
|
|
2306
|
-
if (candidate.role === "assistant" && candidate.status
|
|
2422
|
+
if (candidate.role === "assistant" && candidate.status === "pending") {
|
|
2307
2423
|
return i;
|
|
2308
2424
|
}
|
|
2309
2425
|
}
|
|
@@ -2516,6 +2632,37 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
2516
2632
|
const normalizedTarget = normalizePatchPath(targetPath);
|
|
2517
2633
|
return normalizedPatch === normalizedTarget || normalizedPatch.endsWith(`/${normalizedTarget}`) || normalizedTarget.endsWith(`/${normalizedPatch}`);
|
|
2518
2634
|
};
|
|
2635
|
+
const patchPathMayReferToTarget = (patchPath, targetPath) => {
|
|
2636
|
+
const normalizedPatch = normalizePatchPath(patchPath).replace(/\/+$/, "");
|
|
2637
|
+
const normalizedTarget = normalizePatchPath(targetPath);
|
|
2638
|
+
if (!normalizedPatch)
|
|
2639
|
+
return false;
|
|
2640
|
+
return patchPathMatches(patchPath, targetPath) || normalizedTarget.startsWith(`${normalizedPatch}/`);
|
|
2641
|
+
};
|
|
2642
|
+
const isLikelyCompletePatchPath = (path) => {
|
|
2643
|
+
const normalized = normalizePatchPath(path);
|
|
2644
|
+
if (!normalized || normalized.endsWith("/"))
|
|
2645
|
+
return false;
|
|
2646
|
+
const name = normalized.split("/").pop() ?? "";
|
|
2647
|
+
return name.includes(".");
|
|
2648
|
+
};
|
|
2649
|
+
const getCompletedPatchChangeLineSignature = (patch) => {
|
|
2650
|
+
const stablePatch = patch.endsWith(`
|
|
2651
|
+
`) ? patch : patch.slice(0, patch.lastIndexOf(`
|
|
2652
|
+
`) + 1);
|
|
2653
|
+
if (!stablePatch)
|
|
2654
|
+
return;
|
|
2655
|
+
let changeLines = 0;
|
|
2656
|
+
let stableChangeLength = 0;
|
|
2657
|
+
for (const line of stablePatch.split(`
|
|
2658
|
+
`)) {
|
|
2659
|
+
if (line.startsWith("+") && !line.startsWith("+++") || line.startsWith("-") && !line.startsWith("---")) {
|
|
2660
|
+
changeLines += 1;
|
|
2661
|
+
stableChangeLength += line.length;
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
return changeLines > 0 ? `${changeLines}:${stableChangeLength}` : undefined;
|
|
2665
|
+
};
|
|
2519
2666
|
const extractPathsFromPatch = (patch) => {
|
|
2520
2667
|
const paths = new Set;
|
|
2521
2668
|
for (const line of patch.split(`
|
|
@@ -2637,31 +2784,41 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
2637
2784
|
const failed = result?.ok === false || eventType === "error";
|
|
2638
2785
|
const status = failed ? "error" : eventType === "tool.result" ? "success" : "streaming";
|
|
2639
2786
|
const callId = getToolEventCallId(payload) ?? undefined;
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2787
|
+
const patch = (typeof artifact?.patch === "string" ? artifact.patch : undefined) ?? (status === "streaming" ? getStreamingPatchPreviewContent(args, buffer) : getStringArg(args, buffer, "patch"));
|
|
2788
|
+
if (!patch)
|
|
2789
|
+
return;
|
|
2790
|
+
const previewKey = callId ?? "apply_patch";
|
|
2791
|
+
const lineSignature = status === "streaming" ? getCompletedPatchChangeLineSignature(patch) : undefined;
|
|
2792
|
+
if (status === "streaming") {
|
|
2643
2793
|
const last = toolPreviewEmitRef.current.get(previewKey);
|
|
2644
|
-
|
|
2645
|
-
if (last && now - last.emittedAt < TOOL_PREVIEW_THROTTLE_MS && contentDelta < TOOL_PREVIEW_THROTTLE_MIN_DELTA_CHARS) {
|
|
2794
|
+
if (last?.lineSignature === lineSignature)
|
|
2646
2795
|
return;
|
|
2647
|
-
}
|
|
2648
|
-
toolPreviewEmitRef.current.set(previewKey, {
|
|
2649
|
-
emittedAt: now,
|
|
2650
|
-
contentLength: buffer.length
|
|
2651
|
-
});
|
|
2652
2796
|
}
|
|
2653
|
-
const
|
|
2654
|
-
if (
|
|
2797
|
+
const patchPaths = extractPathsFromPatch(patch);
|
|
2798
|
+
if (patchPaths.length === 0)
|
|
2799
|
+
return;
|
|
2800
|
+
const matchingFileTabs = viewerStore.tabs.filter((tab) => tab.type === "file" && patchPaths.some((path) => patchPathMayReferToTarget(path, tab.path)));
|
|
2801
|
+
const activeMatchingFileTab = matchingFileTabs.find((tab) => tab.id === viewerStore.activeTabId);
|
|
2802
|
+
const fallbackPath = patchPaths.find(isLikelyCompletePatchPath);
|
|
2803
|
+
if (!activeMatchingFileTab && !matchingFileTabs[0] && !fallbackPath)
|
|
2804
|
+
return;
|
|
2805
|
+
const targetPath = activeMatchingFileTab?.path ?? matchingFileTabs[0]?.path ?? fallbackPath;
|
|
2806
|
+
if (!targetPath)
|
|
2655
2807
|
return;
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2808
|
+
viewerStore.openToolPreviewTab({
|
|
2809
|
+
path: targetPath,
|
|
2810
|
+
toolName: "apply_patch",
|
|
2811
|
+
callId,
|
|
2812
|
+
patch,
|
|
2813
|
+
changedLines: getChangedLinesForPath(result, targetPath),
|
|
2814
|
+
status,
|
|
2815
|
+
error: extractErrorMessage2(payload)
|
|
2816
|
+
});
|
|
2817
|
+
if (status === "streaming") {
|
|
2818
|
+
toolPreviewEmitRef.current.set(previewKey, {
|
|
2819
|
+
emittedAt: Date.now(),
|
|
2820
|
+
contentLength: buffer.length,
|
|
2821
|
+
lineSignature
|
|
2665
2822
|
});
|
|
2666
2823
|
}
|
|
2667
2824
|
};
|
|
@@ -2685,19 +2842,9 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
2685
2842
|
return payload.delta;
|
|
2686
2843
|
return typeof payload?.outputTextDelta === "string" ? payload.outputTextDelta : null;
|
|
2687
2844
|
};
|
|
2688
|
-
const getOptimisticPartIndex = (parts,
|
|
2689
|
-
const
|
|
2690
|
-
|
|
2691
|
-
return indexes.length > 0 ? Math.max(...indexes) + 0.001 : 0;
|
|
2692
|
-
})();
|
|
2693
|
-
if (typeof stepIndex !== "number") {
|
|
2694
|
-
return appendIndex;
|
|
2695
|
-
}
|
|
2696
|
-
const sameStepIndexes = parts.filter((part) => part.stepIndex === stepIndex).map((part) => part.index).filter((index) => Number.isFinite(index));
|
|
2697
|
-
if (sameStepIndexes.length > 0) {
|
|
2698
|
-
return Math.max(...sameStepIndexes) + 0.001;
|
|
2699
|
-
}
|
|
2700
|
-
return appendIndex;
|
|
2845
|
+
const getOptimisticPartIndex = (parts, _stepIndex) => {
|
|
2846
|
+
const indexes = parts.map((part) => part.index).filter((index) => Number.isFinite(index));
|
|
2847
|
+
return indexes.length > 0 ? Math.max(...indexes) + 0.001 : 0;
|
|
2701
2848
|
};
|
|
2702
2849
|
const applyReasoningDelta = (payload) => {
|
|
2703
2850
|
const messageId = typeof payload?.messageId === "string" ? payload.messageId : null;
|
|
@@ -3164,6 +3311,7 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
3164
3311
|
const id = typeof payload?.id === "string" ? payload.id : null;
|
|
3165
3312
|
if (role === "assistant" && id) {
|
|
3166
3313
|
assistantMessageIdRef.current = id;
|
|
3314
|
+
optimisticallyQueueMessage(queryClient, sessionId, id);
|
|
3167
3315
|
}
|
|
3168
3316
|
if (id && role) {
|
|
3169
3317
|
const agent = typeof payload?.agent === "string" ? payload.agent : "";
|
|
@@ -3302,7 +3450,26 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
3302
3450
|
removeEphemeralToolCall(payload);
|
|
3303
3451
|
const messageId = typeof payload?.messageId === "string" ? payload.messageId : null;
|
|
3304
3452
|
if (messageId) {
|
|
3453
|
+
if (assistantMessageIdRef.current === messageId) {
|
|
3454
|
+
assistantMessageIdRef.current = null;
|
|
3455
|
+
}
|
|
3305
3456
|
clearEphemeralForMessage(messageId);
|
|
3457
|
+
const errorMessage = typeof payload?.error === "string" ? payload.error : typeof payload?.message === "string" ? payload.message : "Assistant run failed";
|
|
3458
|
+
queryClient.setQueryData(["messages", sessionId], (oldMessages) => {
|
|
3459
|
+
if (!oldMessages)
|
|
3460
|
+
return oldMessages;
|
|
3461
|
+
const idx = oldMessages.findIndex((m) => m.id === messageId);
|
|
3462
|
+
if (idx === -1)
|
|
3463
|
+
return oldMessages;
|
|
3464
|
+
const next = [...oldMessages];
|
|
3465
|
+
next[idx] = {
|
|
3466
|
+
...next[idx],
|
|
3467
|
+
status: "error",
|
|
3468
|
+
completedAt: next[idx].completedAt ?? Date.now(),
|
|
3469
|
+
error: errorMessage
|
|
3470
|
+
};
|
|
3471
|
+
return next;
|
|
3472
|
+
});
|
|
3306
3473
|
}
|
|
3307
3474
|
queryClient.invalidateQueries({ queryKey: ["messages", sessionId] });
|
|
3308
3475
|
break;
|
|
@@ -3311,6 +3478,13 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
3311
3478
|
const id = typeof payload?.id === "string" ? payload.id : null;
|
|
3312
3479
|
const status = typeof payload?.status === "string" ? payload.status : null;
|
|
3313
3480
|
if (id && status) {
|
|
3481
|
+
if (status !== "pending" && assistantMessageIdRef.current === id) {
|
|
3482
|
+
assistantMessageIdRef.current = null;
|
|
3483
|
+
}
|
|
3484
|
+
if (status !== "pending") {
|
|
3485
|
+
clearEphemeralForMessage(id);
|
|
3486
|
+
}
|
|
3487
|
+
const error = typeof payload?.error === "string" ? payload.error : undefined;
|
|
3314
3488
|
queryClient.setQueryData(["messages", sessionId], (oldMessages) => {
|
|
3315
3489
|
if (!oldMessages)
|
|
3316
3490
|
return oldMessages;
|
|
@@ -3320,7 +3494,9 @@ ${bestEffortUnescapeJsonString(rawTail)}`;
|
|
|
3320
3494
|
const next = [...oldMessages];
|
|
3321
3495
|
next[idx] = {
|
|
3322
3496
|
...next[idx],
|
|
3323
|
-
status
|
|
3497
|
+
status,
|
|
3498
|
+
completedAt: status === "pending" ? next[idx].completedAt : next[idx].completedAt ?? Date.now(),
|
|
3499
|
+
error: error ?? next[idx].error
|
|
3324
3500
|
};
|
|
3325
3501
|
return next;
|
|
3326
3502
|
});
|
|
@@ -4666,10 +4842,10 @@ function useFileUpload(options = {}) {
|
|
|
4666
4842
|
};
|
|
4667
4843
|
}
|
|
4668
4844
|
// src/hooks/useSessionFiles.ts
|
|
4669
|
-
import { useQuery as
|
|
4845
|
+
import { useQuery as useQuery6 } from "@tanstack/react-query";
|
|
4670
4846
|
function useSessionFiles(sessionId, enabled = true) {
|
|
4671
4847
|
const isExpanded = useSessionFilesStore((state) => state.isExpanded);
|
|
4672
|
-
return
|
|
4848
|
+
return useQuery6({
|
|
4673
4849
|
queryKey: ["session", sessionId, "files"],
|
|
4674
4850
|
queryFn: () => sessionId ? apiClient.getSessionFiles(sessionId) : null,
|
|
4675
4851
|
enabled: !!sessionId && enabled,
|
|
@@ -4678,46 +4854,6 @@ function useSessionFiles(sessionId, enabled = true) {
|
|
|
4678
4854
|
staleTime: 3000
|
|
4679
4855
|
});
|
|
4680
4856
|
}
|
|
4681
|
-
// src/hooks/useQueueState.ts
|
|
4682
|
-
import { useQuery as useQuery6 } from "@tanstack/react-query";
|
|
4683
|
-
var defaultQueueState = {
|
|
4684
|
-
currentMessageId: null,
|
|
4685
|
-
queuedMessages: [],
|
|
4686
|
-
queueLength: 0
|
|
4687
|
-
};
|
|
4688
|
-
function useQueueState(sessionId) {
|
|
4689
|
-
const { data } = useQuery6({
|
|
4690
|
-
queryKey: ["queueState", sessionId],
|
|
4691
|
-
queryFn: async () => {
|
|
4692
|
-
if (!sessionId)
|
|
4693
|
-
return defaultQueueState;
|
|
4694
|
-
const queueState = await apiClient.getQueueState(sessionId);
|
|
4695
|
-
return {
|
|
4696
|
-
currentMessageId: queueState.currentMessageId,
|
|
4697
|
-
queuedMessages: queueState.queuedMessages,
|
|
4698
|
-
queueLength: queueState.queuedMessages.length
|
|
4699
|
-
};
|
|
4700
|
-
},
|
|
4701
|
-
enabled: !!sessionId,
|
|
4702
|
-
placeholderData: defaultQueueState,
|
|
4703
|
-
staleTime: Infinity
|
|
4704
|
-
});
|
|
4705
|
-
return data ?? defaultQueueState;
|
|
4706
|
-
}
|
|
4707
|
-
function useMessageQueuePosition(sessionId, messageId) {
|
|
4708
|
-
const queueState = useQueueState(sessionId);
|
|
4709
|
-
if (!sessionId || !queueState) {
|
|
4710
|
-
return { isQueued: false, isRunning: false, position: null };
|
|
4711
|
-
}
|
|
4712
|
-
if (queueState.currentMessageId === messageId) {
|
|
4713
|
-
return { isQueued: false, isRunning: true, position: null };
|
|
4714
|
-
}
|
|
4715
|
-
const queuedItem = queueState.queuedMessages.find((item) => item.messageId === messageId);
|
|
4716
|
-
if (queuedItem) {
|
|
4717
|
-
return { isQueued: true, isRunning: false, position: queuedItem.position };
|
|
4718
|
-
}
|
|
4719
|
-
return { isQueued: false, isRunning: false, position: null };
|
|
4720
|
-
}
|
|
4721
4857
|
// src/hooks/useBranch.ts
|
|
4722
4858
|
import { useQuery as useQuery7, useMutation as useMutation5, useQueryClient as useQueryClient7 } from "@tanstack/react-query";
|
|
4723
4859
|
function useCreateBranch(sessionId) {
|
|
@@ -6299,7 +6435,8 @@ export {
|
|
|
6299
6435
|
useAllModels,
|
|
6300
6436
|
useAddRemote,
|
|
6301
6437
|
useAddMCPServer,
|
|
6302
|
-
sessionsQueryKey
|
|
6438
|
+
sessionsQueryKey,
|
|
6439
|
+
optimisticallyQueueMessage
|
|
6303
6440
|
};
|
|
6304
6441
|
|
|
6305
|
-
//# debugId=
|
|
6442
|
+
//# debugId=90296322954CBDC864756E2164756E21
|