Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ result/

.cursor/
.claude/

# Temp iii config files generated by bbdev script mode
api/iii-config-*.yaml
api/data/
60 changes: 60 additions & 0 deletions api/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
port: 49134

modules:
# ── Worker Module ──────────────────────────────────────────────────────
- class: modules::worker::WorkerModule
config:
port: 49134

# ── State Module ───────────────────────────────────────────────────────
- class: modules::state::StateModule
config:
adapter:
class: modules::state::adapters::KvStore
config:
store_method: file_based
file_path: ./data/state_store.db

# ── REST API Module ────────────────────────────────────────────────────
- class: modules::api::RestApiModule
config:
port: 3111
host: 0.0.0.0
default_timeout: 86400000
concurrency_request_limit: 1024
cors:
allowed_origins:
- http://localhost:3000
- http://localhost:5173
allowed_methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS

# ── Queue Module ───────────────────────────────────────────────────────
- class: modules::queue::QueueModule
config:
adapter:
class: modules::queue::BuiltinQueueAdapter

# ── PubSub Module ──────────────────────────────────────────────────────
- class: modules::pubsub::PubSubModule
config:
adapter:
class: modules::pubsub::LocalAdapter

# ── Observability Module ───────────────────────────────────────────────
- class: modules::observability::OtelModule
config:
enabled: true
exporter: memory

# ── Exec Module (Python) ───────────────────────────────────────────────
- class: modules::shell::ExecModule
config:
watch:
- steps/**/*.py
exec:
- PYTHONUNBUFFERED=1 PYTHONPATH=. .venv/bin/motia dev --dir steps
13 changes: 13 additions & 0 deletions api/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[project]
name = "bbdev"
version = "0.1.0"
description = "Agent-friendly developer toolchain backend powered by Motia"
requires-python = ">=3.10"
dependencies = [
"motia[otel]==1.0.0rc17",
"iii-sdk==0.2.0",
"pydantic>=2.0",
]

[project.optional-dependencies]
dev = ["pytest>=8.0.0"]
15 changes: 15 additions & 0 deletions api/steps/compiler/01_build_api.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from motia import ApiRequest, ApiResponse, FlowContext, api

config = {
"name": "build-compiler-api",
"description": "build compiler",
"flows": ["compiler"],
"triggers": [api("POST", "/compiler/build")],
"enqueues": ["compiler.build"],
}


async def handler(request: ApiRequest, ctx: FlowContext) -> ApiResponse:
body = request.body or {}
await ctx.enqueue({"topic": "compiler.build", "data": {**body, "_trace_id": ctx.trace_id}})
return ApiResponse(status=202, body={"trace_id": ctx.trace_id})
56 changes: 56 additions & 0 deletions api/steps/compiler/01_build_event.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import os
import sys

from motia import FlowContext, queue

# Add the utils directory to the Python path
utils_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
if utils_path not in sys.path:
sys.path.insert(0, utils_path)

from utils.path import get_buckyball_path
from utils.stream_run import stream_run_logger
from utils.event_common import check_result, get_origin_trace_id

config = {
"name": "build-compiler",
"description": "build compiler",
"flows": ["compiler"],
"triggers": [queue("compiler.build")],
"enqueues": [],
}


async def handler(input_data: dict, ctx: FlowContext) -> None:
origin_tid = get_origin_trace_id(input_data, ctx)
bbdir = get_buckyball_path()
script_dir = f"{bbdir}/workflow/steps/compiler/scripts"
yaml_dir = f"{script_dir}/yaml"
# ==================================================================================
# Execute operation
# ==================================================================================
command = f"mkdir -p {bbdir}/compiler/build"
result = stream_run_logger(
cmd=command,
logger=ctx.logger,
stdout_prefix="compiler build",
stderr_prefix="compiler build",
)
command = f"cd {bbdir}/compiler/build && ninja -j{os.cpu_count()}"
result = stream_run_logger(
cmd=command,
logger=ctx.logger,
stdout_prefix="compiler build",
stderr_prefix="compiler build",
)

