diff --git a/docs/modules.md b/docs/modules.md deleted file mode 100644 index 24086a1..0000000 --- a/docs/modules.md +++ /dev/null @@ -1 +0,0 @@ -MetaPrompt module system is centered around files. diff --git a/docs/syntax.md b/docs/syntax.md index 5e6f049..706fe14 100644 --- a/docs/syntax.md +++ b/docs/syntax.md @@ -10,15 +10,11 @@ will be expanded to the same string, because it does not contain any MetaPrompt # Variables -```metaprompt -Here's a variable: [:variable_name]. +Variables should be referenced using this sintax: `[:variable_name]`. Variable names should match `[a-zA-Z_][a-zA-Z0-9_]*`. -If a variable is used before first assignment, it is treated as a required -prompt parameter automatically. +The syntax for assignments is `[:variable_name=any expression]`. -[:variable_name=it can be reassigned to any value, however] -[:variable_name=Including a value containing its old value: [:variable_name]] -``` +Optional assignments use `?=` instead of `=` - they update the value only if a variable is unset. # Comments @@ -96,16 +92,32 @@ Normally, you would not need escaping, e.g. `[:foo` will evaluate to `[:foo` as # Modules -Every `.metaprompt` file is a function. +Every `.metaprompt` file is a module. Conceptually, a module is a function that accepts a number of arguments, runs the executable parts, and returns text. + +## Passing parameters + +Unbound variables used in a module are its parameters, that must be provided when calling the module. -Unbound variables used in a file are its parameters, that must be provided. +**Example** + +Consider a file named [`hello.metaprompt`](../examples/hello.metaprompt): ```metaprompt -Hello, [:what]! [# `what` is a parameter ] -[:who=you] [# `who` is NOT a parameter, because it is assigned before first use] +Hello, [:what]! [# `what` is a required parameter ] +[:who?=you] +[# ^ `who` is NOT a required parameter, because it is assigned + before first use. However, optional assignment is used, so + the default value can be overridden from the caller module +] How are [:who] feeling today? ``` +The `hello` module can be used like this from [another module](../examples/module-demo.metaprompt): + +``` +[:use ./hello :what=world :who=we] +``` + ## File imports The following expression will include `./relative-import.metaprompt` file (relative to the directory of the file, NOT to the current working dir): @@ -118,16 +130,6 @@ The following expression will include `./relative-import.metaprompt` file (relat **NOT IMPLEMENTED** -## Passing parameters - -``` -[:use ./relative-import - :someParameter= arbitrary value, potentially using - any other MetaPrompt constructs - :otherParameter= another value -] -``` - ## Special variables - `MODEL` - used to determine active LLM id. diff --git a/examples/hello.metaprompt b/examples/hello.metaprompt new file mode 100644 index 0000000..346b625 --- /dev/null +++ b/examples/hello.metaprompt @@ -0,0 +1,7 @@ +Hello, [:what]! [# `what` is a required parameter ] +[:who?=you] +[# ^ `who` is NOT a required parameter, because it is assigned + before first use. However, optional assignment is used, so + the default value can be overridden from the caller module +] +How are [:who] feeling today? diff --git a/examples/module-demo.metaprompt b/examples/module-demo.metaprompt new file mode 100644 index 0000000..d2339f5 --- /dev/null +++ b/examples/module-demo.metaprompt @@ -0,0 +1 @@ +[:use ./hello :what=world :who=we] diff --git a/python/src/eval.py b/python/src/eval.py index 5329953..6adfbae 100644 --- a/python/src/eval.py +++ b/python/src/eval.py @@ -73,6 +73,8 @@ async def _eval_ast(ast): yield chunk elif ast["type"] == "text": yield ast["text"] + elif ast["type"] == "comment": + return elif ast["type"] == "metaprompt": async for chunk in _eval_exprs(ast["exprs"]): yield chunk diff --git a/python/src/loader.py b/python/src/loader.py index 570ab41..59d42bc 100644 --- a/python/src/loader.py +++ b/python/src/loader.py @@ -104,6 +104,8 @@ def extract_parameter_set(ast): elif ast["type"] == "exprs": for expr in ast["exprs"]: extract_parameter_set(expr, assigned) + elif ast["type"] == "comment": + pass elif ast["type"] == "if_then_else": res = res.then(extract_parameter_set(ast["condition"])).then( extract_parameter_set(ast["then"]).alternative(