Skip to content

Commit

Permalink
Numerous QOL changes and bugfixes
Browse files Browse the repository at this point in the history
- bump to 0.1.1
- Switch thread id and project_dir to workspace state
- Add commands to manage new system
- Update readme for new way of running prompts
- Refactor commands into barrel
  • Loading branch information
ColinMcNeil committed Sep 19, 2024
1 parent aaab8e8 commit a0ca15f
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 73 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ node_modules
/prompts/functions/write_file/blah.txt
/prompts/functions/write_files/.direnv/
/prompts/functions/write_files/result
**/.DS_Store
55 changes: 46 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,58 @@
# Docker AI Prompts
# AI Prompt Runner for VSCode

Docker Labs

## What is this?

## What is this project?
If you aren't familiar with our experiments and work, please check out https://github.com/docker/labs-ai-tools-for-devs

If you are familiar with our projects, then this is simply a VSCode extension to run prompts.

This project is a research prototype. It is ready to try and will give results for any project you try it on.

## Getting started
Docker internal users: You must be opted-out of mandatory sign-in.
*Docker internal users: You must be opted-out of mandatory sign-in.*

1. Install latest VSIX file https://github.com/docker/labs-ai-tools-vscode/releases
2. Open your workspace
3. Execute command `>Set OpenAI API key...` and enter your OpenAI secret key.
4. Execute command `>save-prompt` and enter your prompt URL/ref.
Example prompt: `https://github.com/docker/labs-ai-tools-for-devs/tree/main/prompts/poem`
5. Execute command `>run-prompt`
2. Execute command `>Set OpenAI API key...` and enter your OpenAI secret key.
You can run a prompt with a local model. Docs coming soon.
3. Run a prompt

This project is a research prototype. It is ready to try and will give results for any project you try it on.
### Local Prompt:

Create file test.md

`test.md`

```md
---
extractors:
- name: project-facts
functions:
- name: write_files
---

# Improv Test
This is a test prompt...

# Prompt system
You are Dwight Schrute.

# Prompt user
Tell me about my project.

My project uses the following languages:
{{project-facts.languages}}

My project has the following files:
{{project-facts.files}}

```

Run command `>Run current file as prompt`

## Docs
https://vonwig.github.io/prompts.docs

## Development

Expand Down
24 changes: 10 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "labs-ai-tools-vscode",
"displayName": "Labs: AI Tools for VSCode",
"description": "Run & Debug AI Prompts with Dockerized tools",
"version": "0.1.0",
"version": "0.1.1",
"publisher": "docker",
"repository": {
"type": "git",
Expand All @@ -20,19 +20,6 @@
],
"main": "./out/extension.js",
"contributes": {
"configuration": {
"title": "Docker AI Prompts",
"properties": {
"docker.labs-ai-tools-vscode.project_dir": {
"type": "string",
"description": "Project directory to run AI prompts within"
},
"docker.labs-ai-tools-vscode.thread_id": {
"type": "string",
"description": "If set, will persist the conversation's Docker volume tagged with this thread ID."
}
}
},
"commands": [
{
"command": "docker.labs-ai-tools-vscode.run-prompt",
Expand Down Expand Up @@ -63,6 +50,15 @@
"command": "docker.labs-ai-tools-vscode.run-file-as-prompt",
"title": "Run current file as a prompt",
"when": "editorLangId == markdown"
},
{
"command": "docker.labs-ai-tools-vscode.set-project-dir",
"title": "Set local prompt project directory",
"when": "editorLangId == markdown"
},
{
"command": "docker.labs-ai-tools-vscode.set-thread-id",
"title": "Set prompt thread ID"
}
]
},
Expand Down
22 changes: 22 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// barreli boi
import * as vscode from 'vscode'

Check warning on line 2 in src/commands/index.ts

View workflow job for this annotation

GitHub Actions / test

Missing semicolon
import { runPrompt } from './runPrompt';
import { runHotCommand } from './runHotCommand';
import { deletePrompt, savePrompt } from './manageSavedPrompts';
import { setProjectDir } from './setProjectDir';
import { setThreadId } from './setThreadId';

type CTX = { secrets: any }

Check warning on line 9 in src/commands/index.ts

View workflow job for this annotation

GitHub Actions / test

Missing semicolon

