Skip to content
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

Blog ideation #643

Merged
merged 5 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"sysr",
"treesitter",
"typecheck",
"unfence",
"vsix",
"xpai"
],
Expand Down
5 changes: 5 additions & 0 deletions docs/genaisrc/genaiscript.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions docs/src/content/docs/reference/cli/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@
Commands:
list List all available scripts in workspace
create <name> Create a new script
fix fix all definition files

Check failure on line 122 in docs/src/content/docs/reference/cli/commands.md

View workflow job for this annotation

GitHub Actions / build

Usage description for 'compile' command is inconsistent with the updated usage syntax.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage of the 'compile' command has been updated to include '<folders...>' but the description 'Compile all script in workspace' has not been updated to reflect the change in usage. Consider revising the description to indicate that the command now accepts specific folder patterns as arguments.

generated by pr-docs-review-commit command_usage_inconsistency

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usage description for 'compile' command is inconsistent with the updated usage syntax.

generated by pr-docs-review-commit incorrect_usage

compile Compile all script in workspace
compile [folders...] Compile all script in workspace
model [options] [script] List model connection information for scripts
help [command] display help for command
```
Expand Down Expand Up @@ -164,10 +164,13 @@
### `scripts compile`

```
Usage: genaiscript scripts compile [options]
Usage: genaiscript scripts compile [options] [folders...]

Compile all script in workspace

Check failure on line 169 in docs/src/content/docs/reference/cli/commands.md

View workflow job for this annotation

GitHub Actions / build

Description for 'compile' command is incomplete, missing the explanation for the new '[folders...]' argument.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be a typo here. It should be "Compile all scripts in workspace" instead of "Compile all script in workspace".

generated by pr-docs-review-commit typo

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Description for 'compile' command is incomplete, missing the explanation for the new '[folders...]' argument.

generated by pr-docs-review-commit incorrect_description


Arguments:
folders Pattern to match files

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The description "Pattern to match files" for the argument 'folders' is unclear. It should specify that 'folders' is a pattern to match directories containing scripts to compile.

generated by pr-docs-review-commit description_error


