Skip to content

Commit

Permalink
Implement past tense invocation message and tooltip for tool calls (#…
Browse files Browse the repository at this point in the history
…238635)

* Implement past tense invocation message and tooltip for tool calls

* Fix

* Clean up
  • Loading branch information
roblourens authored Jan 24, 2025
1 parent 340c573 commit 720f2eb
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 19 deletions.
14 changes: 8 additions & 6 deletions src/vs/workbench/api/common/extHostLanguageModelTools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { revive } from '../../../base/common/marshalling.js';
import { generateUuid } from '../../../base/common/uuid.js';
import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
import { IPreparedToolInvocation, isToolInvocationContext, IToolInvocation, IToolInvocationContext, IToolResult } from '../../contrib/chat/common/languageModelToolsService.js';
import { isProposedApiEnabled } from '../../services/extensions/common/extensions.js';
import { checkProposedApiEnabled, isProposedApiEnabled } from '../../services/extensions/common/extensions.js';
import { ExtHostLanguageModelToolsShape, IMainContext, IToolDataDto, MainContext, MainThreadLanguageModelToolsShape } from './extHost.protocol.js';
import * as typeConvert from './extHostTypeConverters.js';

Expand Down Expand Up @@ -136,16 +136,18 @@ export class ExtHostLanguageModelTools implements ExtHostLanguageModelToolsShape
return undefined;
}

if (result.pastTenseMessage || result.tooltip) {
checkProposedApiEnabled(item.extension, 'chatParticipantPrivate');
}