const commands = (context: CTX) => [
{ id: 'docker.labs-ai-tools-vscode.run-commands', callback: runHotCommand },
{ id: 'docker.labs-ai-tools-vscode.save-prompt', callback: savePrompt },
{ id: 'docker.labs-ai-tools-vscode.delete-prompt', callback: deletePrompt },
{ id: 'docker.labs-ai-tools-vscode.run-workspace-as-prompt', callback: () => runPrompt(context.secrets, 'local-dir') },
{ id: 'docker.labs-ai-tools-vscode.run-file-as-prompt', callback: () => runPrompt(context.secrets, 'local-file') },
{ id: 'docker.labs-ai-tools-vscode.run-prompt', callback: () => runPrompt(context.secrets, 'remote') },
{ id: 'docker.labs-ai-tools-vscode.project-dir', callback: setProjectDir },
{ id: 'docker.labs-ai-tools-vscode.thread-id', callback: setThreadId },
]

Check warning on line 20 in src/commands/index.ts

View workflow job for this annotation

GitHub Actions / test

Missing semicolon

export default (context: CTX) => commands(context).map((comm) => vscode.commands.registerCommand(comm.id, comm.callback))

Check warning on line 22 in src/commands/index.ts

View workflow job for this annotation

GitHub Actions / test

Missing semicolon
26 changes: 2 additions & 24 deletions src/commands/runPrompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { createOutputBuffer } from "../utils/promptFilename";
import { spawnPromptImage, writeKeyToVolume } from "../utils/promptRunner";
import { verifyHasOpenAIKey } from "./setOpenAIKey";
import { getCredential } from "../utils/credential";
import { setProjectDir } from "./setProjectDir";

type PromptOption = 'local-dir' | 'local-file' | 'remote';

Expand Down Expand Up @@ -79,29 +80,6 @@ const getWorkspaceFolder = async () => {
return workspaceFolder;
};

// When running local workspace as a prompt, we need to use a config value to determine the project path
const checkHasInputWorkspace = async () => {
const existingPath = vscode.workspace.getConfiguration('docker.labs-ai-tools-vscode').get('project_dir') as string;
if (!existingPath) {
const resp = await vscode.window.showErrorMessage("No project path set in settings", "Set project path", "Cancel");
if (resp === "Set project path") {
const resp = await vscode.window.showOpenDialog({
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
title: "Select project path",
});
if (resp) {
await vscode.workspace.getConfiguration('docker.labs-ai-tools-vscode').update('project_dir', resp[0].fsPath, true);
vscode.window.showInformationMessage(`Project path set to ${resp[0].fsPath}. You can change this in settings.`);
return resp[0].fsPath;
}
}
return;
}
return existingPath;
};


