Skip to content

Commit 96885c1

Browse files
Merge pull request #125 from anticomputer/anticomputer/jinja-templating
Migrate template system to Jinja2
2 parents 211f98e + 002885e commit 96885c1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1354
-152
lines changed

README.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -174,15 +174,15 @@ Every YAML files used by the Seclab Taskflow Agent must include a header like th
174174

175175
```yaml
176176
seclab-taskflow-agent:
177-
version: 1
177+
version: "1.0"
178178
filetype: taskflow
179179
```
180180
181-
The `version` number in the header should always be 1. It means that the
181+
The `version` number in the header is currently 1. It means that the
182182
file uses version 1 of the seclab-taskflow-agent syntax. If we ever need
183183
to make a major change to the syntax, then we'll update the version number.
184184
This will hopefully enable us to make changes without breaking backwards
185-
compatibility.
185+
compatibility. Version can be specified as an integer, float, or string.
186186

187187
The `filetype` determines whether the file defines a personality, toolbox, etc.
188188
This means that different types of files can be stored in the same directory.
@@ -294,10 +294,10 @@ server_params:
294294
url: https://api.githubcopilot.com/mcp/
295295
#See https://github.com/github/github-mcp-server/blob/main/docs/remote-server.md
296296
headers:
297-
Authorization: "{{ env GITHUB_AUTH_HEADER }}"
297+
Authorization: "{{ env('GITHUB_AUTH_HEADER') }}"
298298
optional_headers:
299-
X-MCP-Toolsets: "{{ env GITHUB_MCP_TOOLSETS }}"
300-
X-MCP-Readonly: "{{ env GITHUB_MCP_READONLY }}"
299+
X-MCP-Toolsets: "{{ env('GITHUB_MCP_TOOLSETS') }}"
300+
X-MCP-Readonly: "{{ env('GITHUB_MCP_READONLY') }}"
301301
```
302302

303303
You can force certain tools within a `toolbox` to require user confirmation to run. This can be helpful if a tool may perform irreversible actions and should require user approval prior to its use. This is done by including the name of the tool (function) in the MCP server in the `confirm` section:
@@ -345,7 +345,7 @@ taskflow:
345345
Finally, why are apples and oranges healthy to eat?
346346

347347
# taskflows can set temporary environment variables, these support the general
348-
# "{{ env FROM_EXISTING_ENVIRONMENT }" pattern we use elsewhere as well
348+
# "{{ env('FROM_EXISTING_ENVIRONMENT') }}" pattern we use elsewhere as well
349349
# these environment variables can then be made available to any stdio mcp server
350350
# through its respective yaml configuration, see memcache.yaml for an example
351351
# you can use these to override top-level environment variables on a per-task basis
@@ -492,12 +492,12 @@ Files of types `taskflow` and `toolbox` allow environment variables to be passed
492492
server_params:
493493
...
494494
env:
495-
CODEQL_DBS_BASE_PATH: "{{ env CODEQL_DBS_BASE_PATH }}"
495+
CODEQL_DBS_BASE_PATH: "{{ env('CODEQL_DBS_BASE_PATH') }}"
496496
# prevent git repo operations on gh codeql executions
497497
GH_NO_UPDATE_NOTIFIER: "disable"
498498
```
499499

500-
For `toolbox`, `env` can be used inside `server_params`. A template of the form `{{ env ENV_VARIABLE_NAME }}` can be used to pass values of the environment variable from the current process to the MCP server. So in the above, the MCP server is run with `GH_NO_UPDATE_NOTIFIER=disable` and passes the value of `CODEQL_DBS_BASE_PATH` from the current process to the MCP server. The templated paramater `{{ env CODEQL_DBS_BASE_PATH }}` is replaced by the value of the environment variable `CODEQL_DBS_BASE_PATH` in the current process.
500+
For `toolbox`, `env` can be used inside `server_params`. A template of the form `{{ env('ENV_VARIABLE_NAME') }}` can be used to pass values of the environment variable from the current process to the MCP server. So in the above, the MCP server is run with `GH_NO_UPDATE_NOTIFIER=disable` and passes the value of `CODEQL_DBS_BASE_PATH` from the current process to the MCP server. The templated parameter `{{ env('CODEQL_DBS_BASE_PATH') }}` is replaced by the value of the environment variable `CODEQL_DBS_BASE_PATH` in the current process.
501501

502502
Similarly, environment variables can be passed to a `task` in a `taskflow`:
503503

@@ -514,9 +514,9 @@ taskflow:
514514
MEMCACHE_BACKEND: "dictionary_file"
515515
```
516516
517-
This overwrites the environment variables `MEMCACHE_STATE_DIR` and `MEMCACHE_BACKEND` for the task only. A template `{{ env ENV_VARIABLE_NAME }}` can also be used.
517+
This overwrites the environment variables `MEMCACHE_STATE_DIR` and `MEMCACHE_BACKEND` for the task only. A template `{{ env('ENV_VARIABLE_NAME') }}` can also be used.
518518

519-
Note that when using the template `{{ env ENV_VARIABLE_NAME }}`, `ENV_VARIABLE_NAME` must be the name of an environment variable in the current process.
519+
Note that when using the template `{{ env('ENV_VARIABLE_NAME') }}`, `ENV_VARIABLE_NAME` must be the name of an environment variable in the current process.
520520

521521
## Import paths
522522

doc/GRAMMAR.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -133,10 +133,10 @@ Often we may want to iterate through the same tasks with different inputs. For e
133133
agents:
134134
- seclab_taskflow_agent.personalities.c_auditer
135135
user_prompt: |
136-
The function has name {{ RESULT_name }} and body {{ RESULT_body }} analyze the function.
136+
The function has name {{ result.name }} and body {{ result.body }} analyze the function.
137137
```
138138

139-
In the above, the first task fetches functions in the code base and creates a json list object, with each entry having a `name` and `body` field. In the next task, `repeat_prompt` is set to true, meaning that a task is created for each individual object in the list and the object fields are referenced in the templated prompt using `{{ RESULT_<fieldname> }}`. In other words, `{{ RESULT_name }}` in the prompt is replaced with the value of the `name` field of the object etc. For example, if the list of functions fetched from the first task is:
139+
In the above, the first task fetches functions in the code base and creates a json list object, with each entry having a `name` and `body` field. In the next task, `repeat_prompt` is set to true, meaning that a task is created for each individual object in the list and the object fields are referenced in the templated prompt using `{{ result.fieldname }}`. In other words, `{{ result.name }}` in the prompt is replaced with the value of the `name` field of the object etc. For example, if the list of functions fetched from the first task is:
140140

141141
```javascript
142142
[{'name' : foo, 'body' : foo(){return 1;}}, {'name' : bar, 'body' : bar(a) {return a + 1;}}]
@@ -152,7 +152,7 @@ etc.
152152

153153
Note that when using `repeat_prompt`, the last tool call result of the previous task is used as the iterable. It is recommended to keep the task that creates the iterable short and simple (e.g. just make one tool call to fetch a list of results) to avoid wrong results being passed to the repeat prompt.
154154

155-
The iterable can also contain a list of primitives like string or number, in which case, the template `{{ RESULT }}` can be used in the `repeat_prompt` prompt to parse the results instead:
155+
The iterable can also contain a list of primitives like string or number, in which case, the template `{{ result }}` can be used in the `repeat_prompt` prompt to parse the results instead:
156156

157157
```yaml
158158
- task:
@@ -173,7 +173,7 @@ The iterable can also contain a list of primitives like string or number, in whi
173173
agents:
174174
- seclab_taskflow_agent.personalities.assistant
175175
user_prompt: |
176-
What is the integer value of {{ RESULT }}?
176+
What is the integer value of {{ result }}?
177177
```
178178
179179
Repeat prompt can be run in parallel by setting the `async` field to `true`:
@@ -185,7 +185,7 @@ Repeat prompt can be run in parallel by setting the `async` field to `true`:
185185
agents:
186186
- seclab_taskflow_agent.personalities.c_auditer
187187
user_prompt: |
188-
The function has name {{ RESULT_name }} and body {{ RESULT_body }} analyze the function.
188+
The function has name {{ result.name }} and body {{ result.body }} analyze the function.
189189
```
190190

191191
An optional limit can be set to limit the number of asynchronous tasks via `async_limit`. If not set, the default value (5) is used.
@@ -198,7 +198,7 @@ An optional limit can be set to limit the number of asynchronous tasks via `asyn
198198
agents:
199199
- seclab_taskflow_agent.personalities.c_auditer
200200
user_prompt: |
201-
The function has name {{ RESULT_name }} and body {{ RESULT_body }} analyze the function.
201+
The function has name {{ result.name }} and body {{ result.body }} analyze the function.
202202
```
203203

204204
Both `async` and `async_limit` have no effect when used outside of a `repeat_prompt`.
@@ -211,7 +211,7 @@ At the moment, we do not support nested `repeat_prompt`. So the following is not
211211
agents:
212212
- seclab_taskflow_agent.personalities.c_auditer
213213
user_prompt: |
214-
The function has name {{ RESULT_name }} and body {{ RESULT_body }} analyze the function.
214+
The function has name {{ result.name }} and body {{ result.body }} analyze the function.
215215
- task:
216216
repeat_prompt: true
217217
...
@@ -233,7 +233,7 @@ For example:
233233
agents:
234234
- seclab_taskflow_agent.personalities.assistant
235235
user_prompt: |
236-
What kind of fruit is {{ RESULT }}?
236+
What kind of fruit is {{ result }}?
237237
```
238238

239239
The string `["apple", "banana", "orange"]` is then passed directly to the next task.
@@ -349,7 +349,7 @@ taskflow:
349349
agents:
350350
- examples.personalities.fruit_expert
351351
user_prompt: |
352-
Tell me more about {{ GLOBALS_fruit }}.
352+
Tell me more about {{ globals.fruit }}.
353353
```
354354
355355
Global variables can also be set or overridden from the command line using the `-g` or `--global` flag:
@@ -422,10 +422,10 @@ A reusable taskflow can also have a templated prompt that takes inputs from its
422422
agents:
423423
- examples.personalities.fruit_expert
424424
user_prompt: |
425-
Tell me more about {{ INPUTS_fruit }}.
425+
Tell me more about {{ inputs.fruit }}.
426426
```
427427

428-
In this case, the template parameter `{{ INPUTS_fruit }}` is replaced by the value of `fruit` from the `inputs` of the user, which is apples in this case:
428+
In this case, the template parameter `{{ inputs.fruit }}` is replaced by the value of `fruit` from the `inputs` of the user, which is apples in this case:
429429

430430
```yaml
431431
- task:
@@ -437,9 +437,9 @@ In this case, the template parameter `{{ INPUTS_fruit }}` is replaced by the val
437437

438438
### Reusable Prompts
439439

440-
Reusable prompts are defined in files of `filetype` `prompts`. These are like macros that get replaced when a templated parameter of the form `{{ PROMPTS_<import-path> }}` is encountered.
440+
Reusable prompts are defined in files of `filetype` `prompts`. These are like macros that get included using Jinja2's `{% include %}` directive.
441441

442-
Tasks can incorporate templated prompts which are then replaced by the actual prompt. For example:
442+
Tasks can incorporate reusable prompts using the include directive. For example:
443443

444444
Example:
445445

@@ -449,8 +449,8 @@ Example:
449449
- examples.personalities.fruit_expert
450450
user_prompt: |
451451
Tell me more about apples.
452-
453-
{{ PROMPTS_examples.prompts.example_prompt }}
452+
453+
{% include 'examples.prompts.example_prompt' %}
454454
```
455455
and `examples.prompts.example_prompt` is the following:
456456

0 commit comments

Comments
 (0)