What You’ll Learn
- Implementing a Haystack
@component with component.output_types that runs Python in a Declaw sandbox
- Connecting the component in a Haystack
Pipeline alongside OpenAIGenerator and PromptBuilder
- Demo mode that exercises the component directly without needing an OpenAI key
Prerequisites
- Declaw instance running and
DECLAW_API_KEY / DECLAW_DOMAIN set
OPENAI_API_KEY (optional — the example runs in demo mode without it)
pip install declaw python-dotenv haystack-ai
This example is available in Python. TypeScript support coming soon.
Code Walkthrough
1. Define the DecawCodeRunner component
Use the @component decorator and declare output types with @component.output_types. The run() method receives typed inputs and returns a dict matching the declared output types:
from haystack import component
from declaw import Sandbox
@component
class DecawCodeRunner:
"""Haystack component that executes Python code in a Declaw sandbox."""
@component.output_types(output=str, exit_code=int)
def run(self, code: str) -> dict:
sbx = Sandbox.create(template="python", timeout=300)
try:
sbx.files.write("/tmp/code.py", code)
result = sbx.commands.run("python3 /tmp/code.py", timeout=30)
return {"output": result.stdout, "exit_code": result.exit_code}
finally:
sbx.kill()
The output and exit_code output names can be connected to downstream components in the pipeline by referencing code_runner.output and code_runner.exit_code.
2. Build a pipeline with an LLM and the code runner
from haystack import Pipeline
from haystack.components.generators import OpenAIGenerator
from haystack.components.builders.prompt_builder import PromptBuilder
template = (
"Write Python code (and nothing else) to solve: {{ query }}\n"
"Output only the Python code, no markdown fences."
)
pipeline = Pipeline()
pipeline.add_component("prompt_builder", PromptBuilder(template=template))
pipeline.add_component("llm", OpenAIGenerator(model="gpt-4o-mini"))
pipeline.add_component("code_runner", DecawCodeRunner())
pipeline.connect("prompt_builder", "llm")
pipeline.connect("llm.replies", "code_runner.code")
3. Run the pipeline
query = "Calculate the factorial of 15 and print it"
result = pipeline.run({"prompt_builder": {"query": query}})
print(result["code_runner"]["output"])
print(result["code_runner"]["exit_code"])
4. Demo mode (no API key needed)
Run the component directly without building a pipeline:
from declaw import Sandbox
code = """\
import math
n = 15
print(f"{n}! = {math.factorial(n)}")
"""
sbx = Sandbox.create(template="python", timeout=300)
try:
sbx.files.write("/tmp/code.py", code)
result = sbx.commands.run("python3 /tmp/code.py", timeout=30)
print(result.stdout)
finally:
sbx.kill()
Expected Output
In demo mode:
=======================================================
Haystack + Declaw Sandbox Example
=======================================================
No OPENAI_API_KEY found -- running demo mode.
--- Component Definition ---
@component
class DecawCodeRunner:
@component.output_types(output=str, exit_code=int)
def run(self, code: str) -> dict:
sbx = Sandbox.create(template="python", timeout=300)
...
--- Running Code Directly in Declaw Sandbox ---
Code:
import math
n = 15
print(f"{n}! = {math.factorial(n)}")
stdout: 15! = 1307674368000
stderr:
exit_code: 0
Sandbox cleaned up.
=======================================================
Done!
=======================================================