# ==================================================================================
# Return result to API
# ==================================================================================
success_result, failure_result = await check_result(
ctx, result.returncode, continue_run=False, trace_id=origin_tid)

# ==================================================================================
# Continue routing
# ==================================================================================
return
15 changes: 15 additions & 0 deletions api/steps/firesim/01_buildbitstream_api.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from motia import ApiRequest, ApiResponse, FlowContext, api

config = {
"name": "firesim-buildbitstream-api",
"description": "build bitstream",
"flows": ["firesim"],
"triggers": [api("POST", "/firesim/buildbitstream")],
"enqueues": ["firesim.buildbitstream"],
}


async def handler(request: ApiRequest, ctx: FlowContext) -> ApiResponse:
body = request.body or {}
await ctx.enqueue({"topic": "firesim.buildbitstream", "data": {**body, "_trace_id": ctx.trace_id}})
return ApiResponse(status=202, body={"trace_id": ctx.trace_id})
54 changes: 54 additions & 0 deletions api/steps/firesim/01_buildbitstream_event.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os
import sys

from motia import FlowContext, queue

# Add the utils directory to the Python path
utils_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
if utils_path not in sys.path:
sys.path.insert(0, utils_path)

from utils.path import get_buckyball_path
from utils.stream_run import stream_run_logger
from utils.event_common import check_result, get_origin_trace_id

config = {
"name": "firesim-buildbitstream",
"description": "build bitstream",
"flows": ["firesim"],
"triggers": [queue("firesim.buildbitstream")],
"enqueues": [],
}


async def handler(input_data: dict, ctx: FlowContext) -> None:
origin_tid = get_origin_trace_id(input_data, ctx)
bbdir = get_buckyball_path()
script_dir = f"{bbdir}/workflow/steps/firesim/scripts"
yaml_dir = f"{script_dir}/yaml"
# ==================================================================================
# Execute operation
# ==================================================================================
command = f"firesim buildbitstream "
command += f" -a {yaml_dir}/config_hwdb.yaml"
command += f" -b {yaml_dir}/config_build.yaml"
command += f" -r {yaml_dir}/config_build_recipes.yaml"
command += f" -c {yaml_dir}/config_runtime.yaml"
result = stream_run_logger(
cmd=command,
logger=ctx.logger,
stdout_prefix="firesim buildbitstream",
stderr_prefix="firesim buildbitstream",
)

# ==================================================================================
# Return result to API
# ==================================================================================
success_result, failure_result = await check_result(
ctx, result.returncode, continue_run=False, trace_id=origin_tid)

# ==================================================================================
# Continue routing
# ==================================================================================

return
16 changes: 16 additions & 0 deletions api/steps/firesim/02_infrasetup_api.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from motia import ApiRequest, ApiResponse, FlowContext, api

config = {
"name": "firesim-infrasetup-api",
"description": "infrasetup",
"flows": ["firesim"],
"triggers": [api("POST", "/firesim/infrasetup")],
"enqueues": ["firesim.infrasetup"],
}


async def handler(request: ApiRequest, ctx: FlowContext) -> ApiResponse:
body = request.body or {}
data = {"jobs": body.get("jobs", 16)}
await ctx.enqueue({"topic": "firesim.infrasetup", "data": {**data, "_trace_id": ctx.trace_id}})
return ApiResponse(status=202, body={"trace_id": ctx.trace_id})
54 changes: 54 additions & 0 deletions api/steps/firesim/02_infrasetup_event.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os
import sys

from motia import FlowContext, queue

# Add the utils directory to the Python path
utils_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
if utils_path not in sys.path:
sys.path.insert(0, utils_path)

from utils.path import get_buckyball_path
from utils.stream_run import stream_run_logger
from utils.event_common import check_result, get_origin_trace_id

config = {
"name": "firesim-infrasetup",
"description": "infrasetup",
"flows": ["firesim"],
"triggers": [queue("firesim.infrasetup")],
"enqueues": [],
}


