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
2 changes: 1 addition & 1 deletion .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ uv sync # create .venv + install runtime + dev de
.venv/bin/python -m pytest test/unit/cli/test_loader.py # one file
.venv/bin/python -m pytest test/unit/cli/test_loader.py::TestLoadAdapterClass # one class
.venv/bin/ruff check .
.venv/bin/black . # formatter gate (see .pre-commit-config.yaml)
.venv/bin/ruff format . # formatter gate (see .pre-commit-config.yaml)
.venv/bin/mypy agent_assembly # strict; type-check the package, not test/
.venv/bin/pre-commit run --all-files
```
Expand Down
41 changes: 9 additions & 32 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,39 +16,16 @@ repos:
- id: trailing-whitespace
- id: detect-private-key

- repo: https://github.com/PyCQA/isort
rev: 6.0.1
- repo: https://github.com/astral-sh/ruff-pre-commit
# Single Python formatter/linter (AAASM-4915): replaces the former
# isort + autoflake + black trio. `ruff-check --fix` folds in isort (rule
# `I`) and autoflake's unused-import/var removal (`F401`/`F841`); the shared
# ruff.toml is the source of truth for select/ignore/format config.
rev: v0.15.21
hooks:
- id: isort
args: # arguments to configure black
- --profile=black

- repo: https://github.com/PyCQA/autoflake
rev: v2.3.1
hooks:
- id: autoflake
args:
- --remove-all-unused-imports
- --ignore-init-module-imports
- --in-place

- repo: https://github.com/psf/black
rev: 25.1.0
hooks:
- id: black
args: # arguments to configure black
- --line-length=120
# these folders won't be formatted by black
- --exclude="""\.git |
\.__pycache__|
\**.egg-info|
\.mypy_cache|
\.pytest_cache|
\.tox|
\.venv|
_build|
build|
dist"""
- id: ruff-check
args: [--fix]
- id: ruff-format

- repo: local
hooks:
Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ cargo test --manifest-path native/aa-ffi-python/Cargo.toml

```bash
uv run ruff check . # lint (config: ruff.toml; line length 120, target py312)
uv run black . # auto-format (formatter gate; see .pre-commit-config.yaml)
uv run ruff format . # auto-format (formatter gate; see .pre-commit-config.yaml)
uv run mypy agent_assembly # type check (mypy.ini; strict on adapters.base/registry)
uv run pre-commit run --all-files # full pre-commit suite (isort + black + autoflake + mypy)
uv run pre-commit run --all-files # full pre-commit suite (ruff check + ruff format + mypy)
```

Pre-commit hooks block commits that fail any of the above. Do not bypass with `--no-verify`; fix the underlying issue.
Expand Down
2 changes: 1 addition & 1 deletion agent_assembly/cli/adapter_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def _check_entry_point_metadata(cls: type, path_or_module: str) -> AdapterValida
return AdapterValidationResult(
check_name="entry_point_metadata",
passed=False,
message=('pyproject.toml missing [project.entry-points."agent_assembly.adapters"] ' "section."),
message=('pyproject.toml missing [project.entry-points."agent_assembly.adapters"] section.'),
)

class_qualname = f"{cls.__module__}:{cls.__qualname__}"
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/authoring-adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ repos but should still meet this bar), confirm:
lifecycle (framework mocked).
- [ ] Integration test under `test/integration/adapters/<framework_name>/` exercises a minimal
real flow.
- [ ] `uv run ruff check .`, `uv run black --check .`, and `uv run mypy agent_assembly`
- [ ] `uv run ruff check .`, `uv run ruff format --check .`, and `uv run mypy agent_assembly`
are clean.
- [ ] Entry point declared in `pyproject.toml` under
`[project.entry-points."agent_assembly.adapters"]` (for standalone packages).
Expand Down
9 changes: 9 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ exclude = [
"dist",
"docs_with_docusarus",
"docs",
# AAASM-4915: vendored, verbatim quick-start excerpts (copied from
# ai-agent-assembly/examples; regenerated into docs/quick-start.md by the
# quickstart-tabs-check). Several are partial governance slices that are
# valid as doc excerpts but not standalone modules, so ruff can't lint or
# format them. The former black/isort/autoflake trio excluded this dir via
# the .pre-commit top-level `exclude`; keep that parity now that ruff is the
# single formatter/linter so the bare-CLI gates stay clean and the vendored
# copies are never rewritten.
"quickstart_snippets/",
# AAASM-4434: generated gRPC/protobuf stubs (scripts/gen_proto.py), committed
# verbatim; a CI drift check regenerates them and asserts no diff, so they
# must not be hand-edited to satisfy lint (mirrors the mypy.ini ignore for the
Expand Down
5 changes: 2 additions & 3 deletions scripts/generate_quickstart_tabs.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def build_block(vendor_dir: Path) -> str:
framework_id = entry["framework_id"]
snippet_path = vendor_dir / f"{framework_id}.py"
if not snippet_path.is_file():
raise GenerateError(f"manifest lists '{framework_id}' but its snippet is missing: " f"{snippet_path}")
raise GenerateError(f"manifest lists '{framework_id}' but its snippet is missing: {snippet_path}")
code = snippet_path.read_text(encoding="utf-8").rstrip("\n")
tabs.append(render_tab(entry["label"], code, entry.get("version_compat_note")))

Expand All @@ -115,8 +115,7 @@ def apply_block(doc_text: str, block: str) -> str:
end = doc_text.find(END_MARKER)
if start == -1 or end == -1:
raise GenerateError(
f"markers not found in doc — expected both {BEGIN_MARKER!r} and "
f"{END_MARKER!r}. Add them to the doc first."
f"markers not found in doc — expected both {BEGIN_MARKER!r} and {END_MARKER!r}. Add them to the doc first."
)
if end < start:
raise GenerateError("END marker precedes BEGIN marker in the doc")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,9 @@ def test_contract_members_resolve_statically_not_via_getattr() -> None:
if name in _OVERRIDDEN_MEMBERS:
assert owner is AssemblyCallbackHandler
else:
assert owner.__module__.startswith(
"langchain_core"
), f"{name!r} resolved to {owner!r}, not the LangChain base contract"
assert owner.__module__.startswith("langchain_core"), (
f"{name!r} resolved to {owner!r}, not the LangChain base contract"
)

# Live attribute access (bound methods + evaluated flag properties) also
# resolves without ever delegating to the interceptor.
Expand Down
6 changes: 3 additions & 3 deletions test/unit/adapters/test_failopen_conformance.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@ async def test_failopen_conformance(

posture = "enforce" if is_enforce else "fail-open"
verb = "run" if want else "be blocked"
assert (
ran is want
), f"{adapter_name} under {mode_id} ({posture}) on {scenario}: tool expected to {verb}, but ran={ran}"
assert ran is want, (
f"{adapter_name} under {mode_id} ({posture}) on {scenario}: tool expected to {verb}, but ran={ran}"
)


def test_every_adapter_has_a_driver() -> None:
Expand Down
4 changes: 2 additions & 2 deletions test/unit/cli/test_adapter_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def test_valid_pyproject_passes(self, valid_adapter_cls: type, tmp_path: object)
assert isinstance(tmp_path, pathlib.Path)
pyproject = tmp_path / "pyproject.toml"
qualname = f"{valid_adapter_cls.__module__}:{valid_adapter_cls.__qualname__}"
pyproject.write_text(f'[project.entry-points."agent_assembly.adapters"]\n' f'test_framework = "{qualname}"\n')
pyproject.write_text(f'[project.entry-points."agent_assembly.adapters"]\ntest_framework = "{qualname}"\n')
result = _check_entry_point_metadata(valid_adapter_cls, str(tmp_path))
assert result.passed is True

Expand Down Expand Up @@ -193,7 +193,7 @@ def test_traversal_path_resolved_to_valid_dir(self, valid_adapter_cls: type, tmp
adapter_dir.mkdir()
pyproject = adapter_dir / "pyproject.toml"
qualname = f"{valid_adapter_cls.__module__}:{valid_adapter_cls.__qualname__}"
pyproject.write_text(f'[project.entry-points."agent_assembly.adapters"]\n' f'test_framework = "{qualname}"\n')
pyproject.write_text(f'[project.entry-points."agent_assembly.adapters"]\ntest_framework = "{qualname}"\n')
# "<tmp>/adapter/../adapter" canonicalizes back to "<tmp>/adapter".
traversal = str(adapter_dir / ".." / "adapter")
result = _check_entry_point_metadata(valid_adapter_cls, traversal)
Expand Down
6 changes: 3 additions & 3 deletions test/unit/test_runtime_import_isolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ def test_runtime_import_does_not_pull_in_httpx() -> None:
["httpx", "pydantic"],
"from agent_assembly.runtime import find_aasm_binary, init_assembly, is_running\nprint('ok')\n",
)
assert (
result.returncode == 0
), f"agent_assembly.runtime should not require httpx/pydantic.\nstdout: {result.stdout}\nstderr: {result.stderr}"
assert result.returncode == 0, (
f"agent_assembly.runtime should not require httpx/pydantic.\nstdout: {result.stdout}\nstderr: {result.stderr}"
)
assert result.stdout.strip() == "ok"


Expand Down