Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/sessions/contrib/agentHost/browser/agentHostDiffs.ts
13401 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { isDefined } from '../../../../base/common/types.js';
7
import { URI } from '../../../../base/common/uri.js';
8
import { SessionStatus as ProtocolSessionStatus } from '../../../../platform/agentHost/common/state/protocol/state.js';
9
import { ISessionFileDiff } from '../../../../platform/agentHost/common/state/sessionState.js';
10
import { IChatSessionFileChange2, isIChatSessionFileChange2 } from '../../../../workbench/contrib/chat/common/chatSessionsService.js';
11
import { ISessionFileChange, SessionStatus } from '../../../services/sessions/common/session.js';
12
13
/**
14
* Maps the protocol-layer session status bitset to the UI-layer
15
* {@link SessionStatus} enum used by session adapters.
16
*/
17
export function mapProtocolStatus(protocol: ProtocolSessionStatus): SessionStatus {
18
if ((protocol & ProtocolSessionStatus.InputNeeded) === ProtocolSessionStatus.InputNeeded) {
19
return SessionStatus.NeedsInput;
20
}
21
if (protocol & ProtocolSessionStatus.InProgress) {
22
return SessionStatus.InProgress;
23
}
24
if (protocol & ProtocolSessionStatus.Error) {
25
return SessionStatus.Error;
26
}
27
28
return SessionStatus.Completed;
29
}
30
31
/**
32
* Converts agent host diffs to the chat session file change format.
33
*
34
* @param mapUri Optional URI mapper applied after parsing. The remote agent
35
* host provider uses this to rewrite `file:` URIs into agent-host URIs.
36
*/
37
export function diffsToChanges(diffs: readonly ISessionFileDiff[], mapUri?: (uri: URI) => URI): IChatSessionFileChange2[] {
38
return diffs.map(d => {
39
const rawUri = d.after?.uri ?? d.before?.uri;
40
if (!rawUri) {
41
return undefined;
42
}
43
44
const uri = mapUri ? mapUri(URI.parse(rawUri)) : URI.parse(rawUri);
45
46
// For deletions (no `after`), `modifiedUri` is `undefined` so the
47
// renderer treats the entry as a deletion and doesn't try to open the
48
// (now-missing) file as the "modified" side of the diff editor.
49
const modifiedUri = d.after
50
? (mapUri ? mapUri(URI.parse(d.after.uri)) : URI.parse(d.after.uri))
51
: undefined;
52
53
// Use the before-content reference URI so the diff editor can
54
// fetch the snapshot of the file *before* the session's edits.
55
let originalUri: URI | undefined;
56
if (d.before?.content?.uri) {
57
const parsed = URI.parse(d.before.content.uri);
58
originalUri = mapUri ? mapUri(parsed) : parsed;
59
}
60
61
return {
62
uri,
63
modifiedUri,
64
originalUri,
65
insertions: d.diff?.added ?? 0,
66
deletions: d.diff?.removed ?? 0,
67
} satisfies IChatSessionFileChange2;
68
}).filter(isDefined);
69
}
70
71
/**
72
* Returns `true` when the current file changes already
73
* match the incoming diffs, avoiding unnecessary observable updates.
74
*/
75
export function diffsEqual(current: readonly ISessionFileChange[], diffs: readonly ISessionFileDiff[], mapUri?: (uri: URI) => URI): boolean {
76
if (current.length !== diffs.length) {
77
return false;
78
}
79
for (let i = 0; i < current.length; i++) {
80
const c = current[i];
81
const d = diffs[i];
82
const rawUri = d.after?.uri ?? d.before?.uri;
83
if (!rawUri) {
84
continue;
85
}
86
const parsed = URI.parse(rawUri);
87
const diffUri = mapUri ? mapUri(parsed) : parsed;
88
const cUri = isIChatSessionFileChange2(c) ? c.uri : c.modifiedUri;
89
if (cUri.toString() !== diffUri.toString() || c.insertions !== (d.diff?.added ?? 0) || c.deletions !== (d.diff?.removed ?? 0)) {
90
return false;
91
}
92
93
const beforeContentUri = d.before?.content?.uri;
94
const currentOriginal = c.originalUri?.toString();
95
if (beforeContentUri) {
96
const parsedBefore = URI.parse(beforeContentUri);
97
const mappedBefore = mapUri ? mapUri(parsedBefore) : parsedBefore;
98
if (currentOriginal !== mappedBefore.toString()) {
99
return false;
100
}
101
} else if (currentOriginal) {
102
return false;
103
}
104
}
105
return true;
106
}
107
108