diff --git a/genc/cc/examples/executors/BUILD b/genc/cc/examples/executors/BUILD index e599c5ac..20a9c8ab 100644 --- a/genc/cc/examples/executors/BUILD +++ b/genc/cc/examples/executors/BUILD @@ -12,8 +12,11 @@ pybind_extension( tags = ["generated_py_module=genc.examples.executors"], deps = [ ":executor_stacks", + "//genc/cc/runtime:control_flow_executor", "//genc/cc/runtime:executor", + "//genc/cc/runtime:executor_bindings", "//genc/proto/v0:computation_cc_proto", + "@com_google_absl//absl/status:statusor", "@pybind11_abseil//pybind11_abseil:absl_casters", "@pybind11_abseil//pybind11_abseil:status_casters", "@pybind11_protobuf//pybind11_protobuf:native_proto_caster", @@ -33,6 +36,7 @@ cc_library( "//genc/cc/modules/retrieval:local_cache", "//genc/cc/modules/tools:wolfram_alpha", "//genc/cc/runtime:concurrency", + "//genc/cc/runtime:control_flow_executor", "//genc/cc/runtime:executor", "//genc/cc/runtime:executor_stacks", "//genc/cc/runtime:status_macros", diff --git a/genc/cc/examples/executors/executor_bindings.cc b/genc/cc/examples/executors/executor_bindings.cc index 77c0c083..9c6320d5 100644 --- a/genc/cc/examples/executors/executor_bindings.cc +++ b/genc/cc/examples/executors/executor_bindings.cc @@ -20,7 +20,11 @@ limitations under the License // - Python methods defined here (e.g. `.def_*()`) should not contain // "business logic". That should be implemented on the underlying C++ class. +#include + +#include "absl/status/statusor.h" #include "genc/cc/examples/executors/executor_stacks.h" +#include "genc/cc/runtime/control_flow_executor.h" #include "genc/cc/runtime/executor.h" #include "genc/proto/v0/computation.pb.h" #include "include/pybind11/cast.h" @@ -48,7 +52,66 @@ namespace { PYBIND11_MODULE(executor_bindings, m) { py::google::ImportStatusModule(); - m.def("create_default_executor", &CreateDefaultExecutor, + // Provide an `OwnedValueId` class to handle return values from the + // `Executor` interface. + // + // Note: no `init<>()` method defined, this object is only constructor from + // Executor instances. + py::class_(m, "OwnedValueId") + .def_property_readonly("ref", &OwnedValueId::ref) + .def("__str__", + [](const OwnedValueId& self) { return absl::StrCat(self.ref()); }) + .def("__repr__", [](const OwnedValueId& self) { + return absl::StrCat(""); + }); + + // Provide the `Executor` interface. + // + // A `dispose` method is purposely not exposed. Though `Executor::Dispose` + // exists in C++, Python should call `Dispose` via the `OwnedValueId` + // destructor during garbage collection. + // + // Note: no `init<>()` method defined, must be constructed useing the create_* + // methods defined below. + py::class_>(m, "Executor") + .def("create_value", &Executor::CreateValue, py::arg("value_pb"), + py::return_value_policy::move, + py::call_guard()) + .def("create_struct", &Executor::CreateStruct, + py::return_value_policy::move, + py::call_guard()) + .def("create_selection", &Executor::CreateSelection, + py::return_value_policy::move, + py::call_guard()) + .def("create_call", &Executor::CreateCall, py::arg("function"), + // Allow `argument` to be `None`. + py::arg("argument").none(true), py::return_value_policy::move, + py::call_guard()) + .def( + "materialize", + [](Executor& e, + const ValueId& value_id) -> absl::StatusOr { + // Construct a new `v0::Value` to write to and return it to Python. + v0::Value value_pb; + absl::Status result = e.Materialize(value_id, &value_pb); + if (!result.ok()) { + return result; + } + return value_pb; + }, + py::call_guard()); + + m.def("create_default_executor", + []() -> absl::StatusOr> { + absl::StatusOr> ex = + ::genc::CreateDefaultExecutor(); + if (!ex.ok()) { + return ex.status(); + } + return ex.value(); + }, + py::call_guard(), "Creates a default executor with predefined components used in " "GenC demos."); } diff --git a/genc/cc/examples/executors/executor_stacks.cc b/genc/cc/examples/executors/executor_stacks.cc index f322e5d3..5f48d451 100644 --- a/genc/cc/examples/executors/executor_stacks.cc +++ b/genc/cc/examples/executors/executor_stacks.cc @@ -27,6 +27,7 @@ limitations under the License #include "genc/cc/modules/retrieval/local_cache.h" #include "genc/cc/modules/tools/wolfram_alpha.h" #include "genc/cc/runtime/concurrency.h" +#include "genc/cc/runtime/control_flow_executor.h" #include "genc/cc/runtime/executor.h" #include "genc/cc/runtime/executor_stacks.h" #include "genc/cc/runtime/status_macros.h" @@ -86,8 +87,10 @@ void SetLlamaCppModelInferenceHandler(intrinsics::HandlerSetConfig* config, } // namespace absl::StatusOr> CreateDefaultExecutor() { - return CreateDefaultExecutorWithConcurrencyInterface( - CreateThreadBasedConcurrencyManager()); + absl::StatusOr> result = + CreateDefaultExecutorWithConcurrencyInterface( + CreateThreadBasedConcurrencyManager()); + return result; } absl::StatusOr> diff --git a/genc/cc/runtime/BUILD b/genc/cc/runtime/BUILD index 94a30397..0acdcd60 100644 --- a/genc/cc/runtime/BUILD +++ b/genc/cc/runtime/BUILD @@ -89,6 +89,7 @@ pybind_extension( srcs = ["executor_bindings.cc"], tags = ["generated_py_module=genc.runtime"], deps = [ + ":control_flow_executor", ":executor", ":executor_stacks", "//genc/proto/v0:computation_cc_proto", diff --git a/genc/cc/runtime/control_flow_executor.cc b/genc/cc/runtime/control_flow_executor.cc index 3b651a36..bf2058ad 100644 --- a/genc/cc/runtime/control_flow_executor.cc +++ b/genc/cc/runtime/control_flow_executor.cc @@ -771,8 +771,9 @@ absl::StatusOr> CreateControlFlowExecutor( std::shared_ptr handler_set, std::shared_ptr child_executor, std::shared_ptr concurrency_interface) { - return std::make_shared(handler_set, child_executor, - concurrency_interface); + return std::shared_ptr( + new ControlFlowExecutor( + handler_set, child_executor, concurrency_interface)); } } // namespace genc diff --git a/genc/cc/runtime/executor_bindings.cc b/genc/cc/runtime/executor_bindings.cc index f620a3cc..49a44c10 100644 --- a/genc/cc/runtime/executor_bindings.cc +++ b/genc/cc/runtime/executor_bindings.cc @@ -32,6 +32,7 @@ limitations under the License #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/str_cat.h" +#include "genc/cc/runtime/control_flow_executor.h" #include "genc/cc/runtime/executor.h" #include "genc/cc/runtime/executor_stacks.h" #include "genc/proto/v0/computation.pb.h" diff --git a/genc/python/examples/BUILD b/genc/python/examples/BUILD index c3d4a14d..083fe25e 100644 --- a/genc/python/examples/BUILD +++ b/genc/python/examples/BUILD @@ -25,8 +25,11 @@ py_test( name = "authoring_demo", srcs = ["authoring_demo.py"], deps = [ + ":executor", "//genc", + "//genc/cc/examples/executors:executor_bindings", "//genc/cc/runtime:executor_bindings", + "//genc/python/runtime", ], ) @@ -35,6 +38,8 @@ py_binary( srcs = ["langchain_demo.py"], deps = [ ":executor", + "//genc/cc/examples/executors:executor_bindings", + "//genc/cc/runtime:executor_bindings", "//genc/proto/v0:computation_py_pb2", "//genc/python/interop", "//genc/python/runtime", diff --git a/genc/python/examples/authoring_demo.py b/genc/python/examples/authoring_demo.py index 71e179d2..8a0e9f7e 100644 --- a/genc/python/examples/authoring_demo.py +++ b/genc/python/examples/authoring_demo.py @@ -15,7 +15,7 @@ from absl.testing import absltest import genc as genc -from genc.cc.runtime import executor_bindings +from genc.python.examples import executor # pylint:disable=missing-class-docstring # pylint:disable=missing-function-docstring] @@ -24,8 +24,8 @@ class AuthoringTest(absltest.TestCase): def test_something(self): - genc.runtime.set_default_executor( - executor_bindings.create_default_local_executor()) + my_executor = executor.create_default_executor() + genc.runtime.set_default_executor(my_executor) @genc.authoring.traced_computation def comp(x): diff --git a/genc/python/examples/langchain_demo.py b/genc/python/examples/langchain_demo.py index 2b1e9f97..06911a88 100644 --- a/genc/python/examples/langchain_demo.py +++ b/genc/python/examples/langchain_demo.py @@ -35,7 +35,8 @@ def main(argv: Sequence[str]) -> None: ) comp_pb = interop.langchain.create_computation(my_chain) - comp = runtime.Runner(comp_pb, executor.create_default_executor()) + my_executor = executor.create_default_executor() + comp = runtime.Runner(comp_pb, my_executor) result = comp("a grocery store") print(result)