Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions packages/ai-chat/src/browser/change-set-file-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// *****************************************************************************

import { ConfigurableInMemoryResources, ConfigurableMutableReferenceResource } from '@theia/ai-core';
import { CancellationToken, DisposableCollection, Emitter, URI } from '@theia/core';
import { CancellationToken, DisposableCollection, Emitter, nls, URI } from '@theia/core';
import { ConfirmDialog } from '@theia/core/lib/browser';
import { Replacement } from '@theia/core/lib/common/content-replacer';
import { inject, injectable, postConstruct } from '@theia/core/shared/inversify';
Expand Down Expand Up @@ -448,12 +448,18 @@ export class ChangeSetFileElement implements ChangeSetElement {
}
}

async confirm(verb: string): Promise<boolean> {
async confirm(verb: 'Apply' | 'Revert'): Promise<boolean> {
if (this._state !== 'stale') { return true; }
await this.openChange();
const answer = await new ConfirmDialog({
title: `${verb} suggestion.`,
msg: `The file ${this.uri.path.toString()} has changed since this suggestion was created. Are you certain you wish to ${verb.toLowerCase()} the change?`
title: verb === 'Apply'
? nls.localize('theia/ai/chat/applySuggestion', 'Apply suggestion')
: nls.localize('theia/ai/chat/revertSuggestion', 'Revert suggestion'),
msg: verb === 'Apply'
? nls.localize('theia/ai/chat/confirmApplySuggestion',
'The file {0} has changed since this suggestion was created. Are you certain you wish to apply the change?', this.uri.path.toString())
: nls.localize('theia/ai/chat/confirmRevertSuggestion',
'The file {0} has changed since this suggestion was created. Are you certain you wish to revert the change?', this.uri.path.toString())
}).open(true);
return !!answer;
}
Expand Down
6 changes: 3 additions & 3 deletions packages/ai-chat/src/browser/change-set-file-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************

import { ILogger, URI } from '@theia/core';
import { ILogger, nls, URI } from '@theia/core';
import { ApplicationShell, DiffUris, LabelProvider, NavigatableWidget, OpenerService, open } from '@theia/core/lib/browser';
import { inject, injectable } from '@theia/core/shared/inversify';
import { EditorManager } from '@theia/editor/lib/browser';
Expand Down Expand Up @@ -79,7 +79,7 @@ export class ChangeSetFileService {
if (wsUri) {
const wsRelative = wsUri.relative(uri);
if (wsRelative?.hasDir) {
return `${wsRelative.dir.toString()}`;
return wsRelative.dir.toString();
}
return '';
}
Expand All @@ -104,7 +104,7 @@ export class ChangeSetFileService {

protected getDiffUri(originalUri: URI, suggestedUri: URI): URI {
return DiffUris.encode(originalUri, suggestedUri,
`AI Changes: ${this.labelProvider.getName(originalUri)}`,
nls.localize('theia/ai/chat/changeSetFileDiffUriLabel', 'AI Changes: {0}', this.labelProvider.getName(originalUri)),
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import { AIVariableContext, AIVariableResolutionRequest, PromptText } from '@theia/ai-core';
import { AIVariableCompletionContext, AIVariableDropResult, FrontendVariableContribution, FrontendVariableService } from '@theia/ai-core/lib/browser';
import { FILE_VARIABLE } from '@theia/ai-core/lib/browser/file-variable-contribution';
import { CancellationToken, ILogger, QuickInputService, URI } from '@theia/core';
import { CancellationToken, ILogger, nls, QuickInputService, URI } from '@theia/core';
import { inject, injectable } from '@theia/core/shared/inversify';
import * as monaco from '@theia/monaco-editor-core';
import { FileQuickPickItem, QuickFileSelectService } from '@theia/file-search/lib/browser/quick-file-select-service';
Expand Down Expand Up @@ -76,7 +76,7 @@ export class FileChatVariableContribution implements FrontendVariableContributio

protected async imageArgumentPicker(): Promise<string | undefined> {
const quickPick = this.quickInputService.createQuickPick();
quickPick.title = 'Select an image file';
quickPick.title = nls.localize('theia/ai/chat/selectImageFile', 'Select an image file');

// Get all files and filter only image files
const allPicks = await this.quickFileSelectService.getPicks();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,6 @@ export class ImageContextVariableContribution implements AIVariableContribution,

getDetails(element: ImageContextVariableRequest): string | undefined {
const path = ImageContextVariable.parseArg(element.arg).wsRelativePath;
return path ? this.labelProvider.getDetails(new URI(path)) : '[pasted]';
return path ? this.labelProvider.getDetails(new URI(path)) : undefined;
}
}
12 changes: 9 additions & 3 deletions packages/ai-chat/src/browser/task-context-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// *****************************************************************************

import { inject, injectable } from '@theia/core/shared/inversify';
import { MaybePromise, ProgressService, URI, generateUuid, Event, EOL } from '@theia/core';
import { MaybePromise, ProgressService, URI, generateUuid, Event, EOL, nls } from '@theia/core';
import { ChatAgent, ChatAgentLocation, ChatService, ChatSession, MutableChatModel, MutableChatRequestModel, ParsedChatRequestTextPart } from '../common';
import { PreferenceService } from '@theia/core/lib/common';
import { ChatSessionSummaryAgent } from '../common/chat-session-summary-agent';
Expand Down Expand Up @@ -90,7 +90,10 @@ export class TaskContextService {
if (existing && !override) { return existing.id; }
const summaryId = generateUuid();
const summaryDeferred = new Deferred<Summary>();
const progress = await this.progressService.showProgress({ text: `Summarize: ${session.title || session.id}`, options: { location: 'ai-chat' } });
const progress = await this.progressService.showProgress({
text: nls.localize('theia/ai/chat/taskContextService/summarizeProgressMessage', 'Summarize: {0}', session.title || session.id),
options: { location: 'ai-chat' }
});
this.pendingSummaries.set(session.id, summaryDeferred.promise);
try {
const prompt = await this.getSystemPrompt(session, promptId);
Expand Down Expand Up @@ -127,7 +130,10 @@ export class TaskContextService {
return this.summarize(session, promptId, agent, override);
}

const progress = await this.progressService.showProgress({ text: `Updating: ${session.title || session.id}`, options: { location: 'ai-chat' } });
const progress = await this.progressService.showProgress({
text: nls.localize('theia/ai/chat/taskContextService/updatingProgressMessage', 'Updating: {0}', session.title || session.id),
options: { location: 'ai-chat' }
});
try {
const prompt = await this.getSystemPrompt(session, promptId);
if (!prompt) {
Expand Down
11 changes: 8 additions & 3 deletions packages/ai-chat/src/browser/task-context-variable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,19 @@
// *****************************************************************************

import { AIVariable } from '@theia/ai-core';
import { nls } from '@theia/core';
import { codiconArray } from '@theia/core/lib/browser';

export const TASK_CONTEXT_VARIABLE: AIVariable = {
id: 'taskContext',
description: 'Provides context information for a task, e.g. the plan for completing a task or a summary of a previous sessions',
description: nls.localize('theia/chat/taskContextVariable/description',
'Provides context information for a task, e.g. the plan for completing a task or a summary of a previous sessions'),
name: 'taskContext',
label: 'Task Context',
label: nls.localize('theia/chat/taskContextVariable/label', 'Task Context'),
iconClasses: codiconArray('clippy'),
isContextVariable: true,
args: [{ name: 'context-id', description: 'The ID of the task context to retrieve, or a chat session to summarize.' }]
args: [{
name: 'context-id',
description: nls.localize('theia/chat/taskContextVariable/args/contextId/description', 'The ID of the task context to retrieve, or a chat session to summarize.')
}]
};
4 changes: 2 additions & 2 deletions packages/ai-chat/src/common/change-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************

import { ArrayUtils, Disposable, Emitter, Event, URI } from '@theia/core';
import { ArrayUtils, Disposable, Emitter, Event, nls, URI } from '@theia/core';

export interface ChangeSetElement {
readonly uri: URI;
Expand Down Expand Up @@ -95,7 +95,7 @@ export class ChangeSetImpl implements ChangeSet {

protected hasBeenSet = false;
protected _elements = new Map<string, ChangeSetElement | undefined>();
protected _title = 'Suggested Changes';
protected _title = nls.localize('theia/ai/chat/changeSetDefaultTitle', 'Suggested Changes');
get title(): string {
return this._title;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
import { MaybePromise } from '@theia/core';
import { MaybePromise, nls } from '@theia/core';
import { inject, injectable } from '@theia/core/shared/inversify';
import {
AIVariable,
Expand All @@ -29,7 +29,7 @@ import { ChatAgentService } from './chat-agent-service';
export const CHAT_AGENTS_VARIABLE: AIVariable = {
id: 'chatAgents',
name: 'chatAgents',
description: 'Returns the list of chat agents available in the system'
description: nls.localize('theia/ai/chat/chatAgentsVariable/description', 'Returns the list of chat agents available in the system')
};

export interface ChatAgentDescriptor {
Expand Down
8 changes: 4 additions & 4 deletions packages/ai-chat/src/common/chat-agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
LanguageModelRegistry,
LanguageModelStreamResponsePart
} from '@theia/ai-core/lib/common';
import { ContributionProvider, ILogger, isArray } from '@theia/core';
import { ContributionProvider, ILogger, isArray, nls } from '@theia/core';
import { inject, injectable, named, postConstruct } from '@theia/core/shared/inversify';
import { ChatAgentService } from './chat-agent-service';
import {
Expand Down Expand Up @@ -155,7 +155,7 @@ export abstract class AbstractChatAgent implements ChatAgent {
readonly abstract languageModelRequirements: LanguageModelRequirement[];
iconClass: string = 'codicon codicon-copilot';
locations: ChatAgentLocation[] = ChatAgentLocation.ALL;
tags: string[] = ['Chat'];
tags: string[] = [nls.localizeByDefault('Chat')];
description: string = '';
variables: string[] = [];
prompts: PromptVariantSet[] = [];
Expand All @@ -180,7 +180,7 @@ export abstract class AbstractChatAgent implements ChatAgent {
try {
const languageModel = await this.getLanguageModel(this.defaultLanguageModelPurpose);
if (!languageModel) {
throw new Error('Couldn\'t find a matching language model. Please check your setup!');
throw new Error(nls.localize('theia/ai/chat/couldNotFindMatchingLM', 'Couldn\'t find a matching language model. Please check your setup!'));
}
const systemMessageDescription = await this.getSystemMessageDescription({ model: request.session, request } satisfies ChatSessionContext);
const messages = await this.getMessages(request.session);
Expand Down Expand Up @@ -237,7 +237,7 @@ export abstract class AbstractChatAgent implements ChatAgent {
protected async selectLanguageModel(selector: LanguageModelRequirement): Promise<LanguageModel> {
const languageModel = await this.languageModelRegistry.selectLanguageModel({ agent: this.id, ...selector });
if (!languageModel) {
throw new Error(`Couldn\'t find a ready language model for agent ${this.id}. Please check your setup!`);
throw new Error(nls.localize('theia/ai/chat/couldNotFindReadyLMforAgent', 'Couldn\'t find a ready language model for agent {0}. Please check your setup!', this.id));
}
return languageModel;
}
Expand Down
16 changes: 12 additions & 4 deletions packages/ai-chat/src/common/chat-session-naming-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
} from '@theia/ai-core';
import { inject, injectable } from '@theia/core/shared/inversify';
import { ChatSession } from './chat-service';
import { generateUuid } from '@theia/core';
import { generateUuid, nls } from '@theia/core';

import { CHAT_SESSION_NAMING_PROMPT } from './chat-session-naming-prompt-template';

Expand All @@ -47,16 +47,24 @@ export class ChatSessionNamingAgent implements Agent {
static ID = 'Chat Session Naming';
id = ChatSessionNamingAgent.ID;
name = ChatSessionNamingAgent.ID;
description = 'Agent for generating chat session names';
description = nls.localize('theia/ai/chat/chatSessionNamingAgent/description', 'Agent for generating chat session names');
variables = [];
prompts = [CHAT_SESSION_NAMING_PROMPT];
languageModelRequirements: LanguageModelRequirement[] = [{
purpose: 'chat-session-naming',
identifier: 'default/summarize',
}];
agentSpecificVariables = [
{ name: 'conversation', usedInPrompt: true, description: 'The content of the chat conversation.' },
{ name: 'listOfSessionNames', usedInPrompt: true, description: 'The list of existing session names.' }
{
name: 'conversation',
usedInPrompt: true,
description: nls.localize('theia/ai/chat/chatSessionNamingAgent/vars/conversation/description', 'The content of the chat conversation.')
},
{
name: 'listOfSessionNames',
usedInPrompt: true,
description: nls.localize('theia/ai/chat/chatSessionNamingAgent/vars/listOfSessionNames/description', 'The list of existing session names.')
}
];
functions = [];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const CHAT_SESSION_SUMMARY_PROMPT = {
'The summary will primarily be used by other AI agents, so tailor your response for use by AI agents. ' +
'Also consider the system message. ' +
'Make sure you include all necessary context information and use unique references (such as URIs, file paths, etc.). ' +
'If the conversation was about a task, describe the state of the task, i.e.what has been completed and what is open. ' +
'If the conversation was about a task, describe the state of the task, i.e. what has been completed and what is open. ' +
'If a changeset is open in the session, describe the state of the suggested changes. ' +
`\n\n{{${CHANGE_SET_SUMMARY_VARIABLE_ID}}}`,
}
Expand Down
3 changes: 2 additions & 1 deletion packages/ai-chat/src/common/chat-session-summary-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ import {
import { injectable } from '@theia/core/shared/inversify';
import { AbstractStreamParsingChatAgent, ChatAgent } from './chat-agents';
import { CHAT_SESSION_SUMMARY_PROMPT } from './chat-session-summary-agent-prompt';
import { nls } from '@theia/core';

@injectable()
export class ChatSessionSummaryAgent extends AbstractStreamParsingChatAgent implements ChatAgent {
static ID = 'chat-session-summary-agent';
id = ChatSessionSummaryAgent.ID;
name = 'Chat Session Summary';
override description = 'Agent for generating chat session summaries.';
override description = nls.localize('theia/ai/chat/chatSessionSummaryAgent/description', 'Agent for generating chat session summaries.');
override prompts: PromptVariantSet[] = [CHAT_SESSION_SUMMARY_PROMPT];
protected readonly defaultLanguageModelPurpose = 'chat-session-summary';
languageModelRequirements: LanguageModelRequirement[] = [{
Expand Down
3 changes: 1 addition & 2 deletions packages/ai-chat/src/common/chat-tool-preferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const chatToolPreferences: PreferenceSchema = {
},
default: {},
description: nls.localize('theia/ai/chat/toolConfirmation/description',
'Configure confirmation behavior for different tools. Key is the tool ID, value is the confirmation mode.' +
'Configure confirmation behavior for different tools. Key is the tool ID, value is the confirmation mode. ' +
'Use "*" as the key to set a global default for all tools.'),
title: AI_CORE_PREFERENCES_TITLE,
}
Expand All @@ -80,4 +80,3 @@ export const chatToolPreferences: PreferenceSchema = {
export interface ChatToolConfiguration {
[TOOL_CONFIRMATION_PREFERENCE]: { [toolId: string]: ToolConfirmationMode };
}

27 changes: 21 additions & 6 deletions packages/ai-chat/src/common/image-context-variable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,34 @@ import {
AIVariableResolutionRequest,
ResolvedAIContextVariable
} from '@theia/ai-core';
import { nls } from '@theia/core';

export const IMAGE_CONTEXT_VARIABLE: AIVariable = {
id: 'imageContext',
description: 'Provides context information for an image',
description: nls.localize('theia/ai/chat/imageContextVariable/description', 'Provides context information for an image'),
name: 'imageContext',
label: 'Image File',
label: nls.localize('theia/ai/chat/imageContextVariable/label', 'Image File'),
iconClasses: ['codicon', 'codicon-file-media'],
isContextVariable: true,
args: [
{ name: 'name', description: 'The name of the image file if available.', isOptional: true },
{ name: 'wsRelativePath', description: 'The workspace-relative path of the image file if available.', isOptional: true },
{ name: 'data', description: 'The image data in base64.' },
{ name: 'mimeType', description: 'The mimetype of the image.' }
{
name: 'name',
description: nls.localize('theia/ai/chat/imageContextVariable/args/name/description', 'The name of the image file if available.'),
isOptional: true
},
{
name: 'wsRelativePath',
description: nls.localize('theia/ai/chat/imageContextVariable/args/wsRelativePath/description', 'The workspace-relative path of the image file if available.'),
isOptional: true
},
{
name: 'data',
description: nls.localize('theia/ai/chat/imageContextVariable/args/data/description', 'The image data in base64.')
},
{
name: 'mimeType',
description: nls.localize('theia/ai/chat/imageContextVariable/args/mimeType/description', 'The mimetype of the image.')
}
]
};

Expand Down
Loading