Options:
-h, --help display help for command
```
Expand Down
105 changes: 88 additions & 17 deletions genaisrc/blog-generator.genai.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
script({
description: "Generate a blog post for Dev.to from the documentation",
model: "openai:gpt-4o",
system: [],
tools: ["fs"],
parameters: {
theme: {
Expand Down Expand Up @@ -38,7 +39,7 @@ Use these files to help you generate a topic for the blog post.
`
},
{
model: "openai:gpt-4o",
label: "generate theme",
temperature: 1,
system: [
"system.tools",
Expand All @@ -51,32 +52,99 @@ Use these files to help you generate a topic for the blog post.
topic = res.text
}

// generate a working code snippet from topic
let snippet
{
const { text, fences, error } = await runPrompt(
(_) => {
_.defTool(
"genaiscript_typecheck",
"Validates the syntax and type checks a GenAIScript source code",
{
source: {
type: "string",
description: "The GenAIScript javascript source code",
},
},
async ({ source }) => {
// write file to a scratch folder
console.log(`checking source code`)
await workspace.writeText(
"temp/blog-post/script.genai.mjs",
source
)
return await host.exec("node", [
"packages/cli/built/genaiscript.cjs",
"scripts",
"compile",
"temp/blog-post",
])
}
)

_.def("TOPIC", topic)
_.$`You are a JavaScript developer expert on GenAIScript (https://microsoft.github.io/genaiscript).

# Task

- Generate a GenAISCript source code that implements the idea described in TOPIC.
- Validate syntax and checking with genaiscript_typecheck.
- Respond ONLY with the JavaScript source code. Do NOT fence code in markdown. Do not add text around code.

# Information

Use these files to help you generate a topic for the blog post.

- the code will be executed in node.js by the GenAIScript CLI
- the genaiscript type definition: genaiscript/genaiscript.d.ts. Assume that all globals are ambient. Do not import or require genaiscript module.
- the genaiscript samples: packages/sample/src/*.genai.*
- the documentation: docs/src/content/docs/**/*.md*
- the online documentation: https://microsoft.github.io/genaiscript/
`
},
{
label: "generate script",
system: [
"system.tools",
"system.fs_find_files",
"system.fs_read_file",
],
temperature: 0.5,
}
)
if (error) throw error
snippet =
fences.find(
({ language }) => language === "js" || language === "javascript"
)?.content ?? text
}

// generate a blog post
const today = new Date()
const yyyy = today.getFullYear()
const mm = String(today.getMonth() + 1).padStart(2, "0")
const dd = String(today.getDate()).padStart(2, "0")
const formattedDate = `${yyyy}-${mm}-${dd}`
def("TOPIC", topic)
def("SNIPPET", snippet)

$`
# Task

Generate a blog post for the web site https://dev.to on the topic of using GenAIScript script
to solve the task described in TOPIC.
Generate a blog post that explains how to write the code in SNIPPET.

The main purpose is to create a genaiscript prompt generation script.
Respond with the markdown content of the blog post.

# Writing style and instructions

- generate the blog post content, nothing else
- save the generated markdown to a new file under the docs/src/content/docs/blog folder. THIS IS IMPORTANT
- use a clear and engaging tone
- illustrate with code examples
- explain each line of code separately, link to the documentation if possible
- title should be click-bait, use quotes (") around title
- do NOT generate cover_image
- the script will be execute by GenAIScript CLI
- the TypeScript API is defined in the file genaisrc/genaiscript.d.ts
- the TypeScript API is defined in the file genaisrc/genaiscript.d.ts. Assume that all globals are ambient. Do not import or require genaiscript module.
- generate a single file for the blog post, do NOT generate other files
- examples of GenAIScript code are in folder packages/sample/src/**/*.genai.*js
- do NOT explain how to install GenAIScript or the GenAIScript CLI
Expand All @@ -97,17 +165,20 @@ You can extract information from the following files:
- the online documentation: https://microsoft.github.io/genaiscript/

`

defFileOutput("docs/src/content/docs/blog/*.md", "The generated blog post")
defOutputProcessor((output) => {
if (!Object.keys(output.fileEdits || {}).length) {
const fence = output.fences.find((f) => f.language === "markdown")
if (fence) {
const files = {
[`docs/src/content/docs/blog/unnamed-${formattedDate}.md`]:
fence.content,
}
return { files }
}
let md = output.text
if (/\`\`\`markdown\n/.test(md)) {
md = md.replace(/\`\`\`markdown\n/g, "").replace(/\`\`\`\n?$/g, "")
}
const fm = parsers.frontmatter(md)
const fn =
`docs/src/content/docs/blog/${fm.title.replace(/[^a-z0-9]+/gi, "-")}.md`.toLocaleLowerCase()
const sn =
`packages/sample/genaisrc/blog/${fm.title.replace(/[^a-z0-9]+/gi, "-")}.genai.mjs`.toLocaleLowerCase()
return {
files: {
[fn]: md,
[sn]: snippet,
},
}
})
5 changes: 5 additions & 0 deletions genaisrc/genaiscript.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,13 @@
.option("-cs, --csv-separator <string>", "csv separator", "\t")
.option("-ae, --apply-edits", "apply file edits")
.option(
"--vars <namevalue...>",
"variables, as name=value, stored in env.vars"
)
.option("-rr, --run-retry <number>", "number of retries for the entire run")
.option(
"-rr, --run-retry <number>",
"number of retries for the entire run"
)

Check failure on line 154 in packages/cli/src/cli.ts

View workflow job for this annotation

GitHub Actions / build

The function `cli` is missing validation for the argument `number` in the option `-rr, --run-retry <number>`. It's important to validate user inputs to prevent unexpected behavior or errors.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semicolon

generated by pr-review-commit missing_semi

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function cli does not validate the input arguments. This could lead to unexpected behavior or errors if the function is called with invalid or unexpected arguments. It's a good practice to validate function arguments to ensure they match the expected format and type.

generated by pr-review-commit missing_argument_validation

.action(runScriptWithExitCode)

const test = program.command("test")
Expand Down Expand Up @@ -205,6 +208,7 @@
scripts
.command("compile")
.description("Compile all script in workspace")
.argument("[folders...]", "Pattern to match files")
.action(compileScript)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semicolon

generated by pr-review-commit missing_semi

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function cli does not validate the input arguments for the compile command. This could lead to unexpected behavior or errors if the function is called with invalid or unexpected arguments. It's a good practice to validate function arguments to ensure they match the expected format and type.

generated by pr-review-commit missing_argument_validation

scripts
.command("model")
Expand Down
13 changes: 10 additions & 3 deletions packages/cli/src/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,25 @@ export async function createScript(name: string) {
const t = coreCreateScript(name)
const pr = await copyPrompt(t, { fork: false, name })
console.log(`created script at ${pr}`)
await compileScript()
await compileScript([])
}

export async function fixScripts() {
const project = await buildProject()
await fixPromptDefinitions(project)
}

export async function compileScript() {
export async function compileScript(folders: string[]) {
const project = await buildProject()
await fixPromptDefinitions(project)
for (const folder of project.folders()) {
const scriptFolders = project.folders()
const foldersToCompile = (
folders?.length ? folders : project.folders().map((f) => f.dirname)
)
.map((f) => scriptFolders.find((sf) => sf.dirname === f))
.filter((f) => f)

for (const folder of foldersToCompile) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no error handling for the case when the folders argument is not provided or is an empty array. This could lead to unexpected behavior or errors. Consider adding error handling or a default value. 🚧

generated by pr-review-commit missing_error_handling

const { dirname, js, ts } = folder
logVerbose(`compiling ${dirname}`)
if (js) {
Expand Down
14 changes: 11 additions & 3 deletions packages/core/src/chat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
checkCancelled,
} from "./cancellation"
import { assert, logError, logVerbose } from "./util"
import { extractFenced, findFirstDataFence } from "./fence"
import { extractFenced, findFirstDataFence, unfence } from "./fence"
import {
toStrictJSONSchema,
validateFencesWithSchema,
Expand Down Expand Up @@ -330,13 +330,21 @@ Repair the DATA_FORMAT_ISSUES. THIS IS IMPORTANT.`
return true
}

function assistantText(messages: ChatCompletionMessageParam[]) {
function assistantText(
messages: ChatCompletionMessageParam[],
responseType?: PromptTemplateResponseType
) {
let text = ""
for (let i = messages.length - 1; i >= 0; i--) {
const msg = messages[i]
if (msg.role !== "assistant") break
text = msg.content + text
}

if (responseType === undefined) {
text = unfence(text, "(markdown|md)")
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function unfence is called only when responseType is undefined. However, there is no handling for the case when responseType is not undefined. This could lead to unexpected behavior. Consider adding handling for this case. 🚧

generated by pr-review-commit unhandled_case


return text
}

Expand All @@ -352,7 +360,7 @@ function structurifyChatSession(
): RunPromptResult {
const { trace, responseType, responseSchema } = options
const { resp, err } = others || {}
const text = assistantText(messages)
const text = assistantText(messages, responseType)
const annotations = parseAnnotations(text)
const finishReason = isCancelError(err)
? "cancel"
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export const RECONNECT = "reconnect"
export const OPEN = "open"
export const MAX_CACHED_TEMPERATURE = 0.5
export const MAX_CACHED_TOP_P = 0.5
export const MAX_TOOL_CALLS = 100
export const MAX_TOOL_CALLS = 10000

// https://learn.microsoft.com/en-us/azure/ai-services/openai/reference
// https://github.com/Azure/azure-rest-api-specs/blob/main/specification/cognitiveservices/data-plane/AzureOpenAI/inference/stable/2024-02-01/inference.yaml
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/fence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,12 @@ ${validation.error.split("\n").join("\n> ")}`
)
.join("\n")
}

export function unfence(text: string, language: string) {
const startRx = new RegExp(`^\`\`\`${language}\n`)
const endRx = /\n```[\n\s]*$/
if (startRx.test(text) && endRx.test(text)) {
return text.replace(startRx, "").replace(endRx, "")
}
return text
}
5 changes: 5 additions & 0 deletions packages/core/src/genaisrc/genaiscript.d.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/core/src/promptrunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ export async function runTemplate(
trace.detailsFenced(`πŸ“ file ${fn}`, content)
const fileEdit = await getFileEdit(fn)
fileEdit.after = content
fileEdit.validation = { valid: true }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The valid property of fileEdit.validation is hardcoded to true. This might not reflect the actual validation status of the file edit. Consider calculating this value based on the actual validation results. 🚧

generated by pr-review-commit hardcoded_value

}
if (oannotations) annotations = oannotations.slice(0)
}
Expand Down
5 changes: 5 additions & 0 deletions packages/core/src/types/prompt_template.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,10 @@ type PromptAssertion = {
)

interface PromptTest {
/**
* Short name of the test
*/
name?: string
/**
* Description of the test.
*/
Expand Down Expand Up @@ -629,6 +633,7 @@ type PromptSystemArgs = Omit<
| "maxTokens"
| "seed"
| "tests"
| "responseLanguage"
| "responseType"
| "responseSchema"
| "files"
Expand Down
Loading