diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c36a28d..1fbe21aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,10 +11,11 @@ permissions: jobs: test: - name: Run Tests - runs-on: ubuntu-latest + name: Run Tests ${{ matrix.python-version }} on ${{ matrix.os }} + runs-on: ${{ matrix.os }} strategy: matrix: + os: [ubuntu-latest, windows-latest, macos-latest] python-version: ['3.11', '3.13'] # the one we have in the Codespace + the latest supported one by PyO3. fail-fast: false # Continue testing other version(s) if one fails @@ -28,17 +29,14 @@ jobs: python-version: ${{ matrix.python-version }} cache: 'pip' - - name: Install dependencies - run: | - python -m venv .venv - source .venv/bin/activate - python -m pip install --upgrade pip - python -m pip install -r requirements.txt - python -m pip install -r requirements-test.txt - - name: Run tests with pytest + - name: Install Hatch + run: pip install --upgrade hatch + + - name: Run static analysis run: | - source .venv/bin/activate - pytest tests/ -v - env: - PYTHONPATH: ${{ github.workspace }} + # hatch fmt --check + echo linter errors will be fixed in a separate PR + + - name: Run tests + run: hatch test --python ${{ matrix.python-version }} --cover --randomize --parallel --retries 2 --retry-delay 1 diff --git a/.github/workflows/smoketest.yaml b/.github/workflows/smoketest.yaml index 4b2779dc..967548e0 100644 --- a/.github/workflows/smoketest.yaml +++ b/.github/workflows/smoketest.yaml @@ -40,7 +40,7 @@ jobs: run: | python -m venv .venv source .venv/bin/activate - python -m pip install -r requirements.txt + python -m pip install hatch - name: Run tests env: @@ -49,19 +49,20 @@ jobs: run: | source .venv/bin/activate - python main.py -p personalities.assistant 'explain modems to me please' - python main.py -p personalities.c_auditer 'explain modems to me please' - python main.py -p personalities.examples.echo 'explain modems to me please' - python main.py -t taskflows.CVE-2023-2283.CVE-2023-2283 - python main.py -t taskflows.examples.echo - python main.py -t taskflows.examples.example - python main.py -t taskflows.examples.example_globals - python main.py -t taskflows.examples.example_inputs - python main.py -t taskflows.examples.example_large_list_result_iter - python main.py -t taskflows.examples.example_repeat_prompt - python main.py -t taskflows.examples.example_repeat_prompt_async - python main.py -t taskflows.examples.example_repeat_prompt_dictionary - python main.py -t taskflows.examples.example_reusable_prompt - python main.py -t taskflows.examples.example_reusable_taskflows - python main.py -t taskflows.examples.example_triage_taskflow - python main.py -t taskflows.examples.single_step_taskflow + hatch build + hatch run main -p seclab_taskflow_agent.personalities.assistant 'explain modems to me please' + hatch run main -p seclab_taskflow_agent.personalities.c_auditer 'explain modems to me please' + hatch run main -p examples.personalities.echo 'explain modems to me please' + hatch run main -t examples.taskflows.CVE-2023-2283 + hatch run main -t examples.taskflows.echo + hatch run main -t examples.taskflows.example + hatch run main -t examples.taskflows.example_globals + hatch run main -t examples.taskflows.example_inputs + hatch run main -t examples.taskflows.example_large_list_result_iter + hatch run main -t examples.taskflows.example_repeat_prompt + hatch run main -t examples.taskflows.example_repeat_prompt_async + hatch run main -t examples.taskflows.example_repeat_prompt_dictionary + hatch run main -t examples.taskflows.example_reusable_prompt + hatch run main -t examples.taskflows.example_reusable_taskflows + hatch run main -t examples.taskflows.example_triage_taskflow + hatch run main -t examples.taskflows.single_step_taskflow diff --git a/README.md b/README.md index d48bdeed..0295185d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The Security Lab Taskflow Agent is an MCP enabled multi-Agent framework. The Taskflow Agent is built on top of the [OpenAI Agents SDK](https://openai.github.io/openai-agents-python/). -While the Taskflow Agent does not integrate into the GitHub Doctom Copilot UX, it does operate using the Copilot API (CAPI) as its backend, similar to Copilot IDE extensions. +While the Taskflow Agent does not integrate into the GitHub Dotcom Copilot UX, it does operate using the Copilot API (CAPI) as its backend, similar to Copilot IDE extensions. ## Core Concepts @@ -12,11 +12,11 @@ The Taskflow Agent leverages a GitHub Workflow-esque YAML based grammar to perfo Its primary value proposition is as a CLI tool that allows users to quickly define and script Agentic workflows without having to write any code. -Agents are defined through [personalities](personalities/), that receive a [task](taskflows/) to complete given a set of [tools](toolboxes/). +Agents are defined through [personalities](examples/personalities/), that receive a [task](examples/taskflows/) to complete, given a set of [tools](src/seclab_taskflow_agent/toolboxes/). -Agents can cooperate to complete sequences of tasks through so-called [taskflows](taskflows/GRAMMAR.md). +Agents can cooperate to complete sequences of tasks through so-called [taskflows](doc/GRAMMAR.md). -You can find a detailed overview of the taskflow grammar [here](https://github.com/GitHubSecurityLab/seclab-taskflow-agent/blob/main/taskflows/GRAMMAR.md) and example taskflows [here](https://github.com/GitHubSecurityLab/seclab-taskflow-agent/tree/main/taskflows/examples). +You can find a detailed overview of the taskflow grammar [here](taskflows/GRAMMAR.md) and example taskflows [here](examples/taskflows/). ## Use Cases and Examples @@ -26,7 +26,7 @@ Its design philosophy is centered around the belief that a prompt level focus of While the maintainer himself primarily uses this framework as a code auditing tool it also serves as a more generic swiss army knife for exploring Agentic workflows. For example, the GitHub Security Lab also uses this framework for automated code scanning alert triage. -The framework includes a [CodeQL](https://codeql.github.com/) MCP server that can be used for Agentic code review, see the [CVE-2023-2283](https://github.com/GitHubSecurityLab/seclab-taskflow-agent/blob/main/taskflows/CVE-2023-2283/CVE-2023-2283.yaml) for an example of how to have an Agent review C code using a CodeQL database ([demo video](https://www.youtube.com/watch?v=eRSPSVW8RMo)). +The framework includes a [CodeQL](https://codeql.github.com/) MCP server that can be used for Agentic code review, see the [CVE-2023-2283](examples/taskflows/CVE-2023-2283/CVE-2023-2283.yaml) taskflow for an example of how to have an Agent review C code using a CodeQL database ([demo video](https://www.youtube.com/watch?v=eRSPSVW8RMo)). Instead of generating CodeQL queries itself, the CodeQL MCP Server is used to provide CodeQL-query based MCP tools that allow an Agent to navigate and explore code. It leverages templated CodeQL queries to provide targeted context for model driven code analysis. @@ -52,26 +52,32 @@ CODEQL_DBS_BASE_PATH="/app/my_data/codeql_databases" ## Deploying from Source -First install the required dependencies: +We use [hatch](https://hatch.pypa.io/) to build the project. Download and build like this: -```sh +```bash +git clone https://github.com/GitHubSecurityLab/seclab-taskflow-agent.git +cd seclab-taskflow-agent python -m venv .venv source .venv/bin/activate +pip install hatch +hatch build +``` + python -m pip install -r requirements.txt ``` -Then run `python main.py`. +Then run `hatch run main`. Example: deploying a prompt to an Agent Personality: ```sh -python main.py -p assistant 'explain modems to me please' +hatch run main -p seclab_taskflow_agent.personalities.assistant 'explain modems to me please' ``` Example: deploying a Taskflow: ```sh -python main.py -t example +hatch run main -t examples.taskflows.example ``` ## Deploying from Docker @@ -80,7 +86,7 @@ You can deploy the Taskflow Agent via its Docker image using `docker/run.sh`. WARNING: the Agent Docker image is _NOT_ intended as a security boundary but strictly a deployment convenience. -The image entrypoint is `main.py` and thus it operates the same as invoking the Agent from source directly. +The image entrypoint is `__main__.py` and thus it operates the same as invoking the Agent from source directly. You can find the Docker image for the Seclab Taskflow Agent [here](https://github.com/GitHubSecurityLab/seclab-taskflow-agent/pkgs/container/seclab-taskflow-agent) and how it is built [here](release_tools/). @@ -188,21 +194,20 @@ task: | # personality toolboxes map to mcp servers made available to this Agent toolboxes: - - toolboxes.echo + - seclab_taskflow_agent.toolboxes.echo ``` In the above, the `personality` and `task` field specifies the system prompt to be used whenever this `personality` is used. -The `toolboxes` are the tools that are available to this `personality`. The `toolboxes` should be a list of `filekey` specifying -files of the `filetype` `toolbox`. +The `toolboxes` are the tools that are available to this `personality`. The `toolboxes` should be a list of files of the `filetype` `toolbox`. (See the [Import paths](#import-paths) section for how to reference other files.) Personalities can be used in two ways. First it can be used standalone with a prompt input from the command line: ``` -python3 main.py -p personalities.examples.echo "echo this message" +hatch run main -p examples.personalities.echo 'echo this message' ``` -In this case, `personality` and `task` from `GitHubSecurityLab/seclab-taskflow-agent/personalities/examples/echo` are used as the -system prompt while the user argument `echo this message` is used as a user prompt. In this use case, the only tools that this +In this case, `personality` and `task` from [`examples/personalities/echo.yaml`](examples/personalities/echo.yaml) are used as the +system prompt while the user argument `echo this message` is used as a user prompt. In this use case, the only tools that this personality has access to is the `toolboxes` specified in the file. Personalities can also be used in a `taskflow` to perform tasks. This is done by adding the `personality` to the `agents` field in a `taskflow` file: @@ -214,34 +219,33 @@ taskflow: agents: - personalities.assistant user_prompt: | - Fetch all the open pull requests from `github/codeql` github repository. + Fetch all the open pull requests from `github/codeql` github repository. You do not need to provide a summary of the results. toolboxes: - - toolboxes.github_official + - seclab_taskflow_agent.toolboxes.github_official ``` -In this case, the `personality` specified in `agents` provides the system prompt and the user prompt is specified in `user_prompt` field of the task. A big difference in this case is that the `toolboxes` specified in the `task` will overwrite the `toolboxes` that the `personality` has access to. So in the above example, the `personalities.assistant` will have access to the `toolboxes.github_official` toolbox instead of its own toolbox. It is important to note that the `personalities` toolboxes get *overwritten* in this case, so whenever a `toolboxes` field is provided in a `task`, it'll use the provided toolboxes and `personality` loses access to its own toolboxes. e.g. +In this case, the `personality` specified in `agents` provides the system prompt and the user prompt is specified in the `user_prompt` field of the task. A big difference in this case is that the `toolboxes` specified in the `task` will overwrite the `toolboxes` that the `personality` has access to. So in the above example, the `personalities.assistant` will have access to the `seclab_taskflow_agent.toolboxes.github_official` toolbox instead of its own toolbox. It is important to note that the `personalities` toolboxes get *overwritten* in this case, so whenever a `toolboxes` field is provided in a `task`, it'll use the provided toolboxes and `personality` loses access to its own toolboxes. e.g. ```yaml taskflow: - task: ... agents: - - personalities.examples.echo + - examples.personalities.echo user_prompt: | echo this toolboxes: - - toolboxes.github_official + - seclab_taskflow_agent.toolboxes.github_official ``` -In the above `task`, `personalities.examples.echo` will only have access to the `toolboxes.github_official` and can no longer access the `toolboxes.echo` `toolbox`. (Unless it is added also in the `task` `toolboxes`) +In the above `task`, `personalities.examples.echo` will only have access to the `toolboxes.github_official` and can no longer access the `seclab_taskflow_agent.toolboxes.echo` `toolbox` (unless it is added also in the `task` `toolboxes`). ## Toolboxes -MCP servers that provide tools. Configured through YAML files of `filetype` `toolboxes`. These are files that provide -the type and parameters to start an MCP server. +MCP servers that provide tools. Configured through YAML files of `filetype` `toolbox`. These are files that provide the type and parameters to start an MCP server. -For example, to start a stdio MCP server that are implemented in a python file: +For example, to start a stdio MCP server that is implemented in a python file: ```yaml # stdio mcp server configuration @@ -252,15 +256,14 @@ seclab-taskflow-agent: server_params: kind: stdio command: python - args: - - toolboxes/echo/echo.py + args: ["-m", "seclab_taskflow_agent.mcp_servers.echo.echo"] env: - SOME: value + TEST: value ``` In the above, `command` and `args` are just the command and arguments that should be run to start the MCP server. Environment variables can be passed using the `env` field. -A [streamable](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) is also supported by specifying the `kind` to `streamable`: +A [streamable](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http) is also supported by setting the `kind` to `streamable`: ```yaml server_params: @@ -288,8 +291,8 @@ confirm: ## Taskflows -A sequence of interdependent tasks performed by a set of Agents. Configured through YAML files of `filetype` `taskflow`. -Taskflows supports a number of features, and their details can be found [here](taskflows/GRAMMAR.md). +A sequence of interdependent tasks performed by a set of Agents. Configured through YAML files of `filetype` `taskflow`. +Taskflows supports a number of features, and their details can be found [here](doc/GRAMMAR.md). Example: @@ -308,8 +311,8 @@ taskflow: must_complete: true # taskflows can set a primary (first entry) and handoff (additional entries) agent agents: - - personalities/c_auditer.yaml - - personalities/examples/fruit_expert.yaml + - seclab_taskflow_agent.personalities.c_auditer + - examples.personalities.fruit_expert user_prompt: | Store an example vulnerable C program that uses `strcpy` in the `vulnerable_c_example` memory key and explain why `strcpy` @@ -330,13 +333,13 @@ taskflow: # this normally only has the memcache toolbox, but we extend it here with # the GHSA toolbox toolboxes: - - toolboxes/memcache.yaml - - toolboxes/codeql.yaml + - seclab_taskflow_agent.toolboxes.memcache + - seclab_taskflow_agent.toolboxes.codeql - task: must_complete: true model: gpt-4.1 agents: - - personalities/c_auditer.yaml + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | Retrieve C code for security review from the `vulnerable_c_example` memory key and perform a review. @@ -346,7 +349,7 @@ taskflow: MEMCACHE_STATE_DIR: "example_taskflow/" MEMCACHE_BACKEND: "dictionary_file" toolboxes: - - toolboxes/memcache.yaml + - seclab_taskflow_agent.toolboxes.memcache # headless mode does not prompt for tool call confirms configured for a server # note: this will auto-allow, if you want control over potentially dangerous # tool calls, then you should NOT run a task in headless mode (default: false) @@ -359,7 +362,7 @@ taskflow: - task: repeat_prompt: true agents: - - personalities/assistant.yaml + - seclab_taskflow_agent.personalities.assistant user_prompt: | What kind of fruit is {{ RESULT }}? ``` @@ -372,14 +375,14 @@ See the [taskflow examples](taskflows/examples) for other useful Taskflow patter You can run a taskflow from the command line like this: ``` -python3 main.py -t taskflows.CVE-2023-2283.CVE-2023-2283 +hatch run main -t examples.taskflows.CVE-2023-2283 ``` -## Prompt +## Prompts Prompts are configured through YAML files of `filetype` `prompt`. They define a reusable prompt that can be referenced in `taskflow` files. -They contain only one field, the `prompt` field, which is used to replace any `{{ PROMPT_ }}` template parameter in a taskflow. For example, the following `prompt`. +They contain only one field, the `prompt` field, which is used to replace any `{{ PROMPT_ }}` template parameter in a taskflow. For example, the following `prompt`. ```yaml seclab-taskflow-agent: @@ -390,16 +393,16 @@ prompt: | Tell me more about bananas as well. ``` -would replace any `{{ PROMPT_prompts.examples.example_prompt }}` template parameter found in the `user_prompt` section in a taskflow: +would replace any `{{ PROMPT_examples.prompts.example_prompt }}` template parameter found in the `user_prompt` section in a taskflow: ```yaml - task: agents: - - fruit_expert + - examples.personalities.fruit_expert user_prompt: | Tell me more about apples. - {{ PROMPTS_prompts.examples.example_prompt }} + {{ PROMPTS_examples.prompts.example_prompt }} ``` becomes: @@ -407,7 +410,7 @@ becomes: ```yaml - task: agents: - - fruit_expert + - examples.personalities.fruit_expert user_prompt: | Tell me more about apples. @@ -423,20 +426,20 @@ seclab-taskflow-agent: version: 1 filetype: model_config models: - gpt_latest: gpt-5 + gpt_latest: gpt-5 ``` A `model_config` file can be used in a `taskflow` and the values defined in `models` can then be used throughout. ```yaml -model_config: configs.model_config +model_config: examples.model_configs.model_config taskflow: - task: model: gpt_latest ``` -Model version can then be updated by changing `gpt_latest` in the `model_config` file and applied across all taskflows that use the config. +The model version can then be updated by changing `gpt_latest` in the `model_config` file and applied across all taskflows that use the config. ## Passing environment variables @@ -448,10 +451,10 @@ server_params: env: CODEQL_DBS_BASE_PATH: "{{ env CODEQL_DBS_BASE_PATH }}" # prevent git repo operations on gh codeql executions - GH_NO_UPDATE_NOTIFIER: "Disable" + GH_NO_UPDATE_NOTIFIER: "disable" ``` -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. +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. Similarly, environment variables can be passed to a `task` in a `taskflow`: @@ -460,7 +463,7 @@ taskflow: - task: must_complete: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Store the json array ["apples", "oranges", "bananas"] in the `fruits` memory key. env: @@ -468,10 +471,33 @@ taskflow: MEMCACHE_BACKEND: "dictionary_file" ``` -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. +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. 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. +## Import paths + +YAML files often need to refer to each other. For example, a taskflow can reference a personality like this: + +```yaml +taskflow: + - task: + ... + agents: + - seclab_taskflow_agent.personalities.assistant +``` + +We use Python's import system, so a name like `seclab_taskflow_agent.personalities.assistant` will get resolved to a YAML file using Python's import rules. One of the benefits of this is that it makes it easy to bundle and share taskflows as Python packages on PyPI. + +The implementation works like this: + +1. A name like `seclab_taskflow_agent.personalities.assistant` gets split (at the last `.` character) into a package name (`seclab_taskflow_agent.personalities`) and a file name (`assistant`). +2. Python's [`importlib.resources.files`](https://docs.python.org/3/library/importlib.resources.html#importlib.resources.files) is used to resolve the package name into a directory name. +3. The extension `.yaml` is added to the filename: `assistant.yaml`. +4. The yaml file is loaded from the directory that was returned by `importlib.resources.files`. + +The exact code that implements this can be found in [`available_tools.py`](src/seclab_taskflow_agent/available_tools.py). + ## License This project is licensed under the terms of the [MIT](https://spdx.org/licenses/MIT.html) license. Please refer to the [LICENSE](./LICENSE) file for the full terms. @@ -486,4 +512,4 @@ This project is licensed under the terms of the [MIT](https://spdx.org/licenses/ ## Acknowledgements -Security Lab team members [Man Yue Mo](https://github.com/m-y-mo) and [Peter Stockli](https://github.com/p-) for contributing heavily to the testing and development of this framework, as well as the rest of the Security Lab team for helpful discussions and feedback. +Security Lab team members [Man Yue Mo](https://github.com/m-y-mo) and [Peter Stöckli](https://github.com/p-) for contributing heavily to the testing and development of this framework, as well as the rest of the Security Lab team for helpful discussions and feedback. diff --git a/configs/model_config.yaml b/configs/model_config.yaml deleted file mode 100644 index e236b4c3..00000000 --- a/configs/model_config.yaml +++ /dev/null @@ -1,8 +0,0 @@ -seclab-taskflow-agent: - version: 1 - filetype: model_config -models: - sonnet_default: claude-sonnet-4 - sonnet_latest: claude-sonnet-4.5 - gpt_default: gpt-4.1 - gpt_latest: gpt-5 \ No newline at end of file diff --git a/taskflows/GRAMMAR.md b/doc/GRAMMAR.md similarity index 74% rename from taskflows/GRAMMAR.md rename to doc/GRAMMAR.md index 75a1cd37..4bac01a0 100644 --- a/taskflows/GRAMMAR.md +++ b/doc/GRAMMAR.md @@ -21,7 +21,7 @@ Example: ```yaml - task: agents: - - assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | This is a user prompt. ``` @@ -30,7 +30,7 @@ Note: The exception to this rule are `run` shell tasks. ### Agents -Agents define the system prompt to be used for the task. It contains a list of `filekey` pointing to files of `personality` `filetype`. +`agents` defines the system prompt to be used for the task. It contains a list of files of type `personality`. For example, to use the `personality` defined in the following: @@ -52,12 +52,12 @@ toolboxes: - ... ``` -The task should include the `filekey` in its list of `agents`: +The task should include the personality YAML file in its list of `agents`: ```yaml - task: agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant ... ``` @@ -84,7 +84,7 @@ Tasks can optionally specify which Model to use on the configured inference endp - task: model: gpt-4.1 agents: - - assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | This is a user prompt. ``` @@ -101,30 +101,30 @@ Example: - task: must_complete: true agents: - - assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | ... ``` ### Running templated tasks in a loop -Often we may want to iterate through the same tasks with different inputs. For example, we may want to do fetch all the functions from a code base and then analyze each of the function. This can be done using two consecutive task and with the help of the `repeat_prompt` field. +Often we may want to iterate through the same tasks with different inputs. For example, we may want to fetch all the functions from a code base and then analyze each of the functions. This can be done using two consecutive tasks and with the help of the `repeat_prompt` field. ```yaml - task: agents: - - assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Fetch all the functions in the code base and create a list with entries of the form {'name' : , 'body' : } - task: repeat_prompt: true agents: - - c_auditer + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | The function has name {{ RESULT_name }} and body {{ RESULT_body }} analyze the function. ``` -In the above, the first task fetches functions in the code base and create 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_ }}`. 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: +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_ }}`. 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: ```javascript [{'name' : foo, 'body' : foo(){return 1;}}, {'name' : bar, 'body' : bar(a) {return a + 1;}}] @@ -147,7 +147,7 @@ The iterable can also contain a list of primitives like string or number, in whi max_steps: 5 must_complete: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Store the json array [1, 2, 3] in memory under the `test_repeat_prompt` key as a json object, then retrieve @@ -159,7 +159,7 @@ The iterable can also contain a list of primitives like string or number, in whi must_complete: true repeat_prompt: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | What is the integer value of {{ RESULT }}? ``` @@ -171,7 +171,7 @@ Repeat prompt can be run in parallel by setting the `async` field to `true`: repeat_prompt: true async: true agents: - - c_auditer + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | The function has name {{ RESULT_name }} and body {{ RESULT_body }} analyze the function. ``` @@ -184,12 +184,12 @@ An optional limit can be set to limit the number of asynchronous tasks via `asyn async: true async_limit: 3 agents: - - c_auditer + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | The function has name {{ RESULT_name }} and body {{ RESULT_body }} analyze the function. ``` -Both `async` and `async_limit` have no effect when use outside of a `repeat_prompt`. +Both `async` and `async_limit` have no effect when used outside of a `repeat_prompt`. At the moment, we do not support nested `repeat_prompt`. So the following is not allowed: @@ -197,7 +197,7 @@ At the moment, we do not support nested `repeat_prompt`. So the following is not - task: repeat_prompt: true agents: - - c_auditer + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | The function has name {{ RESULT_name }} and body {{ RESULT_body }} analyze the function. - task: @@ -207,7 +207,7 @@ At the moment, we do not support nested `repeat_prompt`. So the following is not #### Shell Tasks -Tasks can be entirely shell based through the run directive. This simply runs a shell command and pass the result directly to the next task. It is used for creating iterable results for `repeat_prompt`. +Tasks can be entirely shell based through the run directive. This simply runs a shell command and pass the result directly to the next task. It can be used for creating iterable results for `repeat_prompt`. For example: @@ -219,7 +219,7 @@ For example: - task: repeat_prompt: true agents: - - assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | What kind of fruit is {{ RESULT }}? ``` @@ -240,51 +240,51 @@ Example: - task: exclude_from_context: true agents: - - assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | List all the files in the codeql database `some/codeql/db`. toolboxes: - - codeql + - seclab_taskflow_agent.toolboxes.codeql ``` ### Toolboxes / MCP Servers -Toolboxes are MCP server configurations. They can be defined at the Agent level or overridden at the task level. These MCP servers are started and made available to the Agents in the Agents list during a Task. The `toolboxes` field should contain a list of `filekey` for the `toolboxes` that are available for the task: +Toolboxes are MCP server configurations. They can be defined at the Agent level or overridden at the task level. These MCP servers are started and made available to the Agents in the Agents list during a Task. The `toolboxes` field should contain a list of files for the `toolboxes` that are available for the task: ```yaml - task: ... toolboxes: - - toolboxes.codeql + - seclab_taskflow_agent.toolboxes.codeql ``` -If no `toolboxes` is specified, then the `toolboxes` defined in the `personality` of the `agent` is used: +If no `toolboxes` are specified, then the `toolboxes` defined in the `personality` of the `agent` are used: ```yaml - task: agents: - - personalities.c_auditer + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | List all the files in the codeql database `some/codeql/db`. - task: ``` -In the above `task`, as no `toolboxes` is specified, the `toolboxes` defined in the `personality` of `personalities.c_auditer` is used. +In the above `task`, as no `toolboxes` is specified, the `toolboxes` defined in the `personality` of `seclab_taskflow_agent.personalities.c_auditer` is used. Note that when `toolboxes` is defined for a task, it *overwrites* the `toolboxes` that are available. For example, in the following `task`: ```yaml - task: agents: - - personalities.c_auditer + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | List all the files in the codeql database `some/codeql/db`. toolboxes: - - toolboxes.echo + - seclab_taskflow_agent.toolboxes.echo ``` -For this task, the `agent` `personalities.c_auditer` will have access to the `toolboxes.echo` tool. +For this task, the `agent` `seclab_taskflow_agent.personalities.c_auditer` will have access to the `seclab_taskflow_agent.toolboxes.echo` tool. ### Headless Runs @@ -296,7 +296,7 @@ Example: - task: headless: true agents: - - assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Clear the memory cache. toolboxes: @@ -313,11 +313,11 @@ Example: - task: headless: true agents: - - assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Store `hello` in the memory key `world`. toolboxes: - - memcache + - seclab_taskflow_agent.toolboxes.memcache env: MEMCACHE_STATE_DIR: "example_taskflow/" MEMCACHE_BACKEND: "dictionary_file" @@ -335,20 +335,20 @@ globals: taskflow: - task: agents: - - fruit_expert + - examples.personalities.fruit_expert user_prompt: | Tell me more about {{ GLOBALS_fruit }}. ``` ### Reusable Tasks -Tasks can reuse single step taskflows and optionally override any of its configurations. This is done by setting a `uses` field with the `filekey` of the single step taskflow as its value. +Tasks can reuse single step taskflows and optionally override any of its configurations. This is done by setting a `uses` field with a link to the single step taskflow YAML file as its value. Example: ```yaml - task: - uses: single_step_taskflow + uses: examples.taskflows.single_step_taskflow model: gpt-4o ``` @@ -380,15 +380,13 @@ Then the `task` that uses it effectively becomes: - some_toolboxes ``` -which all settings inherited from `single_step_taskflow` while `model` is overwritten. - Any `taskflow` that contains only a single step can be used as a reusable taskflow. -A reusable taskflow can also have templated prompt that takes inputs from its user. This is specified with the `inputs` field from the user. +A reusable taskflow can also have a templated prompt that takes inputs from its user. This is specified with the `inputs` field from the user. ```yaml - task: - uses: single_step_taskflow + uses: examples.taskflows.single_step_taskflow inputs: fruit: apples ``` @@ -396,7 +394,7 @@ A reusable taskflow can also have templated prompt that takes inputs from its us ```yaml - task: agents: - - fruit_expert + - examples.personalities.fruit_expert user_prompt: | Tell me more about {{ INPUTS_fruit }}. ``` @@ -406,14 +404,14 @@ In this case, the template parameter `{{ INPUTS_fruit }}` is replaced by the val ```yaml - task: agents: - - fruit_expert + - examples.personalities.fruit_expert user_prompt: | Tell me more about apples. ``` ### Reusable Prompts -Reusable prompts are defined in files of `filetype` `prompts`. These are like macros that gets replaced when a templated parameter of the form `{{ PROMPTS_ }}` is encountered. +Reusable prompts are defined in files of `filetype` `prompts`. These are like macros that get replaced when a templated parameter of the form `{{ PROMPTS_ }}` is encountered. Tasks can incorporate templated prompts which are then replaced by the actual prompt. For example: @@ -422,13 +420,13 @@ Example: ```yaml - task: agents: - - fruit_expert + - examples.personalities.fruit_expert user_prompt: | Tell me more about apples. - - {{ PROMPTS_prompts.examples.example_prompt }} + + {{ PROMPTS_examples.prompts.example_prompt }} ``` -and `prompts.examples.example_prompt` is the following: +and `examples.prompts.example_prompt` is the following: ```yaml seclab-taskflow-agent: @@ -444,7 +442,7 @@ Then the actual task becomes: ```yaml - task: agents: - - fruit_expert + - examples.personalities.fruit_expert user_prompt: | Tell me more about apples. @@ -453,15 +451,14 @@ Then the actual task becomes: ### Model config -LLM models can be configured in a taskflow by setting the `model_config` field to the `filekey` of a file of `filetype` `model_config` : +LLM models can be configured in a taskflow by setting the `model_config` field to a file of type `model_config`: ```yaml seclab-taskflow-agent: version: 1 filetype: taskflow -model_config: configs.model_config - +model_config: examples.model_configs.model_config ``` The variables defined in the `model_config` file can then be used throughout the taskflow, e.g. @@ -471,7 +468,7 @@ seclab-taskflow-agent: version: 1 filetype: model_config models: - gpt_latest: gpt-5 + gpt_latest: gpt-5 ``` When `gpt_latest` is used in the taskflow to specify a model, the value `gpt-5` is used: @@ -481,9 +478,9 @@ When `gpt_latest` is used in the taskflow to specify a model, the value `gpt-5` model: gpt_latest must_complete: false agents: - - personalities.c_auditer + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | ``` -This provides a easy way to update model versions in a taskflow. \ No newline at end of file +This provides a easy way to update model versions in a taskflow. diff --git a/examples/model_configs/model_config.yaml b/examples/model_configs/model_config.yaml new file mode 100644 index 00000000..681760d8 --- /dev/null +++ b/examples/model_configs/model_config.yaml @@ -0,0 +1,8 @@ +seclab-taskflow-agent: + version: 1 + filetype: model_config +models: + sonnet_default: claude-sonnet-4 + sonnet_latest: claude-sonnet-4.5 + gpt_default: gpt-4.1 + gpt_latest: gpt-5 diff --git a/personalities/examples/apple_expert.yaml b/examples/personalities/apple_expert.yaml similarity index 100% rename from personalities/examples/apple_expert.yaml rename to examples/personalities/apple_expert.yaml diff --git a/personalities/examples/banana_expert.yaml b/examples/personalities/banana_expert.yaml similarity index 100% rename from personalities/examples/banana_expert.yaml rename to examples/personalities/banana_expert.yaml diff --git a/personalities/examples/echo.yaml b/examples/personalities/echo.yaml similarity index 52% rename from personalities/examples/echo.yaml rename to examples/personalities/echo.yaml index 770a752e..bd0aaa58 100644 --- a/personalities/examples/echo.yaml +++ b/examples/personalities/echo.yaml @@ -1,3 +1,4 @@ +# personalities define the system prompt level directives for this Agent seclab-taskflow-agent: version: 1 filetype: personality @@ -8,6 +9,6 @@ personality: | task: | Echo user inputs using the echo tools. +# personality toolboxes map to mcp servers made available to this Agent toolboxes: - - toolboxes.echo - + - seclab_taskflow_agent.toolboxes.echo diff --git a/personalities/examples/example_triage_agent.yaml b/examples/personalities/example_triage_agent.yaml similarity index 100% rename from personalities/examples/example_triage_agent.yaml rename to examples/personalities/example_triage_agent.yaml diff --git a/personalities/examples/fruit_expert.yaml b/examples/personalities/fruit_expert.yaml similarity index 100% rename from personalities/examples/fruit_expert.yaml rename to examples/personalities/fruit_expert.yaml diff --git a/personalities/examples/orange_expert.yaml b/examples/personalities/orange_expert.yaml similarity index 100% rename from personalities/examples/orange_expert.yaml rename to examples/personalities/orange_expert.yaml diff --git a/prompts/examples/example_prompt.yaml b/examples/prompts/example_prompt.yaml similarity index 100% rename from prompts/examples/example_prompt.yaml rename to examples/prompts/example_prompt.yaml diff --git a/taskflows/CVE-2023-2283/CVE-2023-2283.yaml b/examples/taskflows/CVE-2023-2283.yaml similarity index 88% rename from taskflows/CVE-2023-2283/CVE-2023-2283.yaml rename to examples/taskflows/CVE-2023-2283.yaml index 4b3922d3..ddee9271 100644 --- a/taskflows/CVE-2023-2283/CVE-2023-2283.yaml +++ b/examples/taskflows/CVE-2023-2283.yaml @@ -2,23 +2,23 @@ seclab-taskflow-agent: version: 1 filetype: taskflow -model_config: configs.model_config +model_config: examples.model_configs.model_config taskflow: - task: must_complete: true headless: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Clear the memory cache. toolboxes: - - toolboxes.memcache + - seclab_taskflow_agent.toolboxes.memcache - task: model: gpt_latest must_complete: false agents: - - personalities.c_auditer + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | You are auditing code using the `libssh-mirror/libssh-codeql` CodeQL database. @@ -78,15 +78,15 @@ taskflow: 6. Make small and concise single line notes while you work. Update the existing value for `notes` in memory as you work. toolboxes: - - toolboxes.codeql - - toolboxes.memcache + - seclab_taskflow_agent.toolboxes.codeql + - seclab_taskflow_agent.toolboxes.memcache - task: must_complete: true agents: - - personalities.c_auditer + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | Fetch your audit notes from memory using the `notes` key. Do not perform any additional security review, only show me your notes. toolboxes: - - toolboxes.memcache + - seclab_taskflow_agent.toolboxes.memcache diff --git a/taskflows/examples/echo.yaml b/examples/taskflows/echo.yaml similarity index 81% rename from taskflows/examples/echo.yaml rename to examples/taskflows/echo.yaml index 3e562087..34aab564 100644 --- a/taskflows/examples/echo.yaml +++ b/examples/taskflows/echo.yaml @@ -8,13 +8,13 @@ taskflow: max_steps: 5 must_complete: true agents: - - personalities.examples.echo + - examples.personalities.echo user_prompt: | Hello - task: must_complete: true agents: - - personalities.examples.echo + - examples.personalities.echo user_prompt: | Goodbye env: diff --git a/taskflows/examples/example.yaml b/examples/taskflows/example.yaml similarity index 87% rename from taskflows/examples/example.yaml rename to examples/taskflows/example.yaml index 267527cb..f71cb31f 100644 --- a/taskflows/examples/example.yaml +++ b/examples/taskflows/example.yaml @@ -12,8 +12,8 @@ taskflow: must_complete: true # taskflows can set a primary (first entry) and handoff (additional entries) agent agents: - - personalities.c_auditer - - personalities.examples.fruit_expert + - seclab_taskflow_agent.personalities.c_auditer + - examples.personalities.fruit_expert user_prompt: | Store an example vulnerable C program that uses `strcpy` in the `vulnerable_c_example` memory key and explain why `strcpy` @@ -34,13 +34,13 @@ taskflow: # this normally only has the memcache toolbox, but we extend it here with # the GHSA toolbox toolboxes: - - toolboxes.memcache - - toolboxes.codeql + - seclab_taskflow_agent.toolboxes.memcache + - seclab_taskflow_agent.toolboxes.codeql - task: must_complete: true model: gpt-4.1 agents: - - personalities.c_auditer + - seclab_taskflow_agent.personalities.c_auditer user_prompt: | Retrieve C code for security review from the `vulnerable_c_example` memory key and perform a review. @@ -50,7 +50,7 @@ taskflow: MEMCACHE_STATE_DIR: "example_taskflow/" MEMCACHE_BACKEND: "dictionary_file" toolboxes: - - toolboxes.memcache + - seclab_taskflow_agent.toolboxes.memcache # headless mode does not prompt for tool call confirms configured for a server # note: this will auto-allow, if you want control over potentially dangerous # tool calls, then you should NOT run a task in headless mode (default: false) @@ -63,6 +63,6 @@ taskflow: - task: repeat_prompt: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | What kind of fruit is {{ RESULT }}? diff --git a/taskflows/examples/example_globals.yaml b/examples/taskflows/example_globals.yaml similarity index 80% rename from taskflows/examples/example_globals.yaml rename to examples/taskflows/example_globals.yaml index cfaf3105..0383b640 100644 --- a/taskflows/examples/example_globals.yaml +++ b/examples/taskflows/example_globals.yaml @@ -7,6 +7,6 @@ globals: taskflow: - task: agents: - - personalities.examples.fruit_expert + - examples.personalities.fruit_expert user_prompt: | Tell me more about {{ GLOBALS_fruit }}. diff --git a/taskflows/examples/example_inputs.yaml b/examples/taskflows/example_inputs.yaml similarity index 81% rename from taskflows/examples/example_inputs.yaml rename to examples/taskflows/example_inputs.yaml index 322f7a7c..525de032 100644 --- a/taskflows/examples/example_inputs.yaml +++ b/examples/taskflows/example_inputs.yaml @@ -5,7 +5,7 @@ seclab-taskflow-agent: taskflow: - task: agents: - - personalities.examples.fruit_expert + - examples.personalities.fruit_expert inputs: fruit: apples user_prompt: | diff --git a/taskflows/examples/example_large_list_result_iter.yaml b/examples/taskflows/example_large_list_result_iter.yaml similarity index 76% rename from taskflows/examples/example_large_list_result_iter.yaml rename to examples/taskflows/example_large_list_result_iter.yaml index 651c7882..7912bb5c 100644 --- a/taskflows/examples/example_large_list_result_iter.yaml +++ b/examples/taskflows/example_large_list_result_iter.yaml @@ -7,18 +7,18 @@ taskflow: exclude_from_context: true must_complete: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Fetch all the open pull requests from `github/codeql` github repository. You do not need to provide a summary of the results. toolboxes: - - toolboxes.github_official + - seclab_taskflow_agent.toolboxes.github_official env: GITHUB_MCP_TOOLSETS: pull_requests - task: must_complete: true repeat_prompt: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Echo this: The title is {{ RESULT_title }} and the url is {{ RESULT_url }}. diff --git a/taskflows/examples/example_repeat_prompt.yaml b/examples/taskflows/example_repeat_prompt.yaml similarity index 81% rename from taskflows/examples/example_repeat_prompt.yaml rename to examples/taskflows/example_repeat_prompt.yaml index 1fc02b25..09a53c22 100644 --- a/taskflows/examples/example_repeat_prompt.yaml +++ b/examples/taskflows/example_repeat_prompt.yaml @@ -7,7 +7,7 @@ taskflow: max_steps: 5 must_complete: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Store the json array [1, 2, 3] in memory under the `test_repeat_prompt` key as a json object, then retrieve @@ -16,13 +16,13 @@ taskflow: MEMCACHE_STATE_DIR: "example_repeat_prompt_taskflow/" MEMCACHE_BACKEND: "dictionary_file" toolboxes: - - toolboxes.memcache + - seclab_taskflow_agent.toolboxes.memcache - task: # if the last mcp tool result is iterable # repeat_prompt can iter those results must_complete: true repeat_prompt: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | What is the integer value of {{ RESULT }}? diff --git a/taskflows/examples/example_repeat_prompt_async.yaml b/examples/taskflows/example_repeat_prompt_async.yaml similarity index 84% rename from taskflows/examples/example_repeat_prompt_async.yaml rename to examples/taskflows/example_repeat_prompt_async.yaml index c2891581..8ac7cdc7 100644 --- a/taskflows/examples/example_repeat_prompt_async.yaml +++ b/examples/taskflows/example_repeat_prompt_async.yaml @@ -7,7 +7,7 @@ taskflow: max_steps: 5 must_complete: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Store the json array [1, 2, 3] in memory under the `test_repeat_prompt` key as a json object, then retrieve @@ -16,7 +16,7 @@ taskflow: MEMCACHE_STATE_DIR: "example_repeat_prompt_taskflow/" MEMCACHE_BACKEND: "dictionary_file" toolboxes: - - toolboxes.memcache + - seclab_taskflow_agent.toolboxes.memcache - task: # if the last mcp tool result is iterable # repeat_prompt can iter those results @@ -27,6 +27,6 @@ taskflow: # you can also limit the max concurrent tasks (default 5) async_limit: 2 agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | What is the integer value of {{ RESULT }}? diff --git a/taskflows/examples/example_repeat_prompt_dictionary.yaml b/examples/taskflows/example_repeat_prompt_dictionary.yaml similarity index 83% rename from taskflows/examples/example_repeat_prompt_dictionary.yaml rename to examples/taskflows/example_repeat_prompt_dictionary.yaml index a9e23f63..bf29dac9 100644 --- a/taskflows/examples/example_repeat_prompt_dictionary.yaml +++ b/examples/taskflows/example_repeat_prompt_dictionary.yaml @@ -7,7 +7,7 @@ taskflow: max_steps: 5 must_complete: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Store the json array [{index : 1, value : 2}, {index : 2, value : 4}, {index : 3, value : 6}] in memory under the `test_repeat_prompt` key @@ -17,13 +17,13 @@ taskflow: MEMCACHE_STATE_DIR: "example_repeat_prompt_taskflow/" MEMCACHE_BACKEND: "dictionary_file" toolboxes: - - toolboxes.memcache + - seclab_taskflow_agent.toolboxes.memcache - task: # if the last mcp tool result is iterable # repeat_prompt can iter those results must_complete: true repeat_prompt: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | What is the value of {{ RESULT_index }} + {{ RESULT_value }}? diff --git a/taskflows/examples/example_reusable_prompt.yaml b/examples/taskflows/example_reusable_prompt.yaml similarity index 61% rename from taskflows/examples/example_reusable_prompt.yaml rename to examples/taskflows/example_reusable_prompt.yaml index 845bcec9..a8ad81a2 100644 --- a/taskflows/examples/example_reusable_prompt.yaml +++ b/examples/taskflows/example_reusable_prompt.yaml @@ -5,8 +5,8 @@ seclab-taskflow-agent: taskflow: - task: agents: - - personalities.examples.fruit_expert + - examples.personalities.fruit_expert user_prompt: | Tell me more about apples. - {{ PROMPTS_prompts.examples.example_prompt }} + {{ PROMPTS_examples.prompts.example_prompt }} diff --git a/taskflows/examples/example_reusable_taskflows.yaml b/examples/taskflows/example_reusable_taskflows.yaml similarity index 81% rename from taskflows/examples/example_reusable_taskflows.yaml rename to examples/taskflows/example_reusable_taskflows.yaml index 6597e572..49c5e913 100644 --- a/taskflows/examples/example_reusable_taskflows.yaml +++ b/examples/taskflows/example_reusable_taskflows.yaml @@ -5,6 +5,6 @@ seclab-taskflow-agent: taskflow: - task: # with the `uses` directive we can reuse single task taskflows - uses: taskflows.examples.single_step_taskflow + uses: examples.taskflows.single_step_taskflow # and optionally override any of its configurations model: gpt-4o diff --git a/taskflows/examples/example_triage_taskflow.yaml b/examples/taskflows/example_triage_taskflow.yaml similarity index 67% rename from taskflows/examples/example_triage_taskflow.yaml rename to examples/taskflows/example_triage_taskflow.yaml index bd5672e0..cc0a2805 100644 --- a/taskflows/examples/example_triage_taskflow.yaml +++ b/examples/taskflows/example_triage_taskflow.yaml @@ -7,34 +7,34 @@ taskflow: - task: must_complete: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Store the json array ["apples", "oranges", "bananas"] in the `fruits` memory key. env: MEMCACHE_STATE_DIR: "example_taskflow/" MEMCACHE_BACKEND: "dictionary_file" toolboxes: - - toolboxes.memcache + - seclab_taskflow_agent.toolboxes.memcache - task: must_complete: true agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Retrieve the contents of the `fruits` memory key. env: MEMCACHE_STATE_DIR: "example_taskflow/" MEMCACHE_BACKEND: "dictionary_file" toolboxes: - - toolboxes.memcache + - seclab_taskflow_agent.toolboxes.memcache - task: model: gpt-4.1 repeat_prompt: true agents: # primary agent for this task - - personalities.examples.example_triage_agent + - examples.personalities.example_triage_agent # handoff agents - - personalities.examples.apple_expert - - personalities.examples.orange_expert - - personalities.examples.banana_expert + - examples.personalities.apple_expert + - examples.personalities.orange_expert + - examples.personalities.banana_expert user_prompt: | Tell me more about how {{ RESULT }} are grown. diff --git a/taskflows/examples/single_step_taskflow.yaml b/examples/taskflows/single_step_taskflow.yaml similarity index 79% rename from taskflows/examples/single_step_taskflow.yaml rename to examples/taskflows/single_step_taskflow.yaml index 455cc91d..d884f360 100644 --- a/taskflows/examples/single_step_taskflow.yaml +++ b/examples/taskflows/single_step_taskflow.yaml @@ -6,6 +6,6 @@ taskflow: - task: model: gpt-4.1 agents: - - personalities.assistant + - seclab_taskflow_agent.personalities.assistant user_prompt: | Explain the plot of William Gibson's Neuromancer in a single paragraph. diff --git a/mcp_servers/memcache/memcache_backend/__init__.py b/mcp_servers/memcache/memcache_backend/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..d98fe271 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,147 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "seclab-taskflow-agent" +dynamic = ["version"] +description = "A taskflow agent for the SecLab project, enabling secure and automated workflow execution." +readme = "README.md" +requires-python = ">=3.9" +license = "MIT" +keywords = [] +authors = [ + { name = "GitHub Security Lab", email = "securitylab@github.com" }, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: Implementation :: CPython", + "Programming Language :: Python :: Implementation :: PyPy", +] +dependencies = [ + "aiofiles==24.1.0", + "annotated-types==0.7.0", + "anyio==4.9.0", + "attrs==25.3.0", + "Authlib==1.6.5", + "certifi==2025.6.15", + "cffi==2.0.0", + "charset-normalizer==3.4.2", + "click==8.2.1", + "colorama==0.4.6", + "cryptography==45.0.7", + "cyclopts==3.24.0", + "distro==1.9.0", + "dnspython==2.8.0", + "docstring-to-markdown==0.17", + "docstring_parser==0.17.0", + "docutils==0.22", + "email-validator==2.3.0", + "exceptiongroup==1.3.0", + "fastmcp==2.12.2", + "griffe==1.7.3", + "h11==0.16.0", + "httpcore==1.0.9", + "httpx==0.28.1", + "httpx-sse==0.4.1", + "idna==3.10", + "importlib_metadata==8.7.0", + "isodate==0.7.2", + "jedi==0.19.2", + "jiter==0.10.0", + "jsonschema==4.24.0", + "jsonschema-path==0.3.4", + "jsonschema-specifications==2025.4.1", + "lazy-object-proxy==1.12.0", + "markdown-it-py==3.0.0", + "MarkupSafe==3.0.2", + "mcp==1.13.1", + "mdurl==0.1.2", + "more-itertools==10.8.0", + "openai==1.107.0", + "openai-agents==0.2.11", + "openapi-core==0.19.5", + "openapi-pydantic==0.5.1", + "openapi-schema-validator==0.6.3", + "openapi-spec-validator==0.7.2", + "parse==1.20.2", + "parso==0.8.4", + "pathable==0.4.4", + "pluggy==1.6.0", + "pycparser==2.23", + "pydantic==2.11.7", + "pydantic-settings==2.10.1", + "pydantic_core==2.33.2", + "Pygments==2.19.2", + "pyperclip==1.9.0", + "python-dotenv==1.1.1", + "python-lsp-jsonrpc==1.1.2", + "python-lsp-server==1.12.2", + "python-multipart==0.0.20", + "PyYAML==6.0.2", + "referencing==0.36.2", + "requests==2.32.4", + "rfc3339-validator==0.1.4", + "rich==14.0.0", + "rich-rst==1.3.1", + "rpds-py==0.26.0", + "shellingham==1.5.4", + "six==1.17.0", + "sniffio==1.3.1", + "SQLAlchemy==2.0.41", + "sse-starlette==2.4.1", + "starlette==0.47.2", + "tqdm==4.67.1", + "typer==0.16.0", + "types-requests==2.32.4.20250611", + "typing-inspection==0.4.1", + "typing_extensions==4.14.1", + "ujson==5.10.0", + "urllib3==2.5.0", + "uvicorn==0.35.0", + "Werkzeug==3.1.1", + "zipp==3.23.0", +] + +[project.urls] +Source = "https://github.com/GitHubSecurityLab/seclab-taskflow-agent" +Issues = "https://github.com/GitHubSecurityLab/seclab-taskflow-agent/issues" + +[tool.hatch.version] +path = "src/seclab_taskflow_agent/__about__.py" + +[tool.hatch.envs.default.scripts] +main = "python -m seclab_taskflow_agent {args:tests}" +sync-deps = "" + +[tool.hatch.envs.types] +extra-dependencies = [ + "mypy>=1.0.0", +] +[tool.hatch.envs.types.scripts] +check = "mypy --install-types --non-interactive {args:src/seclab_taskflow_agent tests}" + +[tool.coverage.run] +source_pkgs = ["seclab_taskflow_agent", "tests"] +branch = true +parallel = true +omit = [ + "src/seclab_taskflow_agent/__about__.py", +] + +[tool.coverage.paths] +seclab_taskflow_agent = ["src/seclab_taskflow_agent", "*/seclab-taskflow-agent/src/seclab_taskflow_agent"] +tests = ["tests", "*/seclab-taskflow-agent/tests"] + +[tool.coverage.report] +exclude_lines = [ + "no cov", + "if __name__ == .__main__.:", + "if TYPE_CHECKING:", +] diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index 3a0c46d7..00000000 --- a/pytest.ini +++ /dev/null @@ -1,6 +0,0 @@ -[tool:pytest] -testpaths = tests -python_files = test_*.py -python_classes = Test* -python_functions = test_* -addopts = -v --tb=short \ No newline at end of file diff --git a/release.txt b/release.txt index 80dcff3d..0679154d 100644 --- a/release.txt +++ b/release.txt @@ -4,106 +4,119 @@ # release tooling ./release.txt +./release_tools/release.sh ./release_tools/HOWTO.md ./release_tools/copy_files.py ./release_tools/publish_docker.py -# license +# license, etc. ./LICENSE +./CODEOWNERS +./CONTRIBUTING.md +./NOTICE +./CODE_OF_CONDUCT.md +./SUPPORT.md +./SECURITY.md # deps -./requirements.txt +./pyproject.toml # docker ./docker/run.sh # docs ./README.md -./taskflows/GRAMMAR.md +./doc/GRAMMAR.md # logs ./logs/ABOUT # code -./main.py -./agent.py -./capi.py -./mcp_utils.py -./env_utils.py -./render_utils.py -./shell_utils.py -./available_tools.py +./src/seclab_taskflow_agent/__init__.py +./src/seclab_taskflow_agent/__about__.py +./src/seclab_taskflow_agent/__main__.py +./src/seclab_taskflow_agent/agent.py +./src/seclab_taskflow_agent/capi.py +./src/seclab_taskflow_agent/mcp_utils.py +./src/seclab_taskflow_agent/env_utils.py +./src/seclab_taskflow_agent/render_utils.py +./src/seclab_taskflow_agent/shell_utils.py +./src/seclab_taskflow_agent/available_tools.py + +# configs +./examples/model_configs/model_config.yaml # prompts -./prompts/examples/example_prompt.yaml +./examples/prompts/example_prompt.yaml # taskflows -./taskflows/CVE-2023-2283/CVE-2023-2283.yaml -./taskflows/examples/example_reusable_prompt.yaml -./taskflows/examples/echo.yaml -./taskflows/examples/example.yaml -./taskflows/examples/example_inputs.yaml -./taskflows/examples/example_repeat_prompt.yaml -./taskflows/examples/example_repeat_prompt_dictionary.yaml -./taskflows/examples/example_reusable_taskflows.yaml -./taskflows/examples/example_large_list_result_iter.yaml -./taskflows/examples/example_repeat_prompt_async.yaml -./taskflows/examples/single_step_taskflow.yaml -./taskflows/examples/example_triage_taskflow.yaml -./taskflows/examples/example_globals.yaml +./examples/taskflows/CVE-2023-2283.yaml +./examples/taskflows/example_reusable_prompt.yaml +./examples/taskflows/echo.yaml +./examples/taskflows/example.yaml +./examples/taskflows/example_inputs.yaml +./examples/taskflows/example_repeat_prompt.yaml +./examples/taskflows/example_repeat_prompt_dictionary.yaml +./examples/taskflows/example_reusable_taskflows.yaml +./examples/taskflows/example_large_list_result_iter.yaml +./examples/taskflows/example_repeat_prompt_async.yaml +./examples/taskflows/single_step_taskflow.yaml +./examples/taskflows/example_triage_taskflow.yaml +./examples/taskflows/example_globals.yaml # toolboxes ## github official -./toolboxes/github_official.yaml +./src/seclab_taskflow_agent/toolboxes/github_official.yaml ## echo -./toolboxes/echo.yaml -./mcp_servers/echo/echo.py +./src/seclab_taskflow_agent/toolboxes/echo.yaml +./src/seclab_taskflow_agent/mcp_servers/echo/echo.py ## memcache -./toolboxes/memcache.yaml -./mcp_servers/memcache/memcache.py -./mcp_servers/memcache/memcache_backend/__init__.py -./mcp_servers/memcache/memcache_backend/backend.py -./mcp_servers/memcache/memcache_backend/dictionary_file.py -./mcp_servers/memcache/memcache_backend/sql_models.py -./mcp_servers/memcache/memcache_backend/sqlite.py +./src/seclab_taskflow_agent/toolboxes/memcache.yaml +./src/seclab_taskflow_agent/mcp_servers/memcache/__init__.py +./src/seclab_taskflow_agent/mcp_servers/memcache/memcache.py +./src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/__init__.py +./src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/backend.py +./src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/dictionary_file.py +./src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/sql_models.py +./src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/sqlite.py ## logbook -./toolboxes/logbook.yaml -./mcp_servers/logbook/logbook.py +./src/seclab_taskflow_agent/toolboxes/logbook.yaml +./src/seclab_taskflow_agent/mcp_servers/logbook/logbook.py ## codeql -./toolboxes/codeql.yaml -./mcp_servers/codeql/mcp_server.py -./mcp_servers/codeql/client.py -./mcp_servers/codeql/queries/README.md -./mcp_servers/codeql/queries/mcp-js/relative_to_absolute.ql -./mcp_servers/codeql/queries/mcp-js/qlpack.yml -./mcp_servers/codeql/queries/mcp-js/absolute_to_relative.ql -./mcp_servers/codeql/queries/mcp-js/definition_location_for_function.ql -./mcp_servers/codeql/queries/mcp-js/call_graph_from.ql -./mcp_servers/codeql/queries/mcp-js/locations.qll -./mcp_servers/codeql/queries/mcp-js/call_graph_to.ql -./mcp_servers/codeql/queries/mcp-cpp/stmt_location.ql -./mcp_servers/codeql/queries/mcp-cpp/declaration_location_for_variable.ql -./mcp_servers/codeql/queries/mcp-cpp/relative_to_absolute.ql -./mcp_servers/codeql/queries/mcp-cpp/call_graph_from_to.ql -./mcp_servers/codeql/queries/mcp-cpp/qlpack.yml -./mcp_servers/codeql/queries/mcp-cpp/absolute_to_relative.ql -./mcp_servers/codeql/queries/mcp-cpp/codeql-pack.lock.yml -./mcp_servers/codeql/queries/mcp-cpp/definition_location_for_function.ql -./mcp_servers/codeql/queries/mcp-cpp/call_graph_from.ql -./mcp_servers/codeql/queries/mcp-cpp/list_functions.ql -./mcp_servers/codeql/queries/mcp-cpp/locations.qll -./mcp_servers/codeql/queries/mcp-cpp/call_graph_to.ql -./mcp_servers/codeql/jsonrpyc/LICENSE -./mcp_servers/codeql/jsonrpyc/__meta__.py -./mcp_servers/codeql/jsonrpyc/__init__.py -./mcp_servers/codeql/jsonrpyc/py.typed +./src/seclab_taskflow_agent/toolboxes/codeql.yaml +./src/seclab_taskflow_agent/mcp_servers/codeql/mcp_server.py +./src/seclab_taskflow_agent/mcp_servers/codeql/client.py +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/README.md +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/relative_to_absolute.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/qlpack.yml +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/absolute_to_relative.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/definition_location_for_function.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/call_graph_from.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/locations.qll +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/call_graph_to.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/stmt_location.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/declaration_location_for_variable.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/relative_to_absolute.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/call_graph_from_to.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/qlpack.yml +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/absolute_to_relative.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/codeql-pack.lock.yml +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/definition_location_for_function.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/call_graph_from.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/list_functions.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/locations.qll +./src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/call_graph_to.ql +./src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/LICENSE +./src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/__meta__.py +./src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/__init__.py +./src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/py.typed # personalities -./personalities/assistant.yaml -./personalities/c_auditer.yaml -./personalities/examples/fruit_expert.yaml -./personalities/examples/echo.yaml -./personalities/examples/banana_expert.yaml -./personalities/examples/orange_expert.yaml -./personalities/examples/example_triage_agent.yaml -./personalities/examples/apple_expert.yaml +./src/seclab_taskflow_agent/personalities/assistant.yaml +./src/seclab_taskflow_agent/personalities/c_auditer.yaml +./examples/personalities/fruit_expert.yaml +./examples/personalities/echo.yaml +./examples/personalities/banana_expert.yaml +./examples/personalities/orange_expert.yaml +./examples/personalities/example_triage_agent.yaml +./examples/personalities/apple_expert.yaml diff --git a/release_tools/copy_files.py b/release_tools/copy_files.py index e38a6dcd..c57df6fd 100644 --- a/release_tools/copy_files.py +++ b/release_tools/copy_files.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import os import shutil import sys diff --git a/release_tools/publish_docker.py b/release_tools/publish_docker.py index 91839ebd..a28e8575 100644 --- a/release_tools/publish_docker.py +++ b/release_tools/publish_docker.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import os import shutil import subprocess @@ -71,13 +74,14 @@ def write_dockerfile(dest_dir, entrypoint): COPY . /app # Install CodeQL pack dependencies -RUN codeql pack install /app/mcp_servers/codeql/queries/mcp-cpp -RUN codeql pack install /app/mcp_servers/codeql/queries/mcp-js +RUN codeql pack install /app/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp +RUN codeql pack install /app/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js -# Install Python dependencies if requirements.txt exists -RUN if [ -f requirements.txt ]; then pip install --no-cache-dir -r requirements.txt; fi +# Install Python dependencies if pyproject.toml exists +RUN pip install hatch +RUN if [ -f pyproject.toml ]; then hatch run sync-deps; fi -ENTRYPOINT ["python", "{entrypoint}"] +ENTRYPOINT ["hatch", "run", "{entrypoint}"] ''' with open(os.path.join(dest_dir, "Dockerfile"), "w") as f: f.write(dockerfile) diff --git a/release_tools/release.sh b/release_tools/release.sh index fb0b267a..d80be5b9 100755 --- a/release_tools/release.sh +++ b/release_tools/release.sh @@ -1,2 +1,2 @@ #!/bin/sh -python release_tools/publish_docker.py release.txt main.py ghcr.io/githubsecuritylab/seclab-taskflow-agent latest +python release_tools/publish_docker.py release.txt main ghcr.io/githubsecuritylab/seclab-taskflow-agent latest diff --git a/requirements-test.txt b/requirements-test.txt deleted file mode 100644 index ca2a5498..00000000 --- a/requirements-test.txt +++ /dev/null @@ -1 +0,0 @@ -pytest==8.4.2 \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index a78bb095..00000000 --- a/requirements.txt +++ /dev/null @@ -1,82 +0,0 @@ -aiofiles==24.1.0 -annotated-types==0.7.0 -anyio==4.9.0 -attrs==25.3.0 -Authlib==1.6.5 -certifi==2025.6.15 -cffi==2.0.0 -charset-normalizer==3.4.2 -click==8.2.1 -colorama==0.4.6 -cryptography==45.0.7 -cyclopts==3.24.0 -distro==1.9.0 -dnspython==2.8.0 -docstring-to-markdown==0.17 -docstring_parser==0.17.0 -docutils==0.22 -email-validator==2.3.0 -exceptiongroup==1.3.0 -fastmcp==2.12.2 -griffe==1.7.3 -h11==0.16.0 -httpcore==1.0.9 -httpx==0.28.1 -httpx-sse==0.4.1 -idna==3.10 -importlib_metadata==8.7.0 -isodate==0.7.2 -jedi==0.19.2 -jiter==0.10.0 -jsonschema==4.24.0 -jsonschema-path==0.3.4 -jsonschema-specifications==2025.4.1 -lazy-object-proxy==1.12.0 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -mcp==1.13.1 -mdurl==0.1.2 -more-itertools==10.8.0 -openai==1.107.0 -openai-agents==0.2.11 -openapi-core==0.19.5 -openapi-pydantic==0.5.1 -openapi-schema-validator==0.6.3 -openapi-spec-validator==0.7.2 -parse==1.20.2 -parso==0.8.4 -pathable==0.4.4 -pluggy==1.6.0 -pycparser==2.23 -pydantic==2.11.7 -pydantic-settings==2.10.1 -pydantic_core==2.33.2 -Pygments==2.19.2 -pyperclip==1.9.0 -python-dotenv==1.1.1 -python-lsp-jsonrpc==1.1.2 -python-lsp-server==1.12.2 -python-multipart==0.0.20 -PyYAML==6.0.2 -referencing==0.36.2 -requests==2.32.4 -rfc3339-validator==0.1.4 -rich==14.0.0 -rich-rst==1.3.1 -rpds-py==0.26.0 -shellingham==1.5.4 -six==1.17.0 -sniffio==1.3.1 -SQLAlchemy==2.0.41 -sse-starlette==2.4.1 -starlette==0.47.2 -tqdm==4.67.1 -typer==0.16.0 -types-requests==2.32.4.20250611 -typing-inspection==0.4.1 -typing_extensions==4.14.1 -ujson==5.10.0 -urllib3==2.5.0 -uvicorn==0.35.0 -Werkzeug==3.1.1 -zipp==3.23.0 diff --git a/src/seclab_taskflow_agent/__about__.py b/src/seclab_taskflow_agent/__about__.py new file mode 100644 index 00000000..c47c1f90 --- /dev/null +++ b/src/seclab_taskflow_agent/__about__.py @@ -0,0 +1,3 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT +__version__ = "0.0.1" diff --git a/src/seclab_taskflow_agent/__init__.py b/src/seclab_taskflow_agent/__init__.py new file mode 100644 index 00000000..1710739e --- /dev/null +++ b/src/seclab_taskflow_agent/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT diff --git a/main.py b/src/seclab_taskflow_agent/__main__.py similarity index 98% rename from main.py rename to src/seclab_taskflow_agent/__main__.py index b45362b7..5818d9eb 100644 --- a/main.py +++ b/src/seclab_taskflow_agent/__main__.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import asyncio from threading import Thread import argparse @@ -12,7 +15,7 @@ import uuid import pathlib -from agent import DEFAULT_MODEL, TaskRunHooks, TaskAgentHooks +from .agent import DEFAULT_MODEL, TaskRunHooks, TaskAgentHooks #from agents.run import DEFAULT_MAX_TURNS # XXX: this is 10, we need more than that from agents.exceptions import MaxTurnsExceeded, AgentsException from agents.agent import ModelSettings @@ -23,13 +26,13 @@ from openai.types.responses import ResponseTextDeltaEvent from typing import Callable -from shell_utils import shell_tool_call -from mcp_utils import DEFAULT_MCP_CLIENT_SESSION_TIMEOUT, ReconnectingMCPServerStdio, AsyncDebugMCPServerStdio, MCPNamespaceWrap, mcp_client_params, mcp_system_prompt, StreamableMCPThread, compress_name -from render_utils import render_model_output, flush_async_output -from env_utils import TmpEnv -from agent import TaskAgent -from capi import list_tool_call_models -from available_tools import AvailableTools +from .shell_utils import shell_tool_call +from .mcp_utils import DEFAULT_MCP_CLIENT_SESSION_TIMEOUT, ReconnectingMCPServerStdio, MCPNamespaceWrap, mcp_client_params, mcp_system_prompt, StreamableMCPThread, compress_name +from .render_utils import render_model_output, flush_async_output +from .env_utils import TmpEnv +from .agent import TaskAgent +from .capi import list_tool_call_models +from .available_tools import AvailableTools load_dotenv() diff --git a/agent.py b/src/seclab_taskflow_agent/agent.py similarity index 98% rename from agent.py rename to src/seclab_taskflow_agent/agent.py index 4ddf7fb9..91b000fa 100644 --- a/agent.py +++ b/src/seclab_taskflow_agent/agent.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + # https://openai.github.io/openai-agents-python/agents/ import os import logging @@ -12,7 +15,7 @@ from agents.run import RunHooks from agents import Agent, Runner, AgentHooks, RunHooks, result, function_tool, Tool, RunContextWrapper, TContext, OpenAIChatCompletionsModel, set_default_openai_client, set_default_openai_api, set_tracing_disabled -from capi import COPILOT_INTEGRATION_ID, COPILOT_API_ENDPOINT +from .capi import COPILOT_INTEGRATION_ID, COPILOT_API_ENDPOINT # grab our secrets from .env, this must be in .gitignore load_dotenv() diff --git a/available_tools.py b/src/seclab_taskflow_agent/available_tools.py similarity index 87% rename from available_tools.py rename to src/seclab_taskflow_agent/available_tools.py index 4a8276ed..3750b0d4 100644 --- a/available_tools.py +++ b/src/seclab_taskflow_agent/available_tools.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + from enum import Enum import logging import importlib.resources @@ -52,16 +55,14 @@ def get_tool(self, tooltype: AvailableToolType, toolname: str): return self.__yamlcache[tooltype][toolname] except KeyError: pass - # Split the string to get the path and filename. + # Split the string to get the package and filename. components = toolname.rsplit('.', 1) - if len(components) == 2: - path = components[0] - filename = components[1] - else: - path = '' - filename = toolname + if len(components) != 2: + raise BadToolNameError(f'Not a valid toolname: "{toolname}". It should be something like: "packagename.filename"') + package = components[0] + filename = components[1] try: - d = importlib.resources.files(path) + d = importlib.resources.files(package) if not d.is_dir(): raise BadToolNameError(f'Cannot load {toolname} because {d} is not a valid directory.') f = d.joinpath(filename + ".yaml") diff --git a/capi.py b/src/seclab_taskflow_agent/capi.py similarity index 97% rename from capi.py rename to src/seclab_taskflow_agent/capi.py index 0b37be53..735dd9a3 100644 --- a/capi.py +++ b/src/seclab_taskflow_agent/capi.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + # CAPI specific interactions import httpx import json diff --git a/env_utils.py b/src/seclab_taskflow_agent/env_utils.py similarity index 91% rename from env_utils.py rename to src/seclab_taskflow_agent/env_utils.py index 669d48e8..39a28b61 100644 --- a/env_utils.py +++ b/src/seclab_taskflow_agent/env_utils.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import re import os diff --git a/mcp_servers/codeql/client.py b/src/seclab_taskflow_agent/mcp_servers/codeql/client.py similarity index 99% rename from mcp_servers/codeql/client.py rename to src/seclab_taskflow_agent/mcp_servers/codeql/client.py index 3d3c0592..5ef775de 100644 --- a/mcp_servers/codeql/client.py +++ b/src/seclab_taskflow_agent/mcp_servers/codeql/client.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + # a query-server2 codeql client import subprocess import re @@ -11,7 +14,7 @@ import yaml # this is a local fork of https://github.com/riga/jsonrpyc modified for our purposes -import jsonrpyc +from . import jsonrpyc WAIT_INTERVAL = 0.1 diff --git a/mcp_servers/codeql/jsonrpyc/LICENSE b/src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/LICENSE similarity index 100% rename from mcp_servers/codeql/jsonrpyc/LICENSE rename to src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/LICENSE diff --git a/mcp_servers/codeql/jsonrpyc/__init__.py b/src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/__init__.py similarity index 99% rename from mcp_servers/codeql/jsonrpyc/__init__.py rename to src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/__init__.py index 384dfc29..b3d6e974 100644 --- a/mcp_servers/codeql/jsonrpyc/__init__.py +++ b/src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/__init__.py @@ -16,7 +16,7 @@ from typing_extensions import TypeAlias # package infos -from jsonrpyc.__meta__ import ( # noqa +from .__meta__ import ( # noqa __doc__, __author__, __email__, @@ -749,7 +749,7 @@ def run(self) -> None: try: line = self.rpc.stdin.readline() except IOError: - pass + line = None if line: decoded_line = line.decode('utf-8').strip() diff --git a/mcp_servers/codeql/jsonrpyc/__meta__.py b/src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/__meta__.py similarity index 100% rename from mcp_servers/codeql/jsonrpyc/__meta__.py rename to src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/__meta__.py diff --git a/mcp_servers/codeql/jsonrpyc/py.typed b/src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/py.typed similarity index 100% rename from mcp_servers/codeql/jsonrpyc/py.typed rename to src/seclab_taskflow_agent/mcp_servers/codeql/jsonrpyc/py.typed diff --git a/mcp_servers/codeql/mcp_server.py b/src/seclab_taskflow_agent/mcp_servers/codeql/mcp_server.py similarity index 98% rename from mcp_servers/codeql/mcp_server.py rename to src/seclab_taskflow_agent/mcp_servers/codeql/mcp_server.py index c4717174..d692bdc5 100644 --- a/mcp_servers/codeql/mcp_server.py +++ b/src/seclab_taskflow_agent/mcp_servers/codeql/mcp_server.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import logging logging.basicConfig( level=logging.DEBUG, @@ -5,7 +8,7 @@ filename='logs/mcp_codeql.log', filemode='a' ) -from client import run_query, file_from_uri, list_src_files, _debug_log, search_in_src_archive +from .client import run_query, file_from_uri, list_src_files, _debug_log, search_in_src_archive from pydantic import Field #from mcp.server.fastmcp import FastMCP, Context from fastmcp import FastMCP, Context # use FastMCP 2.0 diff --git a/mcp_servers/codeql/queries/README.md b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/README.md similarity index 100% rename from mcp_servers/codeql/queries/README.md rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/README.md diff --git a/mcp_servers/codeql/queries/mcp-cpp/absolute_to_relative.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/absolute_to_relative.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/absolute_to_relative.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/absolute_to_relative.ql diff --git a/mcp_servers/codeql/queries/mcp-cpp/call_graph_from.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/call_graph_from.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/call_graph_from.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/call_graph_from.ql diff --git a/mcp_servers/codeql/queries/mcp-cpp/call_graph_from_to.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/call_graph_from_to.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/call_graph_from_to.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/call_graph_from_to.ql diff --git a/mcp_servers/codeql/queries/mcp-cpp/call_graph_to.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/call_graph_to.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/call_graph_to.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/call_graph_to.ql diff --git a/mcp_servers/codeql/queries/mcp-cpp/codeql-pack.lock.yml b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/codeql-pack.lock.yml similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/codeql-pack.lock.yml rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/codeql-pack.lock.yml diff --git a/mcp_servers/codeql/queries/mcp-cpp/declaration_location_for_variable.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/declaration_location_for_variable.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/declaration_location_for_variable.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/declaration_location_for_variable.ql diff --git a/mcp_servers/codeql/queries/mcp-cpp/definition_location_for_function.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/definition_location_for_function.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/definition_location_for_function.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/definition_location_for_function.ql diff --git a/mcp_servers/codeql/queries/mcp-cpp/list_functions.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/list_functions.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/list_functions.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/list_functions.ql diff --git a/mcp_servers/codeql/queries/mcp-cpp/locations.qll b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/locations.qll similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/locations.qll rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/locations.qll diff --git a/mcp_servers/codeql/queries/mcp-cpp/qlpack.yml b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/qlpack.yml similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/qlpack.yml rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/qlpack.yml diff --git a/mcp_servers/codeql/queries/mcp-cpp/relative_to_absolute.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/relative_to_absolute.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/relative_to_absolute.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/relative_to_absolute.ql diff --git a/mcp_servers/codeql/queries/mcp-cpp/stmt_location.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/stmt_location.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-cpp/stmt_location.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-cpp/stmt_location.ql diff --git a/mcp_servers/codeql/queries/mcp-js/absolute_to_relative.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/absolute_to_relative.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-js/absolute_to_relative.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/absolute_to_relative.ql diff --git a/mcp_servers/codeql/queries/mcp-js/call_graph_from.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/call_graph_from.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-js/call_graph_from.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/call_graph_from.ql diff --git a/mcp_servers/codeql/queries/mcp-js/call_graph_to.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/call_graph_to.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-js/call_graph_to.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/call_graph_to.ql diff --git a/mcp_servers/codeql/queries/mcp-js/definition_location_for_function.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/definition_location_for_function.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-js/definition_location_for_function.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/definition_location_for_function.ql diff --git a/mcp_servers/codeql/queries/mcp-js/locations.qll b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/locations.qll similarity index 100% rename from mcp_servers/codeql/queries/mcp-js/locations.qll rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/locations.qll diff --git a/mcp_servers/codeql/queries/mcp-js/qlpack.yml b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/qlpack.yml similarity index 100% rename from mcp_servers/codeql/queries/mcp-js/qlpack.yml rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/qlpack.yml diff --git a/mcp_servers/codeql/queries/mcp-js/relative_to_absolute.ql b/src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/relative_to_absolute.ql similarity index 100% rename from mcp_servers/codeql/queries/mcp-js/relative_to_absolute.ql rename to src/seclab_taskflow_agent/mcp_servers/codeql/queries/mcp-js/relative_to_absolute.ql diff --git a/mcp_servers/echo/echo.py b/src/seclab_taskflow_agent/mcp_servers/echo/echo.py similarity index 92% rename from mcp_servers/echo/echo.py rename to src/seclab_taskflow_agent/mcp_servers/echo/echo.py index e0bb5a6e..56671377 100644 --- a/mcp_servers/echo/echo.py +++ b/src/seclab_taskflow_agent/mcp_servers/echo/echo.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import logging logging.basicConfig( level=logging.DEBUG, diff --git a/mcp_servers/logbook/logbook.py b/src/seclab_taskflow_agent/mcp_servers/logbook/logbook.py similarity index 97% rename from mcp_servers/logbook/logbook.py rename to src/seclab_taskflow_agent/mcp_servers/logbook/logbook.py index c4ad5971..67b8c8f0 100644 --- a/mcp_servers/logbook/logbook.py +++ b/src/seclab_taskflow_agent/mcp_servers/logbook/logbook.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import logging logging.basicConfig( level=logging.DEBUG, diff --git a/src/seclab_taskflow_agent/mcp_servers/memcache/__init__.py b/src/seclab_taskflow_agent/mcp_servers/memcache/__init__.py new file mode 100644 index 00000000..1710739e --- /dev/null +++ b/src/seclab_taskflow_agent/mcp_servers/memcache/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT diff --git a/mcp_servers/memcache/memcache.py b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache.py similarity index 91% rename from mcp_servers/memcache/memcache.py rename to src/seclab_taskflow_agent/mcp_servers/memcache/memcache.py index 1c8eac86..1a527fb3 100644 --- a/mcp_servers/memcache/memcache.py +++ b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import logging logging.basicConfig( level=logging.DEBUG, @@ -11,8 +14,8 @@ from pathlib import Path import os from typing import Any -from memcache_backend.dictionary_file import MemcacheDictionaryFileBackend -from memcache_backend.sqlite import SqliteBackend +from .memcache_backend.dictionary_file import MemcacheDictionaryFileBackend +from .memcache_backend.sqlite import SqliteBackend mcp = FastMCP("Memcache") diff --git a/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/__init__.py b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/__init__.py new file mode 100644 index 00000000..1710739e --- /dev/null +++ b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT diff --git a/mcp_servers/memcache/memcache_backend/backend.py b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/backend.py similarity index 83% rename from mcp_servers/memcache/memcache_backend/backend.py rename to src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/backend.py index 8bccbd94..cff00a5d 100644 --- a/mcp_servers/memcache/memcache_backend/backend.py +++ b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/backend.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + from typing import Any class Backend: @@ -17,4 +20,4 @@ def list_keys(self) -> str: pass def clear_cache(self) -> str: - pass \ No newline at end of file + pass diff --git a/mcp_servers/memcache/memcache_backend/dictionary_file.py b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/dictionary_file.py similarity index 96% rename from mcp_servers/memcache/memcache_backend/dictionary_file.py rename to src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/dictionary_file.py index 3238a43b..9c7a575c 100644 --- a/mcp_servers/memcache/memcache_backend/dictionary_file.py +++ b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/dictionary_file.py @@ -1,4 +1,7 @@ -from memcache_backend.backend import Backend +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + +from .backend import Backend import json from pathlib import Path from typing import Any @@ -96,4 +99,4 @@ def clear_cache(self): def _clear_cache() -> str: self.memcache = {} return "Memory cache was cleared, all previous key lists are invalidated." - return _clear_cache() \ No newline at end of file + return _clear_cache() diff --git a/mcp_servers/memcache/memcache_backend/sql_models.py b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/sql_models.py similarity index 87% rename from mcp_servers/memcache/memcache_backend/sql_models.py rename to src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/sql_models.py index 16348754..baf8a2e6 100644 --- a/mcp_servers/memcache/memcache_backend/sql_models.py +++ b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/sql_models.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + from sqlalchemy import String, Text, Integer, ForeignKey, Column from sqlalchemy.orm import DeclarativeBase, mapped_column, Mapped, relationship from typing import Optional @@ -13,4 +16,4 @@ class KeyValue(Base): value: Mapped[str] = mapped_column(Text) def __repr__(self): - return f"" \ No newline at end of file + return f"" diff --git a/mcp_servers/memcache/memcache_backend/sqlite.py b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/sqlite.py similarity index 95% rename from mcp_servers/memcache/memcache_backend/sqlite.py rename to src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/sqlite.py index 10dadc1b..f0dd3893 100644 --- a/mcp_servers/memcache/memcache_backend/sqlite.py +++ b/src/seclab_taskflow_agent/mcp_servers/memcache/memcache_backend/sqlite.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import os from pathlib import Path from sqlalchemy import create_engine @@ -5,8 +8,8 @@ from typing import Any import json -from memcache_backend.sql_models import KeyValue, Base -from memcache_backend.backend import Backend +from .sql_models import KeyValue, Base +from .backend import Backend class SqliteBackend(Backend): def __init__(self, memcache_state_dir: str): diff --git a/mcp_utils.py b/src/seclab_taskflow_agent/mcp_utils.py similarity index 99% rename from mcp_utils.py rename to src/seclab_taskflow_agent/mcp_utils.py index 6dca9057..87e6d850 100644 --- a/mcp_utils.py +++ b/src/seclab_taskflow_agent/mcp_utils.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import logging import asyncio from threading import Thread, Event @@ -15,8 +18,8 @@ from mcp.types import CallToolResult, TextContent from agents.mcp import MCPServerStdio -from env_utils import swap_env -from available_tools import AvailableToolType, AvailableTools +from .env_utils import swap_env +from .available_tools import AvailableToolType, AvailableTools DEFAULT_MCP_CLIENT_SESSION_TIMEOUT = 120 diff --git a/personalities/assistant.yaml b/src/seclab_taskflow_agent/personalities/assistant.yaml similarity index 100% rename from personalities/assistant.yaml rename to src/seclab_taskflow_agent/personalities/assistant.yaml diff --git a/personalities/c_auditer.yaml b/src/seclab_taskflow_agent/personalities/c_auditer.yaml similarity index 85% rename from personalities/c_auditer.yaml rename to src/seclab_taskflow_agent/personalities/c_auditer.yaml index 004e53b4..7f56b40d 100644 --- a/personalities/c_auditer.yaml +++ b/src/seclab_taskflow_agent/personalities/c_auditer.yaml @@ -14,5 +14,5 @@ task: | your findings where possible. toolboxes: - - toolboxes.memcache - - toolboxes.codeql + - seclab_taskflow_agent.toolboxes.memcache + - seclab_taskflow_agent.toolboxes.codeql diff --git a/render_utils.py b/src/seclab_taskflow_agent/render_utils.py similarity index 94% rename from render_utils.py rename to src/seclab_taskflow_agent/render_utils.py index 07de660d..cbf09770 100644 --- a/render_utils.py +++ b/src/seclab_taskflow_agent/render_utils.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import asyncio async_output = {} diff --git a/shell_utils.py b/src/seclab_taskflow_agent/shell_utils.py similarity index 94% rename from shell_utils.py rename to src/seclab_taskflow_agent/shell_utils.py index 07f00760..ad8e40d9 100644 --- a/shell_utils.py +++ b/src/seclab_taskflow_agent/shell_utils.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + import subprocess import tempfile import logging diff --git a/toolboxes/codeql.yaml b/src/seclab_taskflow_agent/toolboxes/codeql.yaml similarity index 97% rename from toolboxes/codeql.yaml rename to src/seclab_taskflow_agent/toolboxes/codeql.yaml index 1ea8dd88..dcd34f80 100644 --- a/toolboxes/codeql.yaml +++ b/src/seclab_taskflow_agent/toolboxes/codeql.yaml @@ -7,7 +7,7 @@ server_params: url: 'http://localhost:9999/mcp' # if you set a command/args/env we will also start the server on demand command: python - args: ["mcp_servers/codeql/mcp_server.py"] + args: ["-m", "seclab_taskflow_agent.mcp_servers.codeql.mcp_server"] env: CODEQL_DBS_BASE_PATH: "{{ env CODEQL_DBS_BASE_PATH }}" # prevent git repo operations on gh codeql executions diff --git a/toolboxes/echo.yaml b/src/seclab_taskflow_agent/toolboxes/echo.yaml similarity index 57% rename from toolboxes/echo.yaml rename to src/seclab_taskflow_agent/toolboxes/echo.yaml index 90327249..23ce5bfb 100644 --- a/toolboxes/echo.yaml +++ b/src/seclab_taskflow_agent/toolboxes/echo.yaml @@ -1,3 +1,4 @@ +# stdio mcp server configuration seclab-taskflow-agent: version: 1 filetype: toolbox @@ -5,7 +6,6 @@ seclab-taskflow-agent: server_params: kind: stdio command: python - args: - - mcp_servers/echo/echo.py + args: ["-m", "seclab_taskflow_agent.mcp_servers.echo.echo"] env: TEST: value diff --git a/toolboxes/github_official.yaml b/src/seclab_taskflow_agent/toolboxes/github_official.yaml similarity index 100% rename from toolboxes/github_official.yaml rename to src/seclab_taskflow_agent/toolboxes/github_official.yaml diff --git a/toolboxes/logbook.yaml b/src/seclab_taskflow_agent/toolboxes/logbook.yaml similarity index 84% rename from toolboxes/logbook.yaml rename to src/seclab_taskflow_agent/toolboxes/logbook.yaml index f2c4dfe3..8cb8f674 100644 --- a/toolboxes/logbook.yaml +++ b/src/seclab_taskflow_agent/toolboxes/logbook.yaml @@ -5,8 +5,7 @@ seclab-taskflow-agent: server_params: kind: stdio command: python - args: - - mcp_servers/logbook/logbook.py + args: ["-m", "seclab_taskflow_agent.mcp_servers.logbook.logbook"] env: LOGBOOK_STATE_DIR: "{{ env LOGBOOK_STATE_DIR }}" # the list of tools that you want the framework to confirm with the user before executing diff --git a/toolboxes/memcache.yaml b/src/seclab_taskflow_agent/toolboxes/memcache.yaml similarity index 85% rename from toolboxes/memcache.yaml rename to src/seclab_taskflow_agent/toolboxes/memcache.yaml index 6105461e..9a4be464 100644 --- a/toolboxes/memcache.yaml +++ b/src/seclab_taskflow_agent/toolboxes/memcache.yaml @@ -5,8 +5,7 @@ seclab-taskflow-agent: server_params: kind: stdio command: python - args: - - mcp_servers/memcache/memcache.py + args: ["-m", "seclab_taskflow_agent.mcp_servers.memcache.memcache"] env: MEMCACHE_STATE_DIR: "{{ env MEMCACHE_STATE_DIR }}" MEMCACHE_BACKEND: "{{ env MEMCACHE_BACKEND }}" diff --git a/tests/__init__.py b/tests/__init__.py index 83922b0f..d95d22b9 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1 +1,4 @@ -# this file makes the tests directory a Python package \ No newline at end of file +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + +# this file makes the tests directory a Python package diff --git a/tests/test_yaml_parser.py b/tests/test_yaml_parser.py index 8bcde744..743937b4 100644 --- a/tests/test_yaml_parser.py +++ b/tests/test_yaml_parser.py @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: 2025 GitHub +# SPDX-License-Identifier: MIT + """ Basic tests for YAML parsing functionality in the taskflow agent. @@ -8,7 +11,7 @@ import tempfile from pathlib import Path import yaml -from available_tools import AvailableTools +from seclab_taskflow_agent.available_tools import AvailableTools class TestYamlParser: """Test suite for YamlParser class.""" @@ -34,7 +37,7 @@ def test_parse_example_taskflows(self): # check that example.yaml is parsed correctly example_task_flow = available_tools.get_taskflow( - "taskflows.examples.example") + "examples.taskflows.example") assert 'taskflow' in example_task_flow assert isinstance(example_task_flow['taskflow'], list) assert len(example_task_flow['taskflow']) == 4 # 4 tasks in taskflow