async def handler(input_data: dict, ctx: FlowContext) -> None:
origin_tid = get_origin_trace_id(input_data, ctx)
bbdir = get_buckyball_path()
script_dir = f"{bbdir}/workflow/steps/firesim/scripts"
yaml_dir = f"{script_dir}/yaml"
# ==================================================================================
# Execute operation
# ==================================================================================
command = f"firesim infrasetup "
command += f" -a {yaml_dir}/config_hwdb.yaml"
command += f" -b {yaml_dir}/config_build.yaml"
command += f" -r {yaml_dir}/config_build_recipes.yaml"
command += f" -c {yaml_dir}/config_runtime.yaml"
result = stream_run_logger(
cmd=command,
logger=ctx.logger,
stdout_prefix="firesim infrasetup",
stderr_prefix="firesim infrasetup",
)

# ==================================================================================
# Return result to API
# ==================================================================================
success_result, failure_result = await check_result(
ctx, result.returncode, continue_run=False, trace_id=origin_tid)

# ==================================================================================
# Continue routing
# ==================================================================================

return
16 changes: 16 additions & 0 deletions api/steps/firesim/03_runworkload_api.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from motia import ApiRequest, ApiResponse, FlowContext, api

config = {
"name": "firesim-runworkload-api",
"description": "run workload",
"flows": ["firesim"],
"triggers": [api("POST", "/firesim/runworkload")],
"enqueues": ["firesim.runworkload"],
}


async def handler(request: ApiRequest, ctx: FlowContext) -> ApiResponse:
body = request.body or {}
data = {"jobs": body.get("jobs", 16)}
await ctx.enqueue({"topic": "firesim.runworkload", "data": {**data, "_trace_id": ctx.trace_id}})
return ApiResponse(status=202, body={"trace_id": ctx.trace_id})
54 changes: 54 additions & 0 deletions api/steps/firesim/03_runworkload_event.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os
import sys

from motia import FlowContext, queue

# Add the utils directory to the Python path
utils_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
if utils_path not in sys.path:
sys.path.insert(0, utils_path)

from utils.path import get_buckyball_path
from utils.stream_run import stream_run_logger
from utils.event_common import check_result, get_origin_trace_id

config = {
"name": "firesim-runworkload",
"description": "run workload",
"flows": ["firesim"],
"triggers": [queue("firesim.runworkload")],
"enqueues": [],
}


async def handler(input_data: dict, ctx: FlowContext) -> None:
origin_tid = get_origin_trace_id(input_data, ctx)
bbdir = get_buckyball_path()
script_dir = f"{bbdir}/workflow/steps/firesim/scripts"
yaml_dir = f"{script_dir}/yaml"
# ==================================================================================
# Execute operation
# ==================================================================================
command = f"firesim runworkload "
command += f" -a {yaml_dir}/config_hwdb.yaml"
command += f" -b {yaml_dir}/config_build.yaml"
command += f" -r {yaml_dir}/config_build_recipes.yaml"
command += f" -c {yaml_dir}/config_runtime.yaml"
result = stream_run_logger(
cmd=command,
logger=ctx.logger,
stdout_prefix="firesim runworkload",
stderr_prefix="firesim runworkload",
)

# ==================================================================================
# Return result to API
# ==================================================================================
success_result, failure_result = await check_result(
ctx, result.returncode, continue_run=False, trace_id=origin_tid)

# ==================================================================================
# Continue routing
# ==================================================================================

return
15 changes: 15 additions & 0 deletions api/steps/marshal/01_build_api.step.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from motia import ApiRequest, ApiResponse, FlowContext, api

config = {
"name": "marshal-build-api",
"description": "build marshal",
"flows": ["marshal"],
"triggers": [api("POST", "/marshal/build")],
"enqueues": ["marshal.build"],
}


async def handler(request: ApiRequest, ctx: FlowContext) -> ApiResponse:
body = request.body or {}
await ctx.enqueue({"topic": "marshal.build", "data": {**body, "_trace_id": ctx.trace_id}})
return ApiResponse(status=202, body={"trace_id": ctx.trace_id})
Loading
Loading