export const runPrompt: (secrets: vscode.SecretStorage, mode: PromptOption) => void = (secrets: vscode.SecretStorage, mode: PromptOption) => vscode.window.withProgress({ location: vscode.ProgressLocation.Window }, async progress => {

Expand All @@ -124,7 +102,7 @@ export const runPrompt: (secrets: vscode.SecretStorage, mode: PromptOption) => v

const workspaceFolder = await getWorkspaceFolder();

const inputWorkspace = await checkHasInputWorkspace();
const inputWorkspace = await vscode.commands.executeCommand<ReturnType<typeof setProjectDir>>('docker.labs-ai-tools-vscode.project-dir', false);

const promptOption = mode === 'remote' ? await showPromptPicker() : { id: `${mode === 'local-dir' ? `local://${inputWorkspace}` : `local://${vscode.window.activeTextEditor?.document.uri.fsPath}`}`, name: `Local Prompt (${mode})` };

Expand Down
23 changes: 23 additions & 0 deletions src/commands/setProjectDir.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { window } from "vscode"

Check warning on line 1 in src/commands/setProjectDir.ts

View workflow job for this annotation

GitHub Actions / test

Missing semicolon
import { ctx } from "../extension";

export const setProjectDir = async (overwrite = true) => {
const existingVal = ctx.workspaceState.get<string>('project_dir')

Check warning on line 5 in src/commands/setProjectDir.ts

View workflow job for this annotation

GitHub Actions / test

Missing semicolon
if (!overwrite && existingVal) {
return existingVal

Check warning on line 7 in src/commands/setProjectDir.ts

View workflow job for this annotation

GitHub Actions / test

Missing semicolon
}
const directory = await window.showOpenDialog({
openLabel: 'Use this project',
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false
})

Check warning on line 14 in src/commands/setProjectDir.ts

View workflow job for this annotation

GitHub Actions / test

Missing semicolon
if (!directory) {
window.showErrorMessage('Project directory not set.')

Check warning on line 16 in src/commands/setProjectDir.ts

View workflow job for this annotation

GitHub Actions / test

Missing semicolon
return undefined;
}
const path = directory[0].fsPath

Check warning on line 19 in src/commands/setProjectDir.ts

View workflow job for this annotation

GitHub Actions / test

Missing semicolon
await ctx.workspaceState.update('project_dir', path)
window.showInformationMessage(`Project directory set to ${path}`)
return path;
}
20 changes: 20 additions & 0 deletions src/commands/setThreadId.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { window } from "vscode"
import { ctx } from "../extension"

export const setThreadId = async (overwrite = true) => {
const existingVal = ctx.workspaceState.get<string>('thread_id')
if (!overwrite && existingVal) {
return existingVal
}
const resp = await window.showInputBox({
title: 'Thread ID',
prompt: 'Enter a simple string to tag the thread volume.'
})
if (!resp) {
window.showErrorMessage('No thread ID set.')
return undefined;
}
await ctx.workspaceState.update('thread_id', resp)
window.showInformationMessage(`Thread ID set to ${resp}`)
return resp;
}
25 changes: 3 additions & 22 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { nativeClient } from './utils/lsp';
import { deletePrompt, savePrompt } from './commands/manageSavedPrompts';
import { spawnSync } from 'child_process';
import semver from 'semver';
import commands from './commands';

export let ctx: vscode.ExtensionContext;

Expand Down Expand Up @@ -83,29 +84,9 @@ export async function activate(context: vscode.ExtensionContext) {

spawnSync('docker', ['pull', "vonwig/prompts:latest"]);

let runPromptCommand = vscode.commands.registerCommand('docker.labs-ai-tools-vscode.run-prompt', () => runPrompt(context.secrets, 'remote'));
const registeredCommands = commands(context)

context.subscriptions.push(runPromptCommand);

let runBoundCommands = vscode.commands.registerCommand('docker.labs-ai-tools-vscode.run-commands', runHotCommand);

context.subscriptions.push(runBoundCommands);

let savePromptCommand = vscode.commands.registerCommand('docker.labs-ai-tools-vscode.save-prompt', savePrompt);

context.subscriptions.push(savePromptCommand);

let deletePromptCommand = vscode.commands.registerCommand('docker.labs-ai-tools-vscode.delete-prompt', deletePrompt);

context.subscriptions.push(deletePromptCommand);

let runWorkspaceAsPrompt = vscode.commands.registerCommand('docker.labs-ai-tools-vscode.run-workspace-as-prompt', () => runPrompt(context.secrets, 'local-dir'));

context.subscriptions.push(runWorkspaceAsPrompt);

let runFileAsPrompt = vscode.commands.registerCommand('docker.labs-ai-tools-vscode.run-file-as-prompt', () => runPrompt(context.secrets, 'local-file'));

context.subscriptions.push(runFileAsPrompt);
context.subscriptions.push(...registeredCommands)

nativeClient.onNotification("$bind/register", async (args: {
uri: string, blocks: {
Expand Down
9 changes: 5 additions & 4 deletions src/utils/promptRunner.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { spawn } from "child_process";
import { window, workspace } from "vscode";
import { commands, window, workspace } from "vscode";
import { setThreadId } from "../commands/setThreadId";
const output = window.createOutputChannel("Docker Labs: AI Tools");

export const getRunArgs = (promptRef: string, projectDir: string, username: string, platform: string, pat: string, render = false) => {
export const getRunArgs = async (promptRef: string, projectDir: string, username: string, platform: string, pat: string, render = false) => {
const isLocal = promptRef.startsWith('local://');
const isMarkdown = promptRef.toLowerCase().endsWith('.md');
const threadId = workspace.getConfiguration('docker.labs-ai-tools-vscode').get('thread_id') as string | undefined;
const threadId = await commands.executeCommand<ReturnType<typeof setThreadId>>('docker.labs-ai-tools-vscode.thread-id', false)
let promptArgs: string[] = ["--prompts", promptRef];
let mountArgs: string[] = ["--mount", `type=bind,source=${projectDir},target=/app/${promptRef}`];

Expand Down Expand Up @@ -89,7 +90,7 @@ const runAndStream = async (command: string, args: string[], callback: (json: an
};

export const spawnPromptImage = async (promptArg: string, projectDir: string, username: string, platform: string, pat: string, callback: (json: any) => Promise<void>) => {
const args = getRunArgs(promptArg!, projectDir!, username, platform, pat);
const args = await getRunArgs(promptArg!, projectDir!, username, platform, pat);
callback({ method: 'message', params: { debug: `Running ${args.join(' ')}` } });
return runAndStream("docker", args, callback);
};
Expand Down

0 comments on commit a0ca15f

Please sign in to comment.