-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: change set support in chat input and chat model (#14750)
* Add the concept of a change set to chat model and input UI * Add an implementation of change set elements for files * Add an agent for testing: `@ChangeSet` * Integrates with `@Coder` agent Other fixes in Chat Input UI: * The inProgress state of the chat input was actually unsafely managed. This change addresses the proper management of the inProgress state. * The positioning, e.g. of the placeholder is now more adaptive. As the change set feature directly relates to another feature (context, work in progress), this change also already prepares for those changes in the chat UI: * Prepare chat input for adding context to requests * Add context in the form of variables to chat model Fixes #14749 Co-authored-by: Jonas Helming <[email protected]> Co-authored-by: Stefan Dirix <[email protected]>
- Loading branch information
1 parent
ecf65d3
commit 445b35b
Showing
25 changed files
with
1,235 additions
and
806 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
132 changes: 132 additions & 0 deletions
132
examples/api-samples/src/browser/chat/change-set-chat-agent-contribution.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
// ***************************************************************************** | ||
// Copyright (C) 2024 EclipseSource GmbH. | ||
// | ||
// This program and the accompanying materials are made available under the | ||
// terms of the Eclipse Public License v. 2.0 which is available at | ||
// http://www.eclipse.org/legal/epl-2.0. | ||
// | ||
// This Source Code may also be made available under the following Secondary | ||
// Licenses when the conditions for such availability set forth in the Eclipse | ||
// Public License v. 2.0 are satisfied: GNU General Public License, version 2 | ||
// with the GNU Classpath Exception which is available at | ||
// https://www.gnu.org/software/classpath/license.html. | ||
// | ||
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 | ||
// ***************************************************************************** | ||
|
||
import { | ||
AbstractStreamParsingChatAgent, | ||
ChangeSetImpl, | ||
ChatAgent, | ||
ChatRequestModelImpl, | ||
MarkdownChatResponseContentImpl, | ||
SystemMessageDescription | ||
} from '@theia/ai-chat'; | ||
import { ChangeSetFileElementFactory } from '@theia/ai-chat/lib/browser/change-set-file-element'; | ||
import { Agent, PromptTemplate } from '@theia/ai-core'; | ||
import { inject, injectable, interfaces } from '@theia/core/shared/inversify'; | ||
import { FileService } from '@theia/filesystem/lib/browser/file-service'; | ||
import { WorkspaceService } from '@theia/workspace/lib/browser'; | ||
|
||
export function bindChangeSetChatAgentContribution(bind: interfaces.Bind): void { | ||
bind(ChangeSetChatAgent).toSelf().inSingletonScope(); | ||
bind(Agent).toService(ChangeSetChatAgent); | ||
bind(ChatAgent).toService(ChangeSetChatAgent); | ||
} | ||
|
||
/** | ||
* This is a test agent demonstrating how to create change sets in AI chats. | ||
*/ | ||
@injectable() | ||
export class ChangeSetChatAgent extends AbstractStreamParsingChatAgent implements ChatAgent { | ||
override id = 'ChangeSet'; | ||
readonly name = 'ChangeSet'; | ||
override defaultLanguageModelPurpose = 'chat'; | ||
readonly description = 'This chat will create and modify a change set.'; | ||
readonly variables = []; | ||
readonly agentSpecificVariables = []; | ||
readonly functions = []; | ||
override languageModelRequirements = []; | ||
promptTemplates: PromptTemplate[] = []; | ||
|
||
@inject(WorkspaceService) | ||
protected readonly workspaceService: WorkspaceService; | ||
|
||
@inject(FileService) | ||
protected readonly fileService: FileService; | ||
|
||
@inject(ChangeSetFileElementFactory) | ||
protected readonly fileChangeFactory: ChangeSetFileElementFactory; | ||
|
||
override async invoke(request: ChatRequestModelImpl): Promise<void> { | ||
const roots = this.workspaceService.tryGetRoots(); | ||
if (roots.length === 0) { | ||
request.response.response.addContent(new MarkdownChatResponseContentImpl( | ||
'No workspace is open. For using this chat agent, please open a workspace with at least two files in the root.' | ||
)); | ||
request.response.complete(); | ||
return; | ||
} | ||
|
||
const root = roots[0]; | ||
const files = root.children?.filter(child => child.isFile); | ||
if (!files || files.length < 3) { | ||
request.response.response.addContent(new MarkdownChatResponseContentImpl( | ||
'The workspace does not contain any files. For using this chat agent, please add at least two files in the root.' | ||
)); | ||
request.response.complete(); | ||
return; | ||
} | ||
|
||
const fileToAdd = root.resource.resolve('hello/new-file.txt'); | ||
const fileToChange = files[Math.floor(Math.random() * files.length)]; | ||
const fileToDelete = files.filter(file => file.name !== fileToChange.name)[Math.floor(Math.random() * files.length)]; | ||
|
||
const chatSessionId = request.session.id; | ||
const changeSet = new ChangeSetImpl('My Test Change Set'); | ||
changeSet.addElement( | ||
this.fileChangeFactory({ | ||
uri: fileToAdd, | ||
type: 'add', | ||
state: 'pending', | ||
targetState: 'Hello World!', | ||
changeSet, | ||
chatSessionId | ||
}) | ||
); | ||
if (fileToChange && fileToChange.resource) { | ||
changeSet.addElement( | ||
this.fileChangeFactory({ | ||
uri: fileToChange.resource, | ||
type: 'modify', | ||
state: 'pending', | ||
targetState: 'Hello World Modify!', | ||
changeSet, | ||
chatSessionId | ||
}) | ||
); | ||
} | ||
if (fileToDelete && fileToDelete.resource) { | ||
changeSet.addElement( | ||
this.fileChangeFactory({ | ||
uri: fileToDelete.resource, | ||
type: 'delete', | ||
state: 'pending', | ||
changeSet, | ||
chatSessionId | ||
}) | ||
); | ||
} | ||
request.session.setChangeSet(changeSet); | ||
|
||
request.response.response.addContent(new MarkdownChatResponseContentImpl( | ||
'I have created a change set for you. You can now review and apply it.' | ||
)); | ||
request.response.complete(); | ||
} | ||
|
||
protected override async getSystemMessageDescription(): Promise<SystemMessageDescription | undefined> { | ||
return undefined; | ||
} | ||
} | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.