From 75f6a6f9148004d024f442c6116f146405221293 Mon Sep 17 00:00:00 2001 From: Arron Bailiss Date: Sat, 30 May 2026 10:55:35 -0400 Subject: [PATCH] fix(strandly): fix bootstrap ordering and update README - Move `pip install -e strands-py-wasm/` after build step since it requires strands-agent.wasm to exist - Add pgrayy-wasmtime to root pyproject.toml deps so generate step has access to wasmtime.component.bindgen - Remove _generated/ before regenerating to avoid FileExistsError - Fix stale test imports (StreamEvent moved to types module) - Update strands-wasm/README.md to use strandly commands and correct paths --- pyproject.toml | 3 ++ strandly/src/cli.ts | 7 ++++- strands-py-wasm/tests/test_agent.py | 6 ++-- strands-wasm/README.md | 49 ++++++++++++++--------------- 4 files changed, 36 insertions(+), 29 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c8ba98c74e..3fd2dd8cdf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,9 @@ requires-python = ">=3.10" dependencies = [ # Build-time codegen: parses WIT and emits Python bindings. "componentize-py>=0.23.0,<1.0.0", + # Forked wasmtime-py with async component model support. + # Used by ``strandly generate`` (wasmtime.component.bindgen) and at runtime by strands-py-wasm. + "pgrayy-wasmtime @ git+https://github.com/pgrayy/wasm-deps.git@4b5dc41512109ebafe4c4f1edd592c739872c640#subdirectory=wasmtime-py", # Linter/formatter used by ``strandly check --py`` and ``strandly fmt``. "ruff>=0.13.0,<0.15.0", # Type checker used by ``strandly check --py``. diff --git a/strandly/src/cli.ts b/strandly/src/cli.ts index 181b19726d..b676a877bc 100755 --- a/strandly/src/cli.ts +++ b/strandly/src/cli.ts @@ -99,6 +99,7 @@ program linkCli() generate() build() + installPyWasm() test() }) @@ -183,10 +184,13 @@ function setup(opts?: { node?: boolean; python?: boolean }): void { if (all || opts?.python) { run('python3 -m venv .venv', { cwd: ROOT }) run(`${VENV}/bin/pip install -e .`, { cwd: ROOT }) - run(`${VENV}/bin/pip install -e strands-py-wasm/`, { cwd: ROOT }) } } +function installPyWasm(): void { + run(`${VENV}/bin/pip install -e strands-py-wasm/`, { cwd: ROOT }) +} + function linkCli(): void { run('npm link -w strandly') } @@ -250,6 +254,7 @@ function generate(opts?: { check?: boolean }): void { // Output is a package: one module per WIT interface plus an __init__.py. // The hand-written ``strands.types`` module re-exports the curated public // subset from this private ``_generated`` package. + run('rm -rf strands-py-wasm/src/strands/_generated') run(`${VENV}/bin/python -m wasmtime.component.bindgen wit -o strands-py-wasm/src/strands/_generated`) // Ensure TS + WASM are built first. diff --git a/strands-py-wasm/tests/test_agent.py b/strands-py-wasm/tests/test_agent.py index 777f3c5cd9..60c02cf653 100644 --- a/strands-py-wasm/tests/test_agent.py +++ b/strands-py-wasm/tests/test_agent.py @@ -1,6 +1,6 @@ import pytest -from strands import Agent, BedrockModel, StreamEvent, StreamEvent_Stop +from strands import Agent, BedrockModel, types @pytest.fixture @@ -16,6 +16,6 @@ def agent(model): @pytest.mark.asyncio async def test_stream_async_hello_world(agent): async for event in agent.stream_async("Say hello world"): - assert isinstance(event, StreamEvent) + assert isinstance(event, types.StreamEvent) - assert isinstance(event, StreamEvent_Stop) + assert isinstance(event, types.StreamEvent.Stop) diff --git a/strands-wasm/README.md b/strands-wasm/README.md index 681e7e5b90..3fecae4022 100644 --- a/strands-wasm/README.md +++ b/strands-wasm/README.md @@ -19,7 +19,6 @@ In WIT terminology, the WASM component is the "guest" and Python is the "host". - Node.js 20+ - Python 3.10+ -- [wasmtime-py](https://github.com/bytecodealliance/wasmtime-py) (forked build with async component model support) ### First-time setup @@ -30,7 +29,7 @@ npm install npm run dev -- bootstrap ``` -`bootstrap` installs toolchains, generates type bindings, builds all layers, and runs all tests. If this command doesn't enable development out of the box, file an issue. +`bootstrap` installs toolchains, links `strandly` to your PATH, generates type bindings, builds all layers, installs `strands-py-wasm`, and runs all tests. If this command doesn't enable development out of the box, file an issue. ## Architecture @@ -56,26 +55,25 @@ graph TD | `strands-ts/` | TypeScript | Agent runtime: event loop, model providers, tools, hooks, streaming | | `strands-wasm/` | TypeScript | Bridges the TS SDK to WIT exports, compiles to a WASM component | | `strands-py-wasm/` | Python | Python wrapper: Agent class, @tool decorator, direct WASM host | -| `strands-dev/` | TypeScript | Dev CLI that orchestrates build, test, lint, and CI | -| `dev-docs/` | Markdown | Design proposal and team decisions | +| `strandly/` | TypeScript | Dev CLI that orchestrates build, test, lint, and CI | +| `dev-docs/` | Markdown | Design proposals and team decisions | ### Generated code -`npm run dev -- generate` produces type bindings from `wit/agent.wit` into: +`strandly generate` produces type bindings from `wit/agent.wit` into: -- `strands-ts/generated/` -- `strands-wasm/generated/` +- `strands-ts/generated/` (gitignored) +- `strands-wasm/generated/` (gitignored) +- `strands-py-wasm/src/strands/_generated/` (committed) -Generated files are created by running `npm run dev -- generate` (or `bootstrap`) and are gitignored. Do not edit them by hand. CI runs `generate --check` and fails if they are stale. - -Python types are auto-generated into `strands-py-wasm/strands/_generated/types.py` by `strands-py-wasm/scripts/generate_types.py`. +Generated files are created by running `strandly generate` (or `bootstrap`). Do not edit them by hand. CI runs `strandly generate --check` and fails if they are stale. ### Tests | Layer | Framework | Location | | -------------- | --------- | ----------------------------------------------------------------- | | TypeScript SDK | vitest | `strands-ts/src/**/__tests__/` (unit), `strands-ts/test/` (integ) | -| Python wrapper | pytest | `strands-py-wasm/tests_integ/` | +| Python wrapper | pytest | `strands-py-wasm/tests/` | Add tests alongside the code you change. Bug fixes should include a test that reproduces the original issue. @@ -83,13 +81,13 @@ Add tests alongside the code you change. Bug fixes should include a test that re Each layer depends on the layers above it in the pipeline. The `validate` command rebuilds and tests exactly the layers your change affects. -| What you changed | Validate command | -| ------------------------------------- | ------------------------------------- | -| WIT contract (`wit/agent.wit`) | `npm run dev -- validate wit` | -| TS SDK internals | `npm run dev -- validate ts` | -| TS SDK public API | `npm run dev -- validate ts-api` | -| WASM bridge (`strands-wasm/entry.ts`) | `npm run dev -- validate wasm` | -| Pure Python (`strands-py-wasm/`) | `npm run dev -- validate py` | +| What you changed | Validate command | +| ------------------------------------- | ----------------------------- | +| WIT contract (`wit/agent.wit`) | `strandly validate wit` | +| TS SDK internals | `strandly validate ts` | +| TS SDK public API | `strandly validate ts-api` | +| WASM bridge (`strands-wasm/entry.ts`) | `strandly validate wasm` | +| Pure Python (`strands-py-wasm/`) | `strandly validate py` | **TS internals vs. public API:** The WASM bridge (`strands-wasm/entry.ts`) imports specific types and functions from `strands-ts/`. If your change modifies something the bridge imports, it is a public API change — use `validate ts-api`. If the bridge does not import it, use `validate ts`. @@ -98,19 +96,20 @@ Each layer depends on the layers above it in the pipeline. The `validate` comman ## Dev CLI ```bash -npm run dev -- [options] +strandly [options] ``` Most commands accept layer flags (`--ts`, `--wasm`, `--py`). No flags means all layers. | Command | What it does | | ------------------ | ---------------------------------------------------------------------- | -| `bootstrap` | First-time setup: install, generate, build, test | +| `bootstrap` | First-time setup: install, link, generate, build, install py-wasm, test | | `setup` | Install toolchains (`--node`, `--python`) | +| `link` | Install `strandly` on PATH as a live symlink to this repo | | `generate` | Regenerate type bindings from WIT (`--check`) | -| `build` | Compile layers (`--ts`, `--wasm`, `--py`, `--release`) | +| `build` | Compile layers (`--ts`, `--wasm`, `--py`) | | `test` | Run tests (`--py`, `--ts`, or a specific `[file]`) | -| `check` | Lint and type-check (`--ts`, `--py`) | +| `check` | Lint and type-check (`--ts`, `--wasm`, `--py`) | | `fmt` | Format all code (`--check` to verify without writing) | | `validate ` | Rebuild and test the layers affected by a change | | `ci` | Full pipeline: generate, format, lint, build, test | @@ -126,14 +125,14 @@ Most commands accept layer flags (`--ts`, `--wasm`, `--py`). No flags means all | Python | `ruff format` | `ruff check` | ```bash -npm run dev -- fmt # format everything -npm run dev -- check # lint everything +strandly fmt # format everything +strandly check # lint everything ``` Comments are normative statements that describe what code does or why a decision was made. Avoid TODO's without associated issues, notes-to-self, and parenthetical asides. ## Submitting a PR -- Run `npm run dev -- ci` before pushing. This is the same pipeline CI runs. +- Run `strandly ci` before pushing. This is the same pipeline CI runs. - Keep PRs focused on a single change. - Use conventional commit messages: `feat:`, `fix:`, `refactor:`, `docs:`, etc.