-
Notifications
You must be signed in to change notification settings - Fork 36.5k
Remove chatSessionTracker #279690
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Remove chatSessionTracker #279690
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,7 +20,7 @@ import { Action2, IMenuService, MenuId, MenuItemAction, MenuRegistry, registerAc | |
| import { ContextKeyExpr, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js'; | ||
| import { IRelaxedExtensionDescription } from '../../../../platform/extensions/common/extensions.js'; | ||
| import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js'; | ||
| import { ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; | ||
| import { IInstantiationService, ServicesAccessor } from '../../../../platform/instantiation/common/instantiation.js'; | ||
| import { ILabelService } from '../../../../platform/label/common/label.js'; | ||
| import { ILogService } from '../../../../platform/log/common/log.js'; | ||
| import { isDark } from '../../../../platform/theme/common/theme.js'; | ||
|
|
@@ -39,8 +39,9 @@ import { IChatEditorOptions } from './chatEditor.js'; | |
| import { NEW_CHAT_SESSION_ACTION_ID } from './chatSessions/common.js'; | ||
| import { IChatModel, IChatProgressResponseContent, IChatRequestModel } from '../common/chatModel.js'; | ||
| import { IChatService, IChatToolInvocation } from '../common/chatService.js'; | ||
| import { autorunSelfDisposable } from '../../../../base/common/observable.js'; | ||
| import { autorun, autorunSelfDisposable } from '../../../../base/common/observable.js'; | ||
| import { IChatRequestVariableEntry } from '../common/chatVariableEntries.js'; | ||
| import { Lazy } from '../../../../base/common/lazy.js'; | ||
|
|
||
| const extensionPoint = ExtensionsRegistry.registerExtensionPoint<IChatSessionsExtensionPoint[]>({ | ||
| extensionPoint: 'chatSessions', | ||
|
|
@@ -273,15 +274,18 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ | |
| private readonly _editableSessions = new ResourceMap<IEditableData>(); | ||
| private readonly _registeredRequestIds = new Set<string>(); | ||
| private readonly _registeredModels = new Set<IChatModel>(); | ||
|
|
||
| private readonly _chatServiceLazy = new Lazy(() => | ||
| this._instantiationService.invokeFunction(a => a.get(IChatService)) | ||
| ); | ||
| constructor( | ||
| @ILogService private readonly _logService: ILogService, | ||
| @IChatAgentService private readonly _chatAgentService: IChatAgentService, | ||
| @IExtensionService private readonly _extensionService: IExtensionService, | ||
| @IContextKeyService private readonly _contextKeyService: IContextKeyService, | ||
| @IMenuService private readonly _menuService: IMenuService, | ||
| @IThemeService private readonly _themeService: IThemeService, | ||
| @ILabelService private readonly _labelService: ILabelService | ||
| @ILabelService private readonly _labelService: ILabelService, | ||
| @IInstantiationService private readonly _instantiationService: IInstantiationService, | ||
| ) { | ||
| super(); | ||
|
|
||
|
|
@@ -318,6 +322,12 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ | |
| stripPathStartingSeparator: true, | ||
| } | ||
| })); | ||
|
|
||
| const chatService = this._chatServiceLazy.value; | ||
| this._register(autorun(reader => { | ||
| const models = chatService.chatModels.read(reader); | ||
| this.registerModelProgressListener(models); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't have the big picture, but it seems like a step backwards to do this in this service. I think _chatServiceLazy is trying to avoid a recursive dependency? Actually I don't really see how it helps since you still have to get a IChatService instance in the constructor of this service. And then if the end result of this is just to inform the list that the local sessions have changed, why shouldn't the local sessions provider do that?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was debugging this because I wasn't sure how it worked, and I think it works because our services are created lazily, and it would fail if the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is because we need to do the same for all providers and not just the local chat sessions one. We need to detect progress in the chat model response and indicate the UI update so that we can show the latest progress status.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh I see. Maybe each provider should just be responsible for reporting on its sessions? Even if the underlying data source is the chat service, it can filter the available models to the ones that it is in charge of. Isn't it odd now that the local sessions provider has a
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess I don't quite understand how this works for non-local providers, what is the extension's responsibility and what is core's?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I think the provider having Not sure what the best pattern is for cases like this where core owns part of the UI and the extension another part of it, I guess we need to restrict the API accordingly but how do we manage the updates based on the chat model progress in this case?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't quite understand and don't have full context on the API, happy to dig into it with you when we're back. But in general, I think we need a well-defined extension API, and a well-defined internal API for the view to be built on. |
||
| })); | ||
| } | ||
|
|
||
| public reportInProgress(chatSessionType: string, count: number): void { | ||
|
|
@@ -794,58 +804,63 @@ export class ChatSessionsService extends Disposable implements IChatSessionsServ | |
| }; | ||
| } | ||
|
|
||
| public registerModelProgressListener(model: IChatModel, callback: () => void): void { | ||
| // Prevent duplicate registrations for the same model | ||
| if (this._registeredModels.has(model)) { | ||
| return; | ||
| } | ||
| this._registeredModels.add(model); | ||
|
|
||
| // Helper function to register listeners for a request | ||
| const registerRequestListeners = (request: IChatRequestModel) => { | ||
| if (!request.response || this._registeredRequestIds.has(request.id)) { | ||
| return; | ||
| public registerModelProgressListener(models: Iterable<IChatModel>): void { | ||
osortega marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const disposables = new DisposableStore(); | ||
osortega marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| for (const model of models) { | ||
| // Prevent duplicate registrations for the same model | ||
| if (this._registeredModels.has(model)) { | ||
| continue; | ||
| } | ||
| this._registeredModels.add(model); | ||
|
|
||
| // Get the session type from the model's sessionResource scheme | ||
| // Helper function to register listeners for a request | ||
| const registerRequestListeners = (request: IChatRequestModel) => { | ||
| const chatSessionType = model.sessionResource.scheme === Schemas.vscodeLocalChatSession ? 'local' : model.sessionResource.scheme; | ||
| if (!request.response || this._registeredRequestIds.has(request.id)) { | ||
| return; | ||
| } | ||
|
|
||
| this._registeredRequestIds.add(request.id); | ||
| this._registeredRequestIds.add(request.id); | ||
|
|
||
| this._register(request.response.onDidChange(() => { | ||
| callback(); | ||
| })); | ||
| this._register(request.response.onDidChange(() => { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. registerModelProgressListener runs every time the set of models changes, but then any disposables using |
||
| this.notifySessionItemsChanged(chatSessionType); | ||
| })); | ||
|
|
||
| // Track tool invocation state changes | ||
| const responseParts = request.response.response.value; | ||
| responseParts.forEach((part: IChatProgressResponseContent) => { | ||
| if (part.kind === 'toolInvocation') { | ||
| const toolInvocation = part as IChatToolInvocation; | ||
| // Use autorun to listen for state changes | ||
| this._register(autorunSelfDisposable(reader => { | ||
| const state = toolInvocation.state.read(reader); | ||
|
|
||
| // Also track progress changes when executing | ||
| if (state.type === IChatToolInvocation.StateKind.Executing) { | ||
| state.progress.read(reader); | ||
| } | ||
| // Track tool invocation state changes | ||
| const responseParts = request.response.response.value; | ||
| responseParts.forEach((part: IChatProgressResponseContent) => { | ||
| if (part.kind === 'toolInvocation') { | ||
| const toolInvocation = part as IChatToolInvocation; | ||
| // Use autorun to listen for state changes | ||
| disposables.add(autorunSelfDisposable(reader => { | ||
| const state = toolInvocation.state.read(reader); | ||
|
|
||
| callback(); | ||
| })); | ||
| } | ||
| }); | ||
| }; | ||
| // Listen for response changes on all existing requests | ||
| const requests = model.getRequests(); | ||
| requests.forEach(registerRequestListeners); | ||
|
|
||
| // Listen for new requests being added | ||
| this._register(model.onDidChange(() => { | ||
| const currentRequests = model.getRequests(); | ||
| currentRequests.forEach(registerRequestListeners); | ||
| })); | ||
| // Also track progress changes when executing | ||
| if (state.type === IChatToolInvocation.StateKind.Executing) { | ||
| state.progress.read(reader); | ||
| } | ||
|
|
||
| // Clean up when model is disposed | ||
| this._register(model.onDidDispose(() => { | ||
| this._registeredModels.delete(model); | ||
| })); | ||
| this.notifySessionItemsChanged(chatSessionType); | ||
| })); | ||
| } | ||
| }); | ||
| }; | ||
| // Listen for response changes on all existing requests | ||
| const requests = model.getRequests(); | ||
| requests.forEach(registerRequestListeners); | ||
|
|
||
| // Listen for new requests being added | ||
| disposables.add(model.onDidChange(() => { | ||
| const currentRequests = model.getRequests(); | ||
| currentRequests.forEach(registerRequestListeners); | ||
| })); | ||
|
|
||
| // Clean up when model is disposed | ||
| disposables.add(model.onDidDispose(() => { | ||
| this._registeredModels.delete(model); | ||
| })); | ||
| } | ||
osortega marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| public getSessionDescription(chatModel: IChatModel): string | undefined { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: The
_onDidChangeChatSessionItemsevent is never emitted. Previously, listeners were set up to fire this event when models changed, but that code was removed (lines that calledregisterListeners()andregisterModelListeners()). Without emitting this event, the UI won't be notified when session items change, and the sessions view won't update.The provider should listen to relevant changes and fire the event. Consider:
chatService.chatModelschanges and firing the eventchatSessionsService.onDidChangeSessionItemsfor the local session type and forwarding the event