1
>
/*---------------------------------------------------------------------------------------------
agentHostStateManager.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 { RunOnceScheduler } from '../../../base/common/async.js';
7
>
import { Emitter, Event } from '../../../base/common/event.js';
8
>
import { Disposable } from '../../../base/common/lifecycle.js';
9
>
import { equals } from '../../../base/common/objects.js';
10
>
import { ILogService } from '../../log/common/log.js';
11
>
import { createDecorator } from '../../instantiation/common/instantiation.js';
12
>
import { TelemetryLevel } from '../../telemetry/common/telemetry.js';
13
>
import { ActionType, ActionEnvelope, ActionOrigin, INotification, IRootConfigChangedAction, SessionAction, ChatAction, RootAction, StateAction, TerminalAction, ChangesetAction, ClientChangesetAction, AnnotationsAction, ClientAnnotationsAction, isRootAction, isSessionAction, isChatAction, isChangesetAction, isAnnotationsAction, type AuthRequiredParams, type ProgressParams } from '../common/state/sessionActions.js';
14
>
import type { IStateSnapshot } from '../common/state/sessionProtocol.js';
15
>
import { rootReducer, sessionReducer, chatReducer, changesetReducer, annotationsReducer } from '../common/state/sessionReducers.js';
16
>
import { createRootState, createSessionState, createChatState, createDefaultChatSummary, chatSummaryFromState, buildDefaultChatUri, parseDefaultChatUri, parseRequiredSessionUriFromChatUri, isAhpChatChannel, isDefaultChatUri, mergeSessionWithDefaultChat, isAhpRootChannel, SessionLifecycle, withHostBuildInfo, type Changeset, type ChangesetState, type AnnotationsState, type ChatState, type ChatSummary, type Customization, type ISessionWithDefaultChat, type Message, type RootState, type SessionConfigState, type SessionMeta, type SessionState, type SessionSummary, type Turn, type URI, ROOT_STATE_URI, ChangesetStatus, IHostBuildInfo, SessionStatus } from '../common/state/sessionState.js';
17
>
import { AgentHostTelemetryLevelConfigKey, IPermissionsValue, platformRootSchema, telemetryLevelToAgentHostConfigValue } from '../common/agentHostSchema.js';
18
>
import { SessionConfigKey } from '../common/sessionConfigKeys.js';
19
>
import { parseChangesetUri } from '../common/changesetUri.js';
20
>
import { buildAnnotationsUri, isAnnotationsUri } from '../common/annotationsUri.js';
21
>
import { AgentHostChangesetStateCache, type IAgentHostChangesetStateRetentionOptions } from './agentHostChangesetStateCache.js';
22
>
import { ChangesSummary, ChatInteractivity, type ChatOrigin } from '../common/state/protocol/state.js';
23
>
import { arrayEquals, structuralEquals } from '../../../base/common/equals.js';
24
>
import { preserveProviderBackedRootConfigValues } from '../common/agentCustomizationSettings.js';
25
>
26
>
export interface IAgentHostStateManagerOptions {
27
>
readonly changesetStateRetention?: IAgentHostChangesetStateRetentionOptions;
28
>
/**
29
>
* Build information about the program hosting the agent host. When
30
>
* provided, it is published on {@link RootState._meta} so clients can see
31
>
* which build is hosting them.
32
>
*/
33
>
readonly hostBuildInfo?: IHostBuildInfo;
34
>
}
35
>
36
>
/**
37
>
* Authoritative per-session record held by the state manager. Bundles the flat
38
>
* {@link SessionState} with the {@link SessionSummary} catalog-only fields that
39
>
* do not live on the state. The session URI (catalog `resource`) is the map
40
>
* key, and the catalog `_meta` is the same object as {@link SessionState._meta},
41
>
* so the only extra fields the record carries are the timestamps and the
42
>
* aggregate change counts.
43
>
*/
44
>
interface ISessionEntry {
45
>
state: SessionState;
46
>
/** Creation timestamp (ISO 8601). Catalog-only; immutable after creation. */
47
>
readonly createdAt: string;
48
>
/** Last modification timestamp (ISO 8601). Catalog-only; derived from chat aggregation. */
49
>
modifiedAt: string;
50
>
/** Aggregate file-change counts for the session-wide changeset. Catalog-only. */
51
>
changes?: ChangesSummary;
52
>
}
53
>
54
>
/**
55
>
* Encapsulates the root-channel summary-notification bookkeeping for the
56
>
* {@link AgentHostStateManager}: the last {@link SessionSummary} announced to
57
>
* clients per session (the diff baseline) and the set of sessions whose summary
58
>
* changed since the last debounced flush. The snapshot map and the dirty set
59
>
* are always mutated in lockstep, so keeping them together — rather than as two
60
>
* loose fields on the manager — keeps the diffing state cohesive.
61
>
*
62
>
* The current summary for a session is sourced via the injected `getSummary`
63
>
* callback; diff-based `root/sessionSummaryChanged` notifications are emitted
64
>
* through `emit`.
65
>
*/
66
>
class SessionSummaryNotifier extends Disposable {
67
>
68
>
/** Last summary announced to clients (via sessionAdded or sessionSummaryChanged). */
69
>
private readonly _lastNotified = new Map<string, SessionSummary>();
70
>
71
>
/** Sessions whose summary changed since the last flush. */
72
>
private readonly _dirty = new Set<string>();
73
>
74
>
private readonly _scheduler = this._register(new RunOnceScheduler(() => this._flushAll(), 100));
75
>
76
>
constructor(
77
private readonly _getSummary: (session: string) => SessionSummary | undefined,
78
private readonly _emit: (session: string, changes: Partial<SessionSummary>) => void,