RepoMicrosoftMicrosoftpublished Mar 21, 2024seen 1w

microsoft/vscode-prompt-tsx

TypeScript

Open original ↗

Captured source

source ↗
published Mar 21, 2024seen 1wcaptured 1whttp 200method plain

microsoft/vscode-prompt-tsx

Language: TypeScript

License: MIT

Stars: 279

Forks: 29

Open issues: 22

Created: 2024-03-21T22:35:46Z

Pushed: 2026-06-14T05:33:13Z

Default branch: main

Fork: no

Archived: no

README:

@vscode/prompt-tsx

This library enables you to declare prompts using TSX when you develop VS Code extensions that integrate with Copilot Chat. To learn more, check out our documentation or fork our quickstart sample.

Why TSX?

As AI engineers, our products communicate with large language models using chat messages composed of text prompts. While developing Copilot Chat, we've found that composing prompts with just bare strings is unwieldy and frustrating.

Some of the challenges we ran into include:

1. We used either programmatic string concatenation or template strings for composing prompts. Programmatic string concatenation made prompt text increasingly difficult to read, maintain, and update over time. Template string-based prompts were rigid and prone to issues like unnecessary whitespace. 2. In both cases, our prompts and RAG-generated context could not adapt to changing context window constraints as we upgraded our models. Prompts are ultimately bare strings, which makes them hard to edit once they are composed via string concatenation.

To improve the developer experience for writing prompts in language model-based VS Code extensions like Copilot Chat, we built the TSX-based prompt renderer that we've extracted in this library. This has enabled us to compose expressive, flexible prompts that cleanly convert to chat messages. Our prompts are now able to evolve with our product and dynamically adapt to each model's context window.

Key concepts

In this library, prompts are represented as a tree of TSX components that are flattened into a list of chat messages. Each TSX node in the tree has a priority that is conceptually similar to a zIndex (higher number == higher priority).

If a rendered prompt has more message tokens than can fit into the available context window, the prompt renderer prunes messages with the lowest priority from the ChatMessages result, preserving the order in which they were declared. This means your extension code can safely declare TSX components for potentially large pieces of context like conversation history and codebase context.

TSX components at the root level must render to ChatMessages at the root level. ChatMessages may have TSX components as children, but they must ultimately render to text. You can also have TextChunks within ChatMessages, which allows you to reduce less important parts of a chat message under context window limits without losing the full message.

Usage

Workspace Setup

You can install this library in your extension using the command

npm install --save @vscode/prompt-tsx

This library exports a renderPrompt utility for rendering a TSX component to vscode.LanguageModelChatMessages.

To enable TSX use in your extension, add the following configuration options to your tsconfig.json:

{
"compilerOptions": {
// ...
"jsx": "react",
"jsxFactory": "vscpp",
"jsxFragmentFactory": "vscppf"
}
// ...
}

Note: if your codebase depends on both @vscode/prompt-tsx and another library that uses JSX, for example in a monorepo where a parent folder has dependencies on React, you may encounter compilation errors when trying to add this library to your project. This is because by default, TypeScript includes all @types packages during compilation. You can address this by explicitly listing the types that you want considered during compilation, e.g.:

{
"compilerOptions": {
"types": ["node", "jest", "express"]
}
}

Rendering a Prompt

Next, your extension can use renderPrompt to render a TSX prompt. Here is an example of using TSX prompts in a Copilot chat participant that suggests SQL queries based on database context:

import { renderPrompt } from '@vscode/prompt-tsx';
import * as vscode from 'vscode';
import { TestPrompt } from './prompt';

const participant = vscode.chat.createChatParticipant(
'mssql',
async (
request: vscode.ChatRequest,
context: vscode.ChatContext,
response: vscode.ChatResponseStream,
token: vscode.CancellationToken
) => {
response.progress('Reading database context...');

const models = await vscode.lm.selectChatModels({ family: 'gpt-4' });
if (models.length === 0) {
// No models available, return early
return;
}
const chatModel = models[0];

// Render TSX prompt
const { messages } = await renderPrompt(
TestPrompt,
{ userQuery: request.prompt },
{ modelMaxPromptTokens: 4096 },
chatModel
);

const chatRequest = await chatModel.sendRequest(messages, {}, token);

// ... Report stream data to VS Code UI
}
);

Here is how you would declare the TSX prompt rendered above:

import {
AssistantMessage,
BasePromptElementProps,
PromptElement,
PromptSizing,
UserMessage,
} from '@vscode/prompt-tsx';
import * as vscode from 'vscode';

export interface PromptProps extends BasePromptElementProps {
userQuery: string;
}

export interface PromptState {
creationScript: string;
}

export class TestPrompt extends PromptElement {
override async prepare() {}

async render(state: PromptState, sizing: PromptSizing) {
const sqlExtensionApi = await vscode.extensions.getExtension('ms-mssql.mssql')?.activate();
const creationScript = await sqlExtensionApi.getDatabaseCreateScript?.();

return (
<>

You are a SQL expert.


Your task is to help the user craft SQL queries that perform their task.


You should suggest SQL queries that are performant and correct.


Return your suggested SQL query in a Markdown code block that begins with ```sql and ends
with ```.


Here are the creation scripts that were used to create the tables in my database. Pay
close attention to the tables and columns that are available in my database:


{state.creationScript}


{this.props.userQuery}


);
}
}

Please note:

  • If your prompt does asynchronous work e.g. VS Code extension API calls or additional requests to the Copilot API for chunk reranking, you can precompute this state in an optional async prepare method. prepare is called before render and the prepared state will be passed back to your prompt component's sync render method.
  • Newlines are not...

Excerpt shown — open the source for the full document.

Notability

notability 3.0/10

Routine repo for VS Code prompt tooling.