Skip to content

Commit 0e4502c

Browse files
Use filekeys for cross-referencing
1 parent 0df4f56 commit 0e4502c

32 files changed

Lines changed: 201 additions & 111 deletions

README.md

Lines changed: 68 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ Example:
149149

150150
```yaml
151151
# personalities define the system prompt level directives for this Agent
152+
seclab-taskflow-agent:
153+
version: 1
154+
filetype: personality
155+
filekey: personalities/examples/echo
156+
152157
personality: |
153158
You are a simple echo bot. You use echo tools to echo things.
154159
@@ -157,7 +162,7 @@ task: |
157162
158163
# personality toolboxes map to mcp servers made available to this Agent
159164
toolboxes:
160-
- echo
165+
- toolboxes/echo
161166
```
162167
163168
## Toolboxes
@@ -168,6 +173,11 @@ Example stdio config:
168173

169174
```yaml
170175
# stdio mcp server configuration
176+
seclab-taskflow-agent:
177+
version: 1
178+
filetype: toolbox
179+
filekey: toolboxes/echo
180+
171181
server_params:
172182
kind: stdio
173183
command: python
@@ -184,6 +194,11 @@ A sequence of interdependent tasks performed by a set of Agents. Configured thro
184194
Example:
185195

186196
```yaml
197+
seclab-taskflow-agent:
198+
version: 1
199+
filetype: taskflow
200+
filekey: taskflows/examples/example.yaml
201+
187202
taskflow:
188203
- task:
189204
# taskflows can optionally choose any of the support CAPI models for a task
@@ -194,18 +209,14 @@ taskflow:
194209
must_complete: true
195210
# taskflows can set a primary (first entry) and handoff (additional entries) agent
196211
agents:
197-
- c_auditer
198-
- fruit_expert
212+
- personalities/c_auditer.yaml
213+
- personalities/examples/fruit_expert.yaml
199214
user_prompt: |
200215
Store an example vulnerable C program that uses `strcpy` in the
201216
`vulnerable_c_example` memory key and explain why `strcpy`
202217
is insecure in the C programming language. Do this before handing off
203218
to any other agent.
204219

205-
Then provide a summary of a high impact CVE ID that involved a `strcpy`
206-
based buffer overflow based on your GHSA knowledge as an additional
207-
example.
208-
209220
Finally, why are apples and oranges healthy to eat?
210221

