1
>
/*---------------------------------------------------------------------------------------------
serverAgentHostManager.ts
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 { Event } from '../../base/common/event.js';
7
>
import { Disposable, MutableDisposable, toDisposable } from '../../base/common/lifecycle.js';
8
>
import { ProxyChannel } from '../../base/parts/ipc/common/ipc.js';
9
>
import { IAgentHostConnection, IAgentHostStarter } from '../../platform/agentHost/common/agent.js';
10
>
import { reportAgentHostProcessError } from '../../platform/agentHost/common/agentHostProcessTelemetry.js';
11
>
import { AgentHostIpcChannels, IAgentService } from '../../platform/agentHost/common/agentService.js';
12
>
import { createDecorator } from '../../platform/instantiation/common/instantiation.js';
13
>
import { ILogService, ILoggerService } from '../../platform/log/common/log.js';
14
>
import { RemoteLoggerChannelClient } from '../../platform/log/common/logIpc.js';
15
>
import { ITelemetryService } from '../../platform/telemetry/common/telemetry.js';
16
>
import { IServerLifetimeService } from './serverLifetimeService.js';
17
>
18
>
export const IServerAgentHostManager = createDecorator<IServerAgentHostManager>('serverAgentHostManager');
19
>
20
>
/**
21
>
* Server-specific agent host manager. Eagerly starts the agent host process,
22
>
* handles crash recovery, and tracks active agent sessions plus incoming
23
>
* WebSocket clients to the spawned standalone agent host via
24
>
* {@link IServerLifetimeService}.
25
>
*
26
>
* Renderer-to-agent-host proxy connections handled by `AgentHostChannel`
27
>
* deliberately do not participate here.
28
>
*/
29
>
export interface IServerAgentHostManager {
30
>
readonly _serviceBrand: undefined;
31
>
}
32
>
33
>
/**
34
>
* Proxy interface for the connection tracker IPC channel exposed by the agent
35
>
* host process. This is NOT part of the agent host protocol -- it is a
36
>
* server-only process-management concern.
37
>
*/
38
>
interface IConnectionTrackerService {
39
>
readonly onDidChangeConnectionCount: Event<number>;
40
>
}
41
>
42
>
enum Constants {
43
>
MaxRestarts = 5,
44
>
}
45
>
46
>
export class ServerAgentHostManager extends Disposable implements IServerAgentHostManager {
47
>
declare readonly _serviceBrand: undefined;
48
>
49
>
private _restartCount = 0;
50
>
51
>
/** Lifetime token held while sessions are active or standalone WebSocket clients are connected. */
52
>
private readonly _lifetimeToken = this._register(new MutableDisposable());
53
>
54
>
private _hasActiveSessions = false;
55
>
private _connectionCount = 0;
56
>
57
>
constructor(
58
>
private readonly _starter: IAgentHostStarter,
59
>
@ILogService private readonly _logService: ILogService,
60
>
@ILoggerService private readonly _loggerService: ILoggerService,
61
>
@IServerLifetimeService private readonly _serverLifetimeService: IServerLifetimeService,
62
>
@ITelemetryService private readonly _telemetryService: ITelemetryService,
63
>
) {
64
>
super();
65
>
this._register(this._starter);
66
>
this._start();
67
>
}
68
>
69
>
private async _start(): Promise<void> {
70
>
try {
71
>
const connection = await this._starter.start();
72
>
73
>
if (this._store.isDisposed) {
74
connection.store.dispose();
75
return;
76
}
78
>
this._logService.info('ServerAgentHostManager: agent host started');
79
>
80
>
// Connect logger channel so agent host logs appear in the output channel
81
>
connection.store.add(new RemoteLoggerChannelClient(this._loggerService, connection.client.getChannel(AgentHostIpcChannels.Logger)));
82
>
83
>
this._trackActiveSessions(connection);
84
>
this._trackClientConnections(connection);
85
>
86
>
// Handle unexpected exit
87
>
connection.store.add(connection.onDidProcessExit(e => {
88
if (!this._store.isDisposed) {
89
this._hasActiveSessions = false;