-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add prompty parser #687
Add prompty parser #687
Changes from 4 commits
182b72a
70b8b05
ad3cf72
af3bde9
b30095c
2822fe4
532b5ab
721668b
82f5a5a
24cec98
523fa43
48e72a7
3937fa2
4be861f
e80e9c3
9e40068
35cf3e7
e604b09
35ce3ad
d7040d0
fad5773
2f8c934
1879019
67be940
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,7 +13,7 @@ | |
The script acts as a regular node.js automation script and uses [runPrompt](/genaiscript/reference/scripts/inner-prompts) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect header formatting, should use Markdown header style.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect heading format, remove emoji from heading.
|
||
to issue calls to the LLM and ask the user to confirm the generated text. | ||
|
||
## 🔍 **Explaining the Script** | ||
## Explaining the Script | ||
|
||
First, we check if there are any staged changes in the Git repository: | ||
|
||
|
@@ -24,7 +24,7 @@ | |
If no changes are staged, we ask the user if they want to stage all changes. If the user confirms, we stage all changes. Otherwise, we bail out. | ||
|
||
```ts | ||
const stage = await host.confirm("No staged changes. Stage all changes?", { | ||
const stage = await host.confirm("No staged changes. Stage all changes?", { | ||
default: true, | ||
}) | ||
if (stage) { | ||
|
@@ -70,8 +70,7 @@ | |
|
||
```ts | ||
if (choice === "edit") { | ||
message = await host.input("Edit commit message", | ||
{ required: true }) | ||
message = await host.input("Edit commit message", { required: true }) | ||
choice = "commit" | ||
} | ||
``` | ||
|
@@ -84,7 +83,7 @@ | |
} | ||
``` | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect heading formatting, should use markdown heading style with '#'.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect header formatting, should use Markdown header style.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect heading format, remove emoji from heading.
|
||
## 🚀 **Running the Script** | ||
## Running the Script | ||
|
||
You can run this script using the [CLI](/genaiscript/reference/cli). | ||
|
||
|
@@ -96,8 +95,11 @@ | |
|
||
```json '"gcm": "genaiscript run gcm"' | ||
{ | ||
"devDependencies": { | ||
"genaiscript": "*" | ||
}, | ||
"scripts": { | ||
"gcm": "npx --yes genaiscript run gcm" | ||
"gcm": "genaiscript run gcm" | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect JSON format, missing curly brace to close the JSON object.
pelikhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
``` | ||
|
@@ -108,7 +110,35 @@ | |
npm run gcm | ||
``` | ||
|
||
## Using git hooks | ||
|
||
You can also attach to the [commit-msg](https://git-scm.com/docs/githooks#_commit_msg) git hook to run the message generation on demand. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo found, change "huksy" to "husky".
|
||
Using the [huksy](https://typicode.github.io/husky/) framework, we can register the execution | ||
of genaiscript in the `.husky/commit-msg` file. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect tool name 'huksy'; the correct name is 'Husky'.
|
||
|
||
The `commit-msg` hook receives a file location where the message is stored. We pass this parameter to the script | ||
so that it gets populated in the `env.files` variable. | ||
|
||
```bash title=".husky/commit-msg" | ||
npx --yes genaiscript run commit-msg "$1" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect usage of 'npx --yes'; it should be removed as it is not necessary when running local npm scripts or dependencies.
|
||
``` | ||
|
||
In the script, we check if the content of the file already has a user message, otherwize generate a new message. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo found, change "otherwize" to "otherwise".
pelikhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
```js title="commit-msg.genai.mts" | ||
const msg = env.files[0] // file created by git to hold the message | ||
const msgContent = msg.content // check if the user added any message | ||
?.split(/\n/g) | ||
.filter((l) => l && !/^#/.test(l)) // filter out comments | ||
.join("\n") | ||
if (msgContent) cancel("commit message already exists") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Comments in JavaScript should start with // or /*, not #.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ensure the logic for checking if a commit message already exists is correct and handles edge cases properly.
|
||
|
||
... | ||
|
||
await host.writeText(msg.filename, message) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect code comment 'otherwize'; the correct spelling is 'otherwise'.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code comment 'cancel("commit message already exists")' suggests using a function 'cancel' which is not defined or explained in the provided code snippet.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Verify that the script correctly writes the commit message to the file specified by the git hook.
|
||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The section "Using git hooks" introduces the use of a third-party tool called "huksy" which is likely a typo and should be corrected to "husky".
|
||
|
||
## Acknowledgements | ||
|
||
This script was inspired from Karpathy's | ||
This script was inspired from Karpathy's | ||
[commit message generator](https://gist.github.com/karpathy/1dd0294ef9567971c1e4348a90d69285). |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,10 +2,11 @@ | |
title: Commands | ||
description: List of all CLI commands | ||
sidebar: | ||
order: 100 | ||
order: 100 | ||
--- | ||
|
||
<!-- autogenerated, do not edit --> | ||
|
||
A full list of the CLI command and its respective help text. | ||
|
||
## `run` | ||
|
@@ -308,7 +309,8 @@ | |
code <file> [query] Parse code using tree sitter and executes a | ||
query | ||
tokens [options] <files...> Count tokens in a set of files | ||
jsonl2json Converts JSONL files to a JSON file | ||
Check failure on line 312 in docs/src/content/docs/reference/cli/commands.md GitHub Actions / build
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The command
|
||
prompty <file...> Converts .prompty files to genaiscript | ||
``` | ||
|
||
### `parse fence` | ||
|
@@ -388,7 +390,21 @@ | |
Options: | ||
-h, --help display help for command | ||
``` | ||
|
||
### `parse prompty` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Incorrect heading format, remove the emoji to match MDX standards.
pelikhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
``` | ||
Usage: genaiscript parse prompty [options] <file...> | ||
|
||
Converts .prompty files to genaiscript | ||
|
||
Arguments: | ||
file input JSONL files | ||
|
||
Options: | ||
-h, --help display help for command | ||
Check failure on line 405 in docs/src/content/docs/reference/cli/commands.md GitHub Actions / build
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The section
|
||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate content, the
|
||
|
||
## `workspace` | ||
|
||
``` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
parseHTMLToText, | ||
parsePDF, | ||
parseTokens, | ||
prompty2genaiscript, | ||
} from "./parse" | ||
import { compileScript, createScript, fixScripts, listScripts } from "./scripts" | ||
import { codeQuery } from "./codequery" | ||
|
@@ -299,6 +300,11 @@ | |
.command("jsonl2json", "Converts JSONL files to a JSON file") | ||
.argument("<file...>", "input JSONL files") | ||
.action(jsonl2json) | ||
parser | ||
.command("prompty") | ||
.description("Converts .prompty files to genaiscript") | ||
.argument("<file...>", "input JSONL files") | ||
.action(prompty2genaiscript) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The argument description for the "prompty" command is incorrect. It should not be "input JSONL files" but rather "input .prompty files".
pelikhan marked this conversation as resolved.
Show resolved
Hide resolved
pelikhan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const workspace = program | ||
.command("workspace") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ | |
import { YAMLStringify } from "../../core/src/yaml" | ||
import { resolveTokenEncoder } from "../../core/src/encoders" | ||
import { DEFAULT_MODEL } from "../../core/src/constants" | ||
import { promptyParse, promptyToGenAIScript } from "../../core/src/prompty" | ||
|
||
export async function parseFence(language: string, file: string) { | ||
const res = await parsePdf(file) | ||
|
@@ -69,3 +70,15 @@ | |
} | ||
console.log(text) | ||
} | ||
|
||
export async function prompty2genaiscript(files: string[]) { | ||
const fs = await expandFiles(files) | ||
for (const f of fs) { | ||
console.log(f) | ||
const gf = replaceExt(f, ".genai.mts") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no error handling for the promptyParse function. If the parsing fails, the error will not be caught and the application may crash.
|
||
const content = await readText(f) | ||
const doc = promptyParse(content) | ||
const script = promptyToGenAIScript(doc) | ||
await writeText(gf, script) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is no error handling for the async operations within the "prompty2genaiscript" function. If an error occurs during file reading or writing, it will not be caught and handled.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The functions 'expandFiles', 'replaceExt', 'readText', and 'writeText' are used but not imported or defined in this file.
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,7 +18,7 @@ export async function interpolateVariables( | |
|
||
// remove prompty roles | ||
// https://github.com/microsoft/prompty/blob/main/runtime/prompty/prompty/parsers.py#L113C21-L113C77 | ||
content = content.replace(/^\s*(system|user):\s*$/gim, "\n") | ||
content = content.replace(/^\s*(system|user|assistant)\s*:\s*$/gim, "\n") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The regular expression used to replace roles in the content has been updated to include 'assistant' along with 'system' and 'user'. This change might affect the existing functionality if the 'assistant' role was not intended to be replaced in the content.
|
||
|
||
// remove xml tags | ||
// https://humanloop.com/docs/prompt-file-format | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import { promptyParse } from "./prompty" | ||
import { describe, test, beforeEach } from "node:test" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The imported modules 'node:test' and 'node:assert/strict' might not exist. Please ensure that these modules are available in the node environment.
|
||
import assert from "node:assert/strict" | ||
|
||
describe("promptyParse", () => { | ||
test("correctly parses an empty markdown string", () => { | ||
const result = promptyParse("") | ||
assert.deepStrictEqual(result, { | ||
frontmatter: {}, | ||
content: "", | ||
messages: [], | ||
}) | ||
}) | ||
|
||
test("correctly parses a markdown string without frontmatter", () => { | ||
const content = "This is a sample content without frontmatter." | ||
const result = promptyParse(content) | ||
assert.deepStrictEqual(result, { | ||
frontmatter: {}, | ||
content: content, | ||
messages: [{ role: "system", content: content }], | ||
}) | ||
}) | ||
|
||
test("correctly parses a markdown string with valid frontmatter", () => { | ||
const markdownString = `--- | ||
name: Test | ||
description: A test description | ||
version: 1.0.0 | ||
authors: | ||
- Author1 | ||
- Author2 | ||
tags: | ||
- tag1 | ||
- tag2 | ||
sample: | ||
key: value | ||
--- | ||
# Heading | ||
Content below heading.` | ||
const result = promptyParse(markdownString) | ||
assert.deepStrictEqual(result.frontmatter, { | ||
name: "Test", | ||
description: "A test description", | ||
version: "1.0.0", | ||
authors: ["Author1", "Author2"], | ||
tags: ["tag1", "tag2"], | ||
sample: { key: "value" }, | ||
}) | ||
assert.strictEqual(result.content, "# Heading\nContent below heading.") | ||
}) | ||
|
||
test("correctly parses a markdown string with content split into roles", () => { | ||
const markdownContent = `user: | ||
User's message | ||
assistant: | ||
Assistant's reply | ||
user: | ||
Another message from the user` | ||
const result = promptyParse(markdownContent) | ||
assert.deepStrictEqual(result.messages, [ | ||
{ role: "user", content: "User's message" }, | ||
{ role: "assistant", content: "Assistant's reply" }, | ||
{ role: "user", content: "Another message from the user" }, | ||
]) | ||
}) | ||
|
||
test("correctly handles a markdown string with content but without roles", () => { | ||
const markdownContent = `Just some content without specifying roles.` | ||
const result = promptyParse(markdownContent) | ||
assert.deepStrictEqual(result.messages, [ | ||
{ role: "system", content: markdownContent }, | ||
]) | ||
}) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect heading formatting, should use markdown heading style with '#'.