You can embed the orchestrator in your own scripts.
import anyio
from pathlib import Path
from quick_agent.directory_permissions import DirectoryPermissions
from quick_agent.orchestrator import Orchestrator
agent_roots = [Path("agents")]
tool_roots = [Path("tools")]
permissions = DirectoryPermissions(Path("safe"))
orchestrator = Orchestrator(agent_roots, tool_roots, directory_permissions=permissions)
async def main() -> None:
result = await orchestrator.run_agent("example", Path("input.txt"))
print(result)
anyio.run(main)Use the agent_call tool name in your agent front matter, then invoke the tool by its function name agent_call from the prompt.
Example agent pair:
agents/child.md:
---
name: "Child Agent"
chain:
- id: respond
kind: text
prompt_section: step:respond
output:
format: json
file: out/child.json
---
## step:respond
Reply with exactly: pongagents/parent.md:
---
name: "Parent Agent"
tools:
- "agent_call"
chain:
- id: invoke
kind: text
prompt_section: step:invoke
output:
format: json
file: out/parent.json
---
## step:invoke
Call agent_call with agent "child" and input_file "{base_directory}/child_input.txt".
Then respond with only the returned text value.input/child_input.txt:
ignored
Then run:
python agent.py --agent parent --input input/parent_input.txtExpected output: pong
By default, when an agent is invoked via agent_call or via handoff, the nested agent does not write its own
output.file. Only the top-level agent run writes to its configured output path. The nested agent still returns
its output to the caller.
You can opt into file outputs for nested agents by setting nested_output: file in the parent agent front matter.
Instead of referencing a file, pass inline text directly:
## step:invoke
Call agent_call with agent "child" and input_text "hello from memory".
Then respond with only the returned text value.This uses the same agent_call tool but avoids creating a temporary input file.
The orchestrator can accept either a file path or an input adaptor instance.
Use FileInput when your input comes from a file and should be validated against the safe directory at creation time.
from pathlib import Path
from quick_agent import FileInput
from quick_agent import Orchestrator
safe_root = Path("safe")
orchestrator = Orchestrator([Path("agents")], [Path("tools")], safe_dir=safe_root)
input_adaptor = FileInput(Path("safe/input.txt"), orchestrator.directory_permissions)
result = await orchestrator.run("example", input_adaptor)Use TextInput for inline strings. No permissions are required.
from pathlib import Path
from quick_agent import Orchestrator
from quick_agent import TextInput
orchestrator = Orchestrator([Path("agents")], [Path("tools")], safe_dir=Path("safe"))
input_adaptor = TextInput("hello from memory")
result = await orchestrator.run("example", input_adaptor)- If the orchestrator safe dir is
None, all reads and writes are denied. FileInputperforms its permission check at construction time.TextInputnever touches the filesystem and is always allowed.
When installed as a module, packaged system assets live inside the
quick_agent package. Use importlib.resources to locate them:
import anyio
from importlib.resources import files
from pathlib import Path
from quick_agent.directory_permissions import DirectoryPermissions
from quick_agent.orchestrator import Orchestrator
package_root = Path(files("quick_agent"))
agent_roots = [Path("agents"), package_root / "agents"]
tool_roots = [Path("tools"), package_root / "tools"]
permissions = DirectoryPermissions(Path("safe"))
orchestrator = Orchestrator(agent_roots, tool_roots, directory_permissions=permissions)
async def main() -> None:
result = await orchestrator.run_agent("example", Path("input.txt"))
print(result)
anyio.run(main)