Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/agentHost/test/node/agentConfigurationService.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 { DisposableStore } from '../../../../base/common/lifecycle.js';
8
import { URI } from '../../../../base/common/uri.js';
9
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
10
import { NullLogService } from '../../../log/common/log.js';
11
import { createSchema, schemaProperty } from '../../common/agentHostSchema.js';
12
import type { SessionConfigState, RootConfigState } from '../../common/state/protocol/state.js';
13
import { buildSubagentSessionUri, SessionStatus, type SessionSummary } from '../../common/state/sessionState.js';
14
import { AgentConfigurationService } from '../../node/agentConfigurationService.js';
15
import { AgentHostStateManager } from '../../node/agentHostStateManager.js';
16
17
suite('AgentConfigurationService', () => {
18
19
const disposables = new DisposableStore();
20
let manager: AgentHostStateManager;
21
let service: AgentConfigurationService;
22
23
const schema = createSchema({
24
level: schemaProperty<'low' | 'high'>({
25
type: 'string',
26
title: 'level',
27
enum: ['low', 'high'],
28
}),
29
limit: schemaProperty<number>({ type: 'number', title: 'limit' }),
30
});
31
32
function seedSessionConfig(sessionUri: string, values: Record<string, unknown>): void {
33
const state = manager.getSessionState(sessionUri);
34
assert.ok(state, `Session not found: ${sessionUri}`);
35
const mutable = state as { config?: SessionConfigState };
36
mutable.config = {
37
schema: schema.toProtocol(),
38
values,
39
};
40
}
41
42
function seedRootConfig(values: Record<string, unknown>): void {
43
const rootMutable = manager.rootState as { config?: RootConfigState };
44
rootMutable.config = {
45
schema: schema.toProtocol(),
46
values,
47
};
48
}
49
50
function makeSummary(resource: string, workingDirectory?: string): SessionSummary {
51
return {
52
resource,
53
provider: 'copilot',
54
title: 't',
55
status: SessionStatus.Idle,
56
createdAt: Date.now(),
57
modifiedAt: Date.now(),
58
project: { uri: 'file:///project', displayName: 'Project' },
59
workingDirectory,
60
};
61
}
62
63
setup(() => {
64
manager = disposables.add(new AgentHostStateManager(new NullLogService()));
65
service = disposables.add(new AgentConfigurationService(manager, new NullLogService()));
66
});
67
68
teardown(() => disposables.clear());
69
70
ensureNoDisposablesAreLeakedInTestSuite();
71
72
// ---- getEffectiveValue ------------------------------------------------
73
74
suite('getEffectiveValue', () => {
75
76
test('returns session value when present', () => {
77
const uri = URI.from({ scheme: 'copilot', path: '/a' }).toString();
78
manager.createSession(makeSummary(uri));
79
seedSessionConfig(uri, { level: 'high' });
80
assert.strictEqual(service.getEffectiveValue(uri, schema, 'level'), 'high');
81
});
82
83
test('falls back to host value when session does not provide the key', () => {
84
const uri = URI.from({ scheme: 'copilot', path: '/a' }).toString();
85
manager.createSession(makeSummary(uri));
86
seedSessionConfig(uri, { limit: 5 });
87
seedRootConfig({ level: 'low' });
88
assert.strictEqual(service.getEffectiveValue(uri, schema, 'level'), 'low');
89
});
90
91
test('inherits from parent subagent session', () => {
92
const parent = URI.from({ scheme: 'copilot', path: '/parent' }).toString();
93
manager.createSession(makeSummary(parent));
94
seedSessionConfig(parent, { level: 'high' });
95
96
const child = buildSubagentSessionUri(parent, 'toolcall-1');
97
manager.createSession(makeSummary(child));
98
99
assert.strictEqual(service.getEffectiveValue(child, schema, 'level'), 'high');
100
});
101
102
test('session value takes precedence over parent and host', () => {
103
const parent = URI.from({ scheme: 'copilot', path: '/parent' }).toString();
104
manager.createSession(makeSummary(parent));
105
seedSessionConfig(parent, { level: 'high' });
106
107
const child = buildSubagentSessionUri(parent, 'tc-2');
108
manager.createSession(makeSummary(child));
109
seedSessionConfig(child, { level: 'low' });
110
seedRootConfig({ level: 'high' });
111
112
assert.strictEqual(service.getEffectiveValue(child, schema, 'level'), 'low');
113
});
114
115
test('skips layers whose value fails schema validation and falls through', () => {
116
const uri = URI.from({ scheme: 'copilot', path: '/a' }).toString();
117
manager.createSession(makeSummary(uri));
118
seedSessionConfig(uri, { level: 'bogus' });
119
seedRootConfig({ level: 'high' });
120
assert.strictEqual(service.getEffectiveValue(uri, schema, 'level'), 'high');
121
});
122
123
test('returns undefined when no layer provides a valid value', () => {
124
const uri = URI.from({ scheme: 'copilot', path: '/a' }).toString();
125
manager.createSession(makeSummary(uri));
126
seedSessionConfig(uri, {});
127
assert.strictEqual(service.getEffectiveValue(uri, schema, 'level'), undefined);
128
});
129
});
130
131
// ---- getEffectiveWorkingDirectory -------------------------------------
132
133
suite('getEffectiveWorkingDirectory', () => {
134
135
test('returns session working directory when set', () => {
136
const uri = URI.from({ scheme: 'copilot', path: '/a' }).toString();
137
manager.createSession(makeSummary(uri, 'file:///work'));
138
assert.strictEqual(service.getEffectiveWorkingDirectory(uri), 'file:///work');
139
});
140
141
test('falls back to parent session working directory for subagents', () => {
142
const parent = URI.from({ scheme: 'copilot', path: '/parent' }).toString();
143
manager.createSession(makeSummary(parent, 'file:///work/parent'));
144
145
const child = buildSubagentSessionUri(parent, 'tc-3');
146
manager.createSession(makeSummary(child));
147
assert.strictEqual(service.getEffectiveWorkingDirectory(child), 'file:///work/parent');
148
});
149
150
test('returns undefined when neither layer has a working directory', () => {
151
const uri = URI.from({ scheme: 'copilot', path: '/a' }).toString();
152
manager.createSession(makeSummary(uri));
153
assert.strictEqual(service.getEffectiveWorkingDirectory(uri), undefined);
154
});
155
});
156
157
// ---- updateSessionConfig ----------------------------------------------
158
159
suite('updateSessionConfig', () => {
160
161
test('merges the patch into the session config values', () => {
162
const uri = URI.from({ scheme: 'copilot', path: '/a' }).toString();
163
manager.createSession(makeSummary(uri));
164
seedSessionConfig(uri, { level: 'low', limit: 1 });
165
166
service.updateSessionConfig(uri, { limit: 42 });
167
168
const state = manager.getSessionState(uri);
169
assert.deepStrictEqual(state?.config?.values, { level: 'low', limit: 42 });
170
});
171
});
172
});
173
174