return {
confirmationMessages: result.confirmationMessages ? {
title: result.confirmationMessages.title,
message: typeof result.confirmationMessages.message === 'string' ? result.confirmationMessages.message : typeConvert.MarkdownString.from(result.confirmationMessages.message),
} : undefined,
invocationMessage: typeof result.invocationMessage === 'string' ?
result.invocationMessage :
(result.invocationMessage ?
typeConvert.MarkdownString.from(result.invocationMessage) :
undefined),
invocationMessage: typeConvert.MarkdownString.fromStrict(result.invocationMessage),
pastTenseMessage: typeConvert.MarkdownString.fromStrict(result.pastTenseMessage),
tooltip: result.tooltip ? typeConvert.MarkdownString.fromStrict(result.tooltip) : undefined,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
import * as dom from '../../../../../base/browser/dom.js';
import { Codicon } from '../../../../../base/common/codicons.js';
import { Emitter, Relay } from '../../../../../base/common/event.js';
import { MarkdownString } from '../../../../../base/common/htmlContent.js';
import { IMarkdownString, MarkdownString } from '../../../../../base/common/htmlContent.js';
import { Disposable, DisposableStore, IDisposable } from '../../../../../base/common/lifecycle.js';
import { MarkdownRenderer } from '../../../../../editor/browser/widget/markdownRenderer/browser/markdownRenderer.js';
import { localize } from '../../../../../nls.js';
import { IHoverService } from '../../../../../platform/hover/browser/hover.js';
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
import { IChatProgressMessage, IChatToolInvocation, IChatToolInvocationSerialized } from '../../common/chatService.js';
import { IChatRendererContent } from '../../common/chatViewModel.js';
Expand Down Expand Up @@ -75,6 +76,7 @@ class ChatToolInvocationSubPart extends Disposable {
context: IChatContentPartRenderContext,
renderer: MarkdownRenderer,
@IInstantiationService instantiationService: IInstantiationService,
@IHoverService hoverService: IHoverService,
) {
super();

Expand All @@ -93,9 +95,17 @@ class ChatToolInvocationSubPart extends Disposable {
this._onDidChangeHeight.input = confirmWidget.onDidChangeHeight;
toolInvocation.confirmed.p.then(() => this._onNeedsRerender.fire());
} else {
const content = typeof toolInvocation.invocationMessage === 'string' ?
new MarkdownString().appendText(toolInvocation.invocationMessage + '…') :
new MarkdownString(toolInvocation.invocationMessage.value + '…');
let content: IMarkdownString;
if (toolInvocation.isComplete && toolInvocation.isConfirmed !== false && toolInvocation.pastTenseMessage) {
content = typeof toolInvocation.pastTenseMessage === 'string' ?
new MarkdownString().appendText(toolInvocation.pastTenseMessage) :
toolInvocation.pastTenseMessage;
} else {
content = typeof toolInvocation.invocationMessage === 'string' ?
new MarkdownString().appendText(toolInvocation.invocationMessage + '…') :
new MarkdownString(toolInvocation.invocationMessage.value + '…');
}

const progressMessage: IChatProgressMessage = {
kind: 'progressMessage',
content
Expand All @@ -105,6 +115,10 @@ class ChatToolInvocationSubPart extends Disposable {
toolInvocation.isComplete ?
Codicon.check : undefined;
const progressPart = this._register(instantiationService.createInstance(ChatProgressContentPart, progressMessage, renderer, context, undefined, true, iconOverride));
if (toolInvocation.tooltip) {
this._register(hoverService.setupDelayedHover(progressPart.domNode, { content: toolInvocation.tooltip, additionalClasses: ['chat-tool-hover'] }));
}

this.domNode = progressPart.domNode;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ export class LanguageModelToolsService extends Disposable implements ILanguageMo
const defaultMessage = localize('toolInvocationMessage', "Using {0}", `"${tool.data.displayName}"`);
const invocationMessage = prepared?.invocationMessage ?? defaultMessage;
if (tool.data.id !== 'vscode_editFile') {
toolInvocation = new ChatToolInvocation(invocationMessage, prepared?.confirmationMessages);
toolInvocation = new ChatToolInvocation(invocationMessage, prepared?.pastTenseMessage, prepared?.tooltip, prepared?.confirmationMessages);
model.acceptResponseProgress(request, toolInvocation);
if (prepared?.confirmationMessages) {
const userConfirmed = await toolInvocation.confirmed.p;
Expand Down
21 changes: 13 additions & 8 deletions src/vs/workbench/contrib/chat/browser/media/chat.css
Original file line number Diff line number Diff line change
Expand Up @@ -392,14 +392,15 @@ have to be updated for changes to the rules above, or to support more deeply nes
max-width: 100%;
}

.interactive-item-container .monaco-tokenized-source,
.interactive-item-container code {
font-family: var(--monaco-monospace-font);
font-size: 12px;
color: var(--vscode-textPreformat-foreground);
background-color: var(--vscode-textPreformat-background);
padding: 1px 3px;
border-radius: 4px;
.chat-tool-hover, .interactive-item-container {
.monaco-tokenized-source, code {
font-family: var(--monaco-monospace-font);
font-size: 12px;
color: var(--vscode-textPreformat-foreground);
background-color: var(--vscode-textPreformat-background);
padding: 1px 3px;
border-radius: 4px;
}
}

.interactive-item-container.interactive-item-compact {
Expand Down Expand Up @@ -1447,6 +1448,10 @@ have to be updated for changes to the rules above, or to support more deeply nes
padding: 4px 8px;
}

.interactive-item-container .chat-confirmation-widget .rendered-markdown [data-code] {
margin-bottom: 8px;
}

.interactive-item-container .chat-command-button .monaco-button .codicon {
margin-left: 0;
margin-top: 1px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ export class ChatToolInvocation implements IChatToolInvocation {

constructor(
public readonly invocationMessage: string | IMarkdownString,
public readonly pastTenseMessage: string | IMarkdownString | undefined,
public readonly tooltip: string | IMarkdownString | undefined,
private _confirmationMessages: IToolConfirmationMessages | undefined) {
if (!_confirmationMessages) {
// No confirmation needed
Expand All @@ -63,6 +65,8 @@ export class ChatToolInvocation implements IChatToolInvocation {
return {
kind: 'toolInvocationSerialized',
invocationMessage: this.invocationMessage,
pastTenseMessage: this.pastTenseMessage,
tooltip: this.tooltip,
isConfirmed: this._isConfirmed ?? false,
isComplete: this._isComplete,
};
Expand Down
4 changes: 4 additions & 0 deletions src/vs/workbench/contrib/chat/common/chatService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ export interface IChatToolInvocation {
/** A 3-way: undefined=don't know yet. */
isConfirmed: boolean | undefined;
invocationMessage: string | IMarkdownString;
pastTenseMessage: string | IMarkdownString | undefined;
tooltip: string | IMarkdownString | undefined;

isComplete: boolean;
isCompleteDeferred: DeferredPromise<void>;
Expand All @@ -214,6 +216,8 @@ export interface IChatToolInvocation {
*/
export interface IChatToolInvocationSerialized {
invocationMessage: string | IMarkdownString;
pastTenseMessage: string | IMarkdownString | undefined;
tooltip: string | IMarkdownString | undefined;
isConfirmed: boolean;
isComplete: boolean;
kind: 'toolInvocationSerialized';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ export interface IToolConfirmationMessages {

export interface IPreparedToolInvocation {
invocationMessage?: string | IMarkdownString;
pastTenseMessage?: string | IMarkdownString;
tooltip?: string | IMarkdownString;
confirmationMessages?: IToolConfirmationMessages;
}

Expand Down
5 changes: 5 additions & 0 deletions src/vscode-dts/vscode.proposed.chatParticipantPrivate.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,9 @@ declare module 'vscode' {
export interface LanguageModelToolInvocationOptions<T> {
chatRequestId?: string;
}

export interface PreparedToolInvocation {
pastTenseMessage?: string | MarkdownString;
tooltip?: string | MarkdownString;
}
}

0 comments on commit 720f2eb

Please sign in to comment.