Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/agentHost/test/node/reducers.test.ts
13399 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 assert from 'assert';
7
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
8
import { sessionReducer } from '../../common/state/protocol/reducers.js';
9
import { ActionType } from '../../common/state/sessionActions.js';
10
import { SessionInputAnswerState, SessionInputAnswerValueKind, SessionInputQuestionKind, SessionInputResponseKind, SessionLifecycle, SessionStatus, ToolCallConfirmationReason, type SessionState } from '../../common/state/sessionState.js';
11
12
function makeSession(): SessionState {
13
return {
14
summary: {
15
resource: 'copilot:/test',
16
provider: 'copilot',
17
title: 'Test',
18
status: SessionStatus.Idle,
19
createdAt: Date.now(),
20
modifiedAt: Date.now(),
21
project: { uri: 'file:///test-project', displayName: 'Test Project' },
22
},
23
lifecycle: SessionLifecycle.Ready,
24
turns: [],
25
};
26
}
27
28
function withActiveTurnAndToolCall(state: SessionState): SessionState {
29
state = sessionReducer(state, {
30
type: ActionType.SessionTurnStarted,
31
session: 'copilot:/test',
32
turnId: 'turn-1',
33
userMessage: { text: 'hello' },
34
});
35
state = sessionReducer(state, {
36
type: ActionType.SessionToolCallStart,
37
session: 'copilot:/test',
38
turnId: 'turn-1',
39
toolCallId: 'tc-1',
40
toolName: 'readFile',
41
displayName: 'Read File',
42
});
43
return state;
44
}
45
46
suite('sessionReducer – summaryStatus with tool call confirmations and input requests', () => {
47
48
ensureNoDisposablesAreLeakedInTestSuite();
49
50
test('SessionStatus is InputNeeded when a tool call is PendingConfirmation', () => {
51
let state = withActiveTurnAndToolCall(makeSession());
52
53
// Transition to PendingConfirmation (no `confirmed` field)
54
state = sessionReducer(state, {
55
type: ActionType.SessionToolCallReady,
56
session: 'copilot:/test',
57
turnId: 'turn-1',
58
toolCallId: 'tc-1',
59
invocationMessage: 'Read file?',
60
toolInput: '/foo.ts',
61
});
62
63
assert.strictEqual(state.summary.status, SessionStatus.InputNeeded);
64
});
65
66
test('SessionStatus is InputNeeded when a tool call is PendingResultConfirmation', () => {
67
let state = withActiveTurnAndToolCall(makeSession());
68
69
// Transition to Running first
70
state = sessionReducer(state, {
71
type: ActionType.SessionToolCallReady,
72
session: 'copilot:/test',
73
turnId: 'turn-1',
74
toolCallId: 'tc-1',
75
invocationMessage: 'Read file',
76
toolInput: '/foo.ts',
77
confirmed: ToolCallConfirmationReason.NotNeeded,
78
});
79
80
// Then complete with requiresResultConfirmation
81
state = sessionReducer(state, {
82
type: ActionType.SessionToolCallComplete,
83
session: 'copilot:/test',
84
turnId: 'turn-1',
85
toolCallId: 'tc-1',
86
requiresResultConfirmation: true,
87
result: {
88
success: true,
89
pastTenseMessage: 'Read file',
90
},
91
});
92
93
assert.strictEqual(state.summary.status, SessionStatus.InputNeeded);
94
});
95
96
test('SessionStatus transitions from InputNeeded to InProgress when tool call is confirmed', () => {
97
let state = withActiveTurnAndToolCall(makeSession());
98
99
// Transition to PendingConfirmation
100
state = sessionReducer(state, {
101
type: ActionType.SessionToolCallReady,
102
session: 'copilot:/test',
103
turnId: 'turn-1',
104
toolCallId: 'tc-1',
105
invocationMessage: 'Read file?',
106
toolInput: '/foo.ts',
107
});
108
assert.strictEqual(state.summary.status, SessionStatus.InputNeeded);
109
110
// Confirm it
111
state = sessionReducer(state, {
112
type: ActionType.SessionToolCallConfirmed,
113
session: 'copilot:/test',
114
turnId: 'turn-1',
115
toolCallId: 'tc-1',
116
approved: true,
117
confirmed: ToolCallConfirmationReason.UserAction,
118
});
119
120
assert.strictEqual(state.summary.status, SessionStatus.InProgress);
121
});
122
123
test('SessionStatus is InputNeeded with inputRequests', () => {
124
let state = withActiveTurnAndToolCall(makeSession());
125
126
state = sessionReducer(state, {
127
type: ActionType.SessionInputRequested,
128
session: 'copilot:/test',
129
request: {
130
id: 'req-1',
131
message: 'What is your name?',
132
questions: [{
133
kind: SessionInputQuestionKind.Text,
134
id: 'q-1',
135
message: 'What is your name?',
136
required: true,
137
}],
138
},
139
});
140
141
assert.strictEqual(state.summary.status, SessionStatus.InputNeeded);
142
});
143
144
test('SessionStatus transitions from InputNeeded to InProgress after SessionInputCompleted', () => {
145
let state = withActiveTurnAndToolCall(makeSession());
146
147
// Add an input request
148
state = sessionReducer(state, {
149
type: ActionType.SessionInputRequested,
150
session: 'copilot:/test',
151
request: {
152
id: 'req-1',
153
message: 'What is your name?',
154
questions: [{
155
kind: SessionInputQuestionKind.Text,
156
id: 'q-1',
157
message: 'What is your name?',
158
required: true,
159
}],
160
},
161
});
162
assert.strictEqual(state.summary.status, SessionStatus.InputNeeded);
163
164
// Complete the input request
165
state = sessionReducer(state, {
166
type: ActionType.SessionInputCompleted,
167
session: 'copilot:/test',
168
requestId: 'req-1',
169
response: SessionInputResponseKind.Accept,
170
answers: { 'q-1': { state: SessionInputAnswerState.Submitted, value: { kind: SessionInputAnswerValueKind.Text, value: 'Alice' } } },
171
});
172
173
assert.strictEqual(state.summary.status, SessionStatus.InProgress);
174
});
175
176
test('Tool call transition to PendingConfirmation updates summary status to InputNeeded', () => {
177
let state = withActiveTurnAndToolCall(makeSession());
178
179
// After SessionToolCallStart, status should be InProgress (tool is Streaming)
180
assert.strictEqual(state.summary.status, SessionStatus.InProgress);
181
182
// Transition to PendingConfirmation via SessionToolCallReady (no confirmed)
183
state = sessionReducer(state, {
184
type: ActionType.SessionToolCallReady,
185
session: 'copilot:/test',
186
turnId: 'turn-1',
187
toolCallId: 'tc-1',
188
invocationMessage: 'Read file?',
189
toolInput: '/foo.ts',
190
});
191
192
assert.strictEqual(state.summary.status, SessionStatus.InputNeeded);
193
});
194
});
195
196