From eb427375c448ed6cdca741592a7fc6b81d6d4ba7 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 12 Jun 2024 15:44:04 +0000 Subject: [PATCH 1/3] centralize vscode.Uri usage --- packages/vscode/src/browser.ts | 2 +- packages/vscode/src/edit.ts | 12 +++++-- packages/vscode/src/fragmentcommands.ts | 8 ++--- packages/vscode/src/lmaccess.ts | 2 +- packages/vscode/src/promptcommands.ts | 6 ++-- packages/vscode/src/state.ts | 43 ++----------------------- packages/vscode/src/statusbar.ts | 6 ++-- packages/vscode/src/testcontroller.ts | 4 +-- packages/vscode/src/vshost.ts | 11 +++++++ 9 files changed, 37 insertions(+), 57 deletions(-) diff --git a/packages/vscode/src/browser.ts b/packages/vscode/src/browser.ts index e41c3c7a69..d78c0235f6 100644 --- a/packages/vscode/src/browser.ts +++ b/packages/vscode/src/browser.ts @@ -3,6 +3,6 @@ import * as vscode from "vscode" export async function openUrlInTab(url: string) { await vscode.commands.executeCommand( "simpleBrowser.show", - vscode.Uri.parse(url) + vscode.Uri.parse(url, true) ) } diff --git a/packages/vscode/src/edit.ts b/packages/vscode/src/edit.ts index 87bee74ad4..87b1cd54fe 100644 --- a/packages/vscode/src/edit.ts +++ b/packages/vscode/src/edit.ts @@ -1,5 +1,6 @@ import * as vscode from "vscode" import { Fragment, eolPosition } from "genaiscript-core" +import { ExtensionState } from "./state" export function toPos(p: CharPosition | number) { if (typeof p === "number") return new vscode.Position(p, 0) @@ -7,7 +8,11 @@ export function toPos(p: CharPosition | number) { } export function toRange(p: CharRange | LineRange) { if (!p) return undefined - if (Array.isArray(p) && typeof p[0] === "number" && typeof p[1] === "number") + if ( + Array.isArray(p) && + typeof p[0] === "number" && + typeof p[1] === "number" + ) return new vscode.Range( new vscode.Position(p[0], 0), new vscode.Position(p[1], eolPosition) @@ -21,6 +26,7 @@ export function fragmentRange(frag: Fragment) { } export async function applyEdits( + state: ExtensionState, edits: Edits[], options?: { needsConfirmation?: boolean @@ -31,7 +37,7 @@ export async function applyEdits( const { needsConfirmation } = options || {} const edit = new vscode.WorkspaceEdit() for (const e of edits) { - const uri = vscode.Uri.file(e.filename) + const uri = state.host.toUri(e.filename) const meta: vscode.WorkspaceEditEntryMetadata = { label: e.label, needsConfirmation: false, @@ -68,7 +74,7 @@ export async function applyEdits( } } if (needsConfirmation) - edit.insert(vscode.Uri.file(edits[0].filename), toPos([0, 0]), "", { + edit.insert(state.host.toUri(edits[0].filename), toPos([0, 0]), "", { label: "Fake edit", needsConfirmation: true, }) diff --git a/packages/vscode/src/fragmentcommands.ts b/packages/vscode/src/fragmentcommands.ts index 3e86bf1561..8f87a50f2f 100644 --- a/packages/vscode/src/fragmentcommands.ts +++ b/packages/vscode/src/fragmentcommands.ts @@ -73,7 +73,7 @@ async function showPromptParametersQuickPicks( } export function activateFragmentCommands(state: ExtensionState) { - const { context } = state + const { context, host } = state const { subscriptions } = context const pickTemplate = async (options?: { @@ -110,7 +110,7 @@ export function activateFragmentCommands(state: ExtensionState) { let fragment: Fragment if (typeof frag === "string" && !/\.gpspec\.md(:.*)?$/i.test(frag)) { - const fragUri = vscode.Uri.file(frag) + const fragUri = host.toUri(frag) if (await checkFileExists(fragUri)) { const prj = await state.parseDocument(fragUri) fragment = prj?.rootFiles?.[0].fragments?.[0] @@ -119,7 +119,7 @@ export function activateFragmentCommands(state: ExtensionState) { fragment = prj?.rootFiles?.[0].fragments?.[0] } } else if (typeof frag === "string" && GENAI_JS_REGEX.test(frag)) { - const fragUri = vscode.Uri.file(frag) + const fragUri = host.toUri(frag) const prj = await state.parseDocument(fragUri) fragment = prj?.rootFiles?.[0].fragments?.[0] } else { @@ -223,7 +223,7 @@ export function activateFragmentCommands(state: ExtensionState) { fragment = state.project.resolveFragment(fragment) if (!fragment) return const { file, startPos } = fragment - const uri = vscode.Uri.file(file.filename) + const uri = host.toUri(file.filename) const editor = await vscode.window.showTextDocument(uri) const pos = new vscode.Position(...startPos) editor.selections = [new vscode.Selection(pos, pos)] diff --git a/packages/vscode/src/lmaccess.ts b/packages/vscode/src/lmaccess.ts index d6f980c28c..b2b0cd693d 100644 --- a/packages/vscode/src/lmaccess.ts +++ b/packages/vscode/src/lmaccess.ts @@ -109,7 +109,7 @@ export async function pickLanguageModel( else { await updateConnectionConfiguration(res.provider, res.apiType) const doc = await vscode.workspace.openTextDocument( - vscode.Uri.joinPath(state.host.projectUri, ".env") + state.host.toUri("./.env") ) await vscode.window.showTextDocument(doc) return undefined diff --git a/packages/vscode/src/promptcommands.ts b/packages/vscode/src/promptcommands.ts index 2dfc8c185b..60e649bae0 100644 --- a/packages/vscode/src/promptcommands.ts +++ b/packages/vscode/src/promptcommands.ts @@ -5,12 +5,12 @@ import { builtinPromptUri } from "./markdowndocumentprovider" import { templatesToQuickPickItems } from "./fragmentcommands" export function activatePromptCommands(state: ExtensionState) { - const { context } = state + const { context, host } = state const { subscriptions } = context async function showPrompt(fn: string) { await state.fixPromptDefinitions() - vscode.window.showTextDocument(vscode.Uri.file(fn)) + vscode.window.showTextDocument(host.toUri(fn)) await state.parseWorkspace() } @@ -73,7 +73,7 @@ export function activatePromptCommands(state: ExtensionState) { "genaiscript.prompt.navigate", async (prompt: PromptScript) => { const uri = prompt.filename - ? vscode.Uri.file(prompt.filename) + ? host.toUri(prompt.filename) : builtinPromptUri(prompt.id) await vscode.window.showTextDocument(uri) } diff --git a/packages/vscode/src/state.ts b/packages/vscode/src/state.ts index cfe528fc06..99a66dbeb8 100644 --- a/packages/vscode/src/state.ts +++ b/packages/vscode/src/state.ts @@ -169,7 +169,7 @@ export class ExtensionState extends EventTarget { } private async saveScripts() { - const dir = vscode.Uri.file(dotGenaiscriptPath(".")) + const dir = this.host.toUri(dotGenaiscriptPath(".")) await vscode.workspace.fs.createDirectory(dir) // add .gitignore @@ -214,7 +214,7 @@ temp/ req.editsApplied = null this.dispatchChange() - const applied = await applyEdits(edits, { + const applied = await applyEdits(this, edits, { needsConfirmation: true, }) @@ -251,43 +251,6 @@ temp/ if (edits?.length) this.applyEdits() } catch (e) { if (isCancelError(e)) return - /* - else if (isRequestError(e, 403)) { - const trace = "Open Trace" - const res = await vscode.window.showErrorMessage( - "OpenAI token refused (403).", - trace - ) - if (res === trace) - vscode.commands.executeCommand( - "genaiscript.request.open.trace" - ) - } else if (isRequestError(e, 400, "context_length_exceeded")) { - const help = "Documentation" - const title = `Context length exceeded.` - const msg = `${title}. - ${errorMessage(e)}` - const res = await vscode.window.showWarningMessage(msg, help) - if (res === help) - vscode.env.openExternal( - vscode.Uri.parse(CONTEXT_LENGTH_DOCUMENTATION_URL) - ) - } else if (isRequestError(e, 400)) { - const help = "Documentation" - const msg = `OpenAI model error (400). -${errorMessage(e)}` - const res = await vscode.window.showWarningMessage(msg, help) - if (res === help) - vscode.env.openExternal( - vscode.Uri.parse(TOKEN_DOCUMENTATION_URL) - ) - } else if (isRequestError(e)) { - const msg = isRequestError(e, 404) - ? `LLM model not found (404).` - : errorMessage(e) - await vscode.window.showWarningMessage(msg) - } else - */ throw e } } @@ -594,7 +557,7 @@ ${!GENAI_JS_REGEX.test(fn) ? `- [${fn}](./${fn})` : ""} const murl = /\[([^\]]+)\]\((https:\/\/([^)]+))\)/.exec(message) if (murl) { value = murl[1] - target = vscode.Uri.parse(murl[2]) + target = vscode.Uri.parse(murl[2], true) } const r = new vscode.Diagnostic( toRange(d.range), diff --git a/packages/vscode/src/statusbar.ts b/packages/vscode/src/statusbar.ts index ded935994e..7a51da8a30 100644 --- a/packages/vscode/src/statusbar.ts +++ b/packages/vscode/src/statusbar.ts @@ -13,8 +13,8 @@ export function activateStatusBar(state: ExtensionState) { ) statusBarItem.command = "genaiscript.request.status" const updateStatusBar = async () => { - const { parsing } = state - const { computing, progress, options } = state.aiRequest || {} + const { parsing, host, aiRequest } = state + const { computing, progress, options } = aiRequest || {} const { template, fragment } = options || {} const { tokensSoFar } = progress || {} statusBarItem.text = toStringList( @@ -28,7 +28,7 @@ export function activateStatusBar(state: ExtensionState) { const md = new vscode.MarkdownString( toMarkdownString( fragment - ? Utils.basename(vscode.Uri.file(fragment.file.filename)) + ? Utils.basename(host.toUri(fragment.file.filename)) : undefined, template ? `- tool: ${template.title} (${template.id})` diff --git a/packages/vscode/src/testcontroller.ts b/packages/vscode/src/testcontroller.ts index 70b52df4aa..eef80c32bf 100644 --- a/packages/vscode/src/testcontroller.ts +++ b/packages/vscode/src/testcontroller.ts @@ -16,7 +16,7 @@ import { PROMPTFOO_VERSION } from "../../cli/src/version" import { openUrlInTab } from "./browser" export async function activateTestController(state: ExtensionState) { - const { context } = state + const { context, host } = state const { subscriptions } = context const ctrl = vscode.tests.createTestController(TOOL_ID, "GenAIScript") @@ -135,7 +135,7 @@ export async function activateTestController(state: ExtensionState) { const file = ctrl.createTestItem( script.id, script.id, - vscode.Uri.file(script.filename) + host.toUri(script.filename) ) file.description = script.title ?? script.description ctrl.items.add(file) diff --git a/packages/vscode/src/vshost.ts b/packages/vscode/src/vshost.ts index b38fe4d559..23553faabc 100644 --- a/packages/vscode/src/vshost.ts +++ b/packages/vscode/src/vshost.ts @@ -16,6 +16,7 @@ import { LanguageModel, MODEL_PROVIDER_AZURE, AbortSignalOptions, + HTTPS_REGEX, } from "genaiscript-core" import { Uri } from "vscode" import { ExtensionState } from "./state" @@ -138,6 +139,16 @@ export class VSCodeHost extends EventTarget implements Host { return r.fsPath } + toUri(filenameOrUrl: string): vscode.Uri { + const folder = this.projectUri + if (!filenameOrUrl) return folder + if (/^[a-z][a-z0-9+\-.]*:\/\//.test(filenameOrUrl)) + return vscode.Uri.parse(filenameOrUrl, true) + if (this.path.isAbsolute(filenameOrUrl)) + return vscode.Uri.file(filenameOrUrl) + else return Utils.resolvePath(folder, filenameOrUrl) + } + log(level: LogLevel, msg: string): void { const output = this.state.output switch (level) { From be0c0cfda512bcf2d802f9a53061f93d7952b768 Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 12 Jun 2024 16:05:42 +0000 Subject: [PATCH 2/3] cleanup --- packages/sample/genaisrc/code-annotator.genai.js | 6 +++++- packages/vscode/src/vshost.ts | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/sample/genaisrc/code-annotator.genai.js b/packages/sample/genaisrc/code-annotator.genai.js index bd4335aa48..ead029b7da 100644 --- a/packages/sample/genaisrc/code-annotator.genai.js +++ b/packages/sample/genaisrc/code-annotator.genai.js @@ -6,6 +6,10 @@ script({ group: "hello world", system: ["system", "system.annotations"], temperature: 0, + files: "src/counting.py", + tests: { + files: "src/counting.py" + } }) def( @@ -16,7 +20,7 @@ def( ) $` -You are an EXPORT software developer with deep knowledge of all programming languages. +You are an EXPERT software developer with deep knowledge of all programming languages. Your job is to do a code review of CODE and create ANNOTATION with code improvement notice, warning and errors. - No more than 5 annotations per code file. diff --git a/packages/vscode/src/vshost.ts b/packages/vscode/src/vshost.ts index 23553faabc..c5d1c5295c 100644 --- a/packages/vscode/src/vshost.ts +++ b/packages/vscode/src/vshost.ts @@ -16,7 +16,6 @@ import { LanguageModel, MODEL_PROVIDER_AZURE, AbortSignalOptions, - HTTPS_REGEX, } from "genaiscript-core" import { Uri } from "vscode" import { ExtensionState } from "./state" From 685fe5bd63e0c009dd989b918907a42de5e0b8cb Mon Sep 17 00:00:00 2001 From: Peli de Halleux Date: Wed, 12 Jun 2024 16:06:13 +0000 Subject: [PATCH 3/3] tweak review prompt --- packages/sample/genaisrc/pr-review.genai.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/sample/genaisrc/pr-review.genai.js b/packages/sample/genaisrc/pr-review.genai.js index fae2c62c40..33b2162cef 100644 --- a/packages/sample/genaisrc/pr-review.genai.js +++ b/packages/sample/genaisrc/pr-review.genai.js @@ -37,5 +37,5 @@ If the changes look good, respond "LGTM :rocket:". If you have any concerns, pro - All the TypeScript files are compiled and type-checked by the TypeScript compiler. Do not report issues that the TypeScript compiler would find. - only report functional issues - Use emojis -- If available, suggest code fixes and improvements +- If available, suggest code fixes and improvements using a diff format. `