Skip to content
Draft
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
17 changes: 17 additions & 0 deletions composer/io/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,23 @@ def emit_custom_event(payload: Mapping[str, Any]):
raise ValueError("No IO handler installed")
curr_io[0].push(ProgressEvent(dict(payload)))


def push_custom_update(
payload: Mapping[str, Any], *, thread_id: str, checkpoint_id: str = ""
) -> bool:
"""Push a ``CustomUpdate`` to the current ``with_handler`` scope's queue so it
reaches ``EventHandler.handle_event`` — the out-of-graph analogue of
``get_stream_writer()``. Used by backends (e.g. the Rust IoC loop) that emit
domain events *between* graph calls, where ``get_stream_writer()`` is unavailable.
Returns ``False`` (event dropped) if no handler scope is installed."""
curr_io = _io_handler.get()
if curr_io is None:
return False
curr_io[0].push(
CustomUpdate(payload=dict(payload), thread_id=thread_id, checkpoint_id=checkpoint_id)
)
return True

async def run_graph[S: StateLike, C: StateLike | None, I: StateLike](
graph: CompiledStateGraph[S, C, I, Any],
ctxt: C,
Expand Down
19 changes: 15 additions & 4 deletions composer/pipeline/ecosystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,21 @@ def _evm_analysis_extra_input(source: SourceCode) -> list[str | dict]:
#: Cargo/Anchor project layout: hide build output, VCS, lockfiles, and the JS side; keep the
#: crate sources and `tests/`. (Contrast the Foundry-shaped ``FS_FORBIDDEN_READ``.)
RUST_FORBIDDEN_READ = r"(^target/.*)|(^\.git.*)|(^node_modules/.*)|(.*\.lock$)"
# NOTE: the confined-build scratch dirs (``.sandbox_cargo`` / ``.sandbox_rustup`` /
# ``.sandbox_tmp`` and nested ``target/``) are also excluded, but that extension lives with the
# rust-framework layer that introduces confined Rust builds — no build runs in this front-half, so
# those dirs never exist here.
# The pipeline generates hundreds of MB of build/scratch *inside the workdir* mid-run, which the
# source tools' file-listing would otherwise pull into LLM context and blow the model's window:
# • ``.sandbox_cargo`` — the command sandbox's private CARGO_HOME (docs/command-sandbox.md §3);
# a build fills it with the *entire* cargo registry (~19.5k files, ~520 MB).
# • ``.sandbox_rustup`` — the sandbox's private RUSTUP_HOME; its ``toolchains`` is a symlink to
# the shared rustup home, so a naive listing would enumerate the whole Rust toolchain.
# • ``.sandbox_tmp`` — the sandbox's private linker TMPDIR.
# • nested ``target/`` — cargo build output below the root (e.g. the generated
# ``fuzz/<program>/target``, ~4k files, ~900 MB); the top-level ``^target/`` above misses it.
# These are never source, so they are never readable by the source tools (belt-and-suspenders with
# each run's own cleanup: a re-run or cached CI workspace can leave them behind).
RUST_FORBIDDEN_READ = (
RUST_FORBIDDEN_READ
+ r"|(^\.sandbox_cargo/.*)|(^\.sandbox_rustup/.*)|(^\.sandbox_tmp/.*)|(.*/target/.*)"
)

RUST_CODE_EXPLORER_PROMPT = """\
You are a code-exploration assistant analyzing Rust source for on-chain programs (e.g. Solana
Expand Down
137 changes: 137 additions & 0 deletions composer/rustapp/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
"""Host for AutoProver applications whose backend is *implemented* in Rust (PyO3).

"Rust" here is the **backend implementation** language — the wheel is compiled Rust — and it is
orthogonal to the ecosystem, i.e. the language of the *code being analyzed*: a Rust-implemented
backend may analyze Solidity (``echoprover`` selects ecosystem ``evm``) or Rust (Crucible selects
``solana``). The analyzed-source language rides on the ecosystem (see
``composer.pipeline.ecosystem.Language``); this host never assumes it from the fact that the
backend is a Rust wheel — it reads it from ``app.ecosystem.language``.

This package is the Python side of the seam described in
``docs/rust-backend-api.md``. A Rust application is a wheel built with
``autoprover-sdk`` (see ``rust/``) exposing a small, synchronous, JSON FFI surface
— a **passive service** the pipeline drives:

descriptor() -> str # the AppDescriptor (declarative spine)
validate_preconditions(args_json) -> str|None
units(input_json) -> str # the report rows / validation units
author_prompt(input_json, failure_json|None) -> str
judge_prompt(input_json, spec) -> str|None
compile(input_json, spec, workdir, sandbox_json) -> str # BLOCKING (run-confined)
validate(input_json, spec, unit, workdir, sandbox_json) -> str # BLOCKING (run-confined)
finalize(outcomes_json) -> str|None

The host loads that module, synthesizes the pipeline's phase enum from the
descriptor, and wraps the module in a :class:`PipelineBackend` whose ``formalize``
runs the author→compile→judge→validate loop (:mod:`composer.rustapp.adapter`) —
Python owns the loop and every LLM turn; the two blocking callouts run the toolchain
via ``run-confined``. No IoC ``resume`` protocol and no ``pyo3-async`` bridge.

Entry points:

* :func:`composer.rustapp.cli.tui_main` / ``console_main`` — a complete runnable
application from a module name (the descriptor drives argparse, the entry point,
the frontend, and ``main()``). This is the whole vertical.
* :func:`composer.rustapp.host.build_application` — synthesize the phase enum,
labels, section order and backend factory for a frontend / ``main()``.
* :func:`composer.rustapp.entry.rust_entry_point` — the async entry point context
manager (services + ``WorkflowContext``), yielding the Executor.
* :func:`composer.rustapp.host.run_rust_pipeline` — headless: build the backend
from a module name and run the shared driver directly.
"""

from composer.rustapp.descriptor import (
AppDescriptor,
ArgDefault,
ArgSpec,
ArtifactLayout,
CoreSlot,
DeliverableMode,
EventKind,
PhaseSpec,
SetupSpec,
)
from composer.rustapp.result import RustArtifact, RustFormalResult
from composer.rustapp.adapter import (
RustBackend,
RustFormalizer,
RustPreparedSystem,
as_report_backend,
author_and_compile,
make_emitter,
unique_slugs,
)
from composer.rustapp.store import RustArtifactStore
from composer.rustapp.host import (
BackendOptions,
RustApplication,
StoreFactory,
build_application,
build_backend,
build_core_phases,
build_phase_enum,
load_descriptor,
load_module,
resolve_ecosystem,
run_application,
run_rust_pipeline,
)
from composer.rustapp.entry import (
EnvBuilder,
RustRunner,
build_arg_parser,
build_neutral_env,
rust_entry_point,
)
from composer.rustapp.frontend import (
GenericRustApp,
GenericRustConsoleHandler,
GenericRustTaskHandler,
)

# NOTE: composer.rustapp.cli is intentionally NOT imported here — it runs
# `import composer.bind` (import-time DI / test-tape bootstrap), which the
# built-in apps only trigger from their `main` modules. Import it explicitly:
# from composer.rustapp.cli import tui_main, console_main

__all__ = [
"AppDescriptor",
"ArgDefault",
"ArgSpec",
"ArtifactLayout",
"CoreSlot",
"DeliverableMode",
"EventKind",
"PhaseSpec",
"SetupSpec",
"RustArtifact",
"RustFormalResult",
"RustBackend",
"RustFormalizer",
"RustPreparedSystem",
"as_report_backend",
"author_and_compile",
"make_emitter",
"unique_slugs",
"RustArtifactStore",
"RustApplication",
"BackendOptions",
"StoreFactory",
"build_application",
"build_backend",
"build_core_phases",
"build_phase_enum",
"load_descriptor",
"load_module",
"resolve_ecosystem",
"run_application",
"run_rust_pipeline",
"EnvBuilder",
"RustRunner",
"build_arg_parser",
"build_neutral_env",
"rust_entry_point",
"GenericRustApp",
"GenericRustConsoleHandler",
"GenericRustTaskHandler",
]
Loading
Loading