211222
# taskflows can set temporary environment variables, these support the general
@@ -217,16 +228,16 @@ taskflow:
217228
MEMCACHE_STATE_DIR: "example_taskflow/"
218229
MEMCACHE_BACKEND: "dictionary_file"
219230
# taskflows can optionally override personality toolboxes, in this example
220-
# kevin normally only has the memcache toolbox, but we extend it here with
231+
# this normally only has the memcache toolbox, but we extend it here with
221232
# the GHSA toolbox
222233
toolboxes:
223-
- ghsa
224-
- memcache
234+
- toolboxes/memcache.yaml
235+
- toolboxes/codeql.yaml
225236
- task:
226237
must_complete: true
227238
model: gpt-4.1
228239
agents:
229-
- c_auditer
240+
- personalities/c_auditer.yaml
230241
user_prompt: |
231242
Retrieve C code for security review from the `vulnerable_c_example`
232243
memory key and perform a review.
@@ -236,13 +247,58 @@ taskflow:
236247
MEMCACHE_STATE_DIR: "example_taskflow/"
237248
MEMCACHE_BACKEND: "dictionary_file"
238249
toolboxes:
239-
- memcache
250+
- toolboxes/memcache.yaml
251+
# headless mode does not prompt for tool call confirms configured for a server
252+
# note: this will auto-allow, if you want control over potentially dangerous
253+
# tool calls, then you should NOT run a task in headless mode (default: false)
254+
headless: true
255+
- task:
256+
# tasks can also run shell scripts that return e.g. json output for repeat prompt iterable
257+
must_complete: true
258+
run: |
259+
echo '["apple", "banana", "orange"]'
260+
- task:
261+
repeat_prompt: true
262+
agents:
263+
- personalities/assistant.yaml
264+
user_prompt: |
265+
What kind of fruit is {{ RESULT }}?
240266
```
241267
242268
Taskflows support [Agent handoffs](https://openai.github.io/openai-agents-python/handoffs/). Handoffs are useful for implementing triage patterns where the primary Agent can decide to handoff a task to any subsequent Agents in the `Agents` list.
243269

244270
See the [taskflow examples](taskflows/examples) for other useful Taskflow patterns such as repeatable and asynchronous templated prompts.
245271

272+
## Notes about the yaml syntax
273+
274+
Every personality, toolbox, and taskflow is defined by a YAML file, which
275+
should always include a header like this:
276+
277+
```
278+
seclab-taskflow-agent:
279+
version: 1
280+
filetype: taskflow
281+
filekey: taskflows/examples/example
282+
```
283+
284+
The "filetype" determines whether the file defines a personality, toolbox, or
285+
taskflow. This means that different types of files can be stored in the same directory.
286+
287+
The "filekey" is a unique name for the file. It is used to allow
288+
cross-referencing between files. For example, a taskflow can reference
289+
a personality by its filekey. Because filekeys are used for
290+
cross-referencing (rather than file paths), it means that you can move
291+
a file to a different directory without breaking the links. This also
292+
means that you can easily import new files by dropping them into a sub-directory.
293+
We recommend including something like your
294+
GitHub "username/reponame" in your filekeys to make them globably unique.
295+
296+
The "version" number in the header should always be 1. It means that the
297+
file uses version 1 of the seclab-taskflow-agent syntax. If we ever need
298+
to make a major change to the syntax, then we'll update the version number.
299+
This will hopefully enable us to make changes without breaking backwards
300+
compatibility.
301+
246302
## License
247303

248304
This project is licensed under the terms of the MIT open source license. Please refer to the [LICENSE](./LICENSE) file for the full terms.

available_tools.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,18 @@
33
class VersionException(Exception):
44
pass
55

6+
class FileIDException(Exception):
7+
pass
8+
69
class FileTypeException(Exception):
710
pass
811

12+
def add_yaml_to_dict(table, key, yaml):
13+
"""Add the yaml to the table, but raise an error if the id isn't unique """
14+
if key in table:
15+
raise FileIDException(str(key))
16+
table.update({key: yaml})
17+
918
class AvailableTools:
1019
"""
1120
This class is used for storing dictionaries of all the available
@@ -30,20 +39,23 @@ def __init__(self, yamls: dict):
3039
version = header['version']
3140
if version != 1:
3241
raise VersionException(str(version))
33-
filetype = header['type']
42+
filekey = header['filekey']
43+
filetype = header['filetype']
3444
if filetype == 'personality':
35-
self.personalities.update({path: yaml})
45+
add_yaml_to_dict(self.personalities, filekey, yaml)
3646
elif filetype == 'taskflow':
37-
self.taskflows.update({path: yaml})
47+
add_yaml_to_dict(self.taskflows, filekey, yaml)
3848
elif filetype == 'prompt':
39-
self.prompts.update({path: yaml})
49+
add_yaml_to_dict(self.prompts, filekey, yaml)
4050
elif filetype == 'toolbox':
41-
self.toolboxes.update({path: yaml})
51+
add_yaml_to_dict(self.toolboxes, filekey, yaml)
4252
else:
4353
raise FileTypeException(str(filetype))
4454
except KeyError as err:
4555
logging.error(f'{path} does not contain the key {err.args[0]}')
4656
except VersionException as err:
4757
logging.error(f'{path}: seclab-taskflow-agent version {err.args[0]} is not supported')
58+
except FileIDException as err:
59+
logging.error(f'{path}: file ID {err.args[0]} is not unique')
4860
except FileTypeException as err:
4961
logging.error(f'{path}: seclab-taskflow-agent file type {err.args[0]} is not supported')

main.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import re
1111
import json
1212
import uuid
13+
import pathlib
1314

1415
from agent import DEFAULT_MODEL, TaskRunHooks, TaskAgentHooks
1516
#from agents.run import DEFAULT_MAX_TURNS # XXX: this is 10, we need more than that
@@ -628,11 +629,12 @@ async def _deploy_task_agents(resolved_agents, prompt):
628629
break
629630

630631
if __name__ == '__main__':
632+
cwd = pathlib.Path.cwd()
631633
available_tools = AvailableTools(
632-
YamlParser('personalities').get_yaml_dict() |
633-
YamlParser('taskflows').get_yaml_dict() |
634-
YamlParser('prompts').get_yaml_dict(dir_namespace=True) |
635-
YamlParser('toolboxes').get_yaml_dict(recurse=True))
634+
YamlParser(cwd).get_yaml_dict((cwd/'personalities').rglob('*')) |
635+
YamlParser(cwd).get_yaml_dict((cwd/'taskflows').rglob('*')) |
636+
YamlParser(cwd).get_yaml_dict((cwd/'prompts').rglob('*')) |
637+
YamlParser(cwd).get_yaml_dict((cwd/'toolboxes').rglob('*')))
636638

637639
p, t, l, user_prompt, help_msg = parse_prompt_args(available_tools)
638640

mcp_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ class MCPNamespaceWrap:
221221
def __init__(self, confirms, obj):
222222
self.confirms = confirms
223223
self._obj = obj
224-
self.namespace = f"{obj.name.upper().replace(' ', '_')}_"
224+
self.namespace = f"{obj.name.upper().replace(' ', '_').replace('/','-')}_"
225225

226226
def __getattr__(self, name):
227227
attr = getattr(self._obj, name)

personalities/assistant.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
seclab-taskflow-agent:
2-
type: personality
32
version: 1
3+
filetype: personality
4+
filekey: personalities/assistant.yaml
45

56
personality: |
67
You are a helpful assistant.

personalities/c_auditer.yaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
seclab-taskflow-agent:
2-
type: personality
32
version: 1
3+
filetype: personality
4+
filekey: personalities/c_auditer.yaml
45

56
personality: |
67
Your name is Ronald. You are a C programming language security expert.
@@ -14,5 +15,5 @@ task: |
1415
your findings where possible.
1516
1617
toolboxes:
17-
- memcache
18-
- codeql
18+
- toolboxes/memcache.yaml
19+
- toolboxes/codeql.yaml

personalities/examples/apple_expert.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
seclab-taskflow-agent:
2-
type: personality
32
version: 1
3+
filetype: personality
4+
filekey: personalities/examples/apple_expert.yaml
45

56
personality: |
67
You are an apples expert.

personalities/examples/banana_expert.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
seclab-taskflow-agent:
2-
type: personality
32
version: 1
3+
filetype: personality
4+
filekey: personalities/examples/banana_expert.yaml
45

56
personality: |
67
You are a bananas expert.

personalities/examples/echo.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
seclab-taskflow-agent:
2-
type: personality
32
version: 1
3+
filetype: personality
4+
filekey: personalities/examples/echo.yaml
45

56
personality: |
67
You are a simple echo bot. You use echo tools to echo things.
@@ -9,5 +10,5 @@ task: |
910
Echo user inputs using the echo tools.
1011
1112
toolboxes:
12-
- echo
13+
- toolboxes/echo.yaml
1314

personalities/examples/example_triage_agent.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
seclab-taskflow-agent:
2-
type: personality
32
version: 1
3+
filetype: personality
4+
filekey: personalities/examples/example_triage_agent.yaml
45

56
personality: |
67
You are a triage agent. You route tasks to other agents.

0 commit comments

Comments
 (0)