diff --git a/README.md b/README.md index 78a32b9b..dc451172 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,8 @@ For more details, see the [flmadm README](flmadm/README.md). ## Documentation * [API Reference](docs/api/index.md) +* [SDKs](docs/sdk/index.md): [Rust SDK](docs/sdk/rust.md), [Python SDK](docs/sdk/python.md) +* [Rust API Tutorial](docs/tutorials/rust-api.md) * [Local Development](docs/tutorials/local-development.md) * [Runner Setup Guide](docs/tutorials/runner-setup.md) * [Design Documents](docs/designs/) diff --git a/docs/api/index.md b/docs/api/index.md index 70609419..0f020c71 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -18,6 +18,7 @@ Flame exposes three gRPC services: - [Frontend Service](frontend.md) - For client SDK developers - [Backend Service](backend.md) - For executor/node developers - [Instance Service](shim.md) - For application shim developers +- [SDK Guides](../sdk/index.md) - For application developers using Rust or Python ## Package @@ -61,6 +62,8 @@ gRPC status codes are used for error reporting: ## Related Documentation - [Flame README](../../README.md) +- [Rust SDK](../sdk/rust.md) +- [Python SDK](../sdk/python.md) - [Local Development](../tutorials/local-development.md) - [Runner Setup Guide](../tutorials/runner-setup.md) -- [Python SDK](../../sdk/python/README.md) +- [Python SDK README](../../sdk/python/README.md) diff --git a/docs/sdk/index.md b/docs/sdk/index.md new file mode 100644 index 00000000..2fbdcd79 --- /dev/null +++ b/docs/sdk/index.md @@ -0,0 +1,56 @@ +# Flame SDKs + +Flame provides SDKs for building clients that submit work to Flame and services that run inside Flame executors. + +| SDK | Use it for | Documentation | +|-----|------------|---------------| +| Rust SDK | Typed async clients, compiled services, high-throughput task submission, and object-cache workflows | [Rust SDK](rust.md) | +| Python SDK | Python services, scripts, agent and RL workflows, and dynamic packaging through Runner | [Python SDK](python.md) | + +Both SDKs use the same Flame concepts: + +- An application is the service registered in Flame. +- A session is a group of tasks for one application. +- A task is one unit of work inside a session. +- Common data is shared session input sent to every service instance. +- Object cache stores larger shared values, files, packages, and versioned objects. + +## Configuration + +Both SDKs read Flame configuration from `~/.flame/flame.yaml` and accept environment overrides from the Flame runtime: + +```yaml +current-context: flame +contexts: + - name: flame + cluster: + endpoint: "http://127.0.0.1:8080" + cache: + endpoint: "grpc://127.0.0.1:9090" +``` + +Common environment overrides: + +- `FLAME_ENDPOINT` +- `FLAME_CACHE_ENDPOINT` +- `FLAME_CA_FILE` + +Use `https://` for the session-manager endpoint when TLS is enabled. Use `grpcs://` for the object-cache endpoint when cache TLS is enabled. + +## Typical Workflow + +1. Start a Flame cluster with Docker Compose or `flmadm`. +2. Deploy or register an application service. +3. Create a session for that application from a client. +4. Submit tasks with `invoke()` or `run()`. +5. Close the session when no more work will be submitted. + +The SDKs wrap the gRPC APIs documented in [Flame API Reference](../api/index.md). Use the SDK pages for common application code and the API reference when implementing lower-level protocol integrations. + +## Examples + +- [Rust Pi example](../../examples/pi/rust/README.md) +- [Rust API tutorial](../tutorials/rust-api.md) +- [Rust Candle Based example](../../examples/candle/based/README.md) +- [Python Pi Runner example](../../examples/pi/python/README.md) +- [Python SDK API reference](../../sdk/python/docs/API.md) diff --git a/docs/sdk/python.md b/docs/sdk/python.md new file mode 100644 index 00000000..13545419 --- /dev/null +++ b/docs/sdk/python.md @@ -0,0 +1,220 @@ +# Flame Python SDK + +The Python SDK is distributed as `flamepy`. It provides: + +- A synchronous client for sessions, tasks, and application registration. +- A host-shim service base class for Python services. +- Object-cache helpers for pickled objects, files, and versioned references. +- The Runner API for packaging Python code and invoking functions or objects remotely. + +## Install + +Install the SDK package: + +```bash +pip install flamepy +``` + +The package requires Python 3.9 or newer. + +For local development from this repository: + +```bash +python3 -m pip install -e sdk/python --user --no-build-isolation +``` + +## Configure A Client + +The SDK reads `~/.flame/flame.yaml` by default: + +```yaml +current-context: flame +contexts: + - name: flame + cluster: + endpoint: "http://127.0.0.1:8080" + cache: + endpoint: "grpc://127.0.0.1:9090" + package: + excludes: + - "*.log" + - "*.pkl" +``` + +Environment variables override the file: + +- `FLAME_ENDPOINT` +- `FLAME_CACHE_ENDPOINT` +- `FLAME_CACHE_STORAGE` +- `FLAME_CA_FILE` + +Use `https://` for the session-manager endpoint when TLS is enabled. Use `grpcs://` for the object-cache endpoint when cache TLS is enabled. + +## Create Sessions And Run Tasks + +The core client API uses bytes for task input, task output, and common data: + +```python +from concurrent.futures import wait + +import flamepy + +session = flamepy.create_session( + "flmping", + min_instances=1, + resreq=flamepy.ResourceRequirement.from_string("cpu=1,mem=1g"), +) + +output = session.invoke(b"hello") +print(output) + +futures = [session.run(f"task {idx}".encode()) for idx in range(10)] +wait(futures) +outputs = [future.result() for future in futures] + +session.close() +``` + +Use `session.create_task()`, `session.get_task()`, `session.list_tasks()`, and `session.watch_task()` when callers need explicit task objects or streamed task updates. + +## Register Applications + +Most users deploy applications with `flmctl deploy`. The SDK can also register an application directly: + +```python +import flamepy + +flamepy.register_application( + "echo", + { + "shim": flamepy.Shim.HOST, + "command": "python /opt/echo/service.py", + "description": "Echo service", + }, +) +``` + +Use the same application name when creating a session: + +```python +session = flamepy.create_session("echo") +``` + +## Write A Service + +Subclass `FlameService` and run it with `flamepy.run()`: + +```python +from typing import Optional + +import flamepy + + +class Echo(flamepy.FlameService): + def on_session_enter(self, context: flamepy.SessionContext): + self.session_id = context.session_id + self.common_data = context.common_data() + + def on_task_invoke(self, context: flamepy.TaskContext) -> Optional[bytes]: + return context.input + + def on_session_leave(self): + self.session_id = None + + +if __name__ == "__main__": + flamepy.run(Echo()) +``` + +The service runtime provides `FLAME_INSTANCE_ENDPOINT` and calls the service through a Unix domain socket. Service methods should return bytes or `None`. + +## Use The Service Helper + +For object-oriented or agent-style applications, `flamepy.service` provides a higher-level API that serializes Python objects through object cache: + +```python +from flamepy import service + +instance = service.FlameInstance() + + +@instance.entrypoint +def answer(question: str) -> str: + history = instance.context() or [] + history.append(question) + instance.update_context(history) + return f"received {question}" + + +if __name__ == "__main__": + instance.run() +``` + +Clients use `flamepy.service.Session` with the deployed application name: + +```python +from flamepy.service import Session + +with Session("agent-app", ctx=[]) as session: + print(session.invoke("hello")) + print(session.context()) +``` + +Use this helper when request, response, or session context objects are easier to model as Python objects than raw bytes. Use the core `FlameService` API when you need explicit byte-level protocol control. + +## Use Object Cache + +Top-level helpers store Python objects in Flame object cache: + +```python +import flamepy + +ref = flamepy.put_object("my-app/shared", {"temperature": 0.8}) +value = flamepy.get_object(ref) + +next_ref = flamepy.update_object(ref, {"temperature": 0.7}) +next_value = flamepy.get_object(next_ref) +``` + +Object references are versioned. `version=0` forces a fresh download. Nonzero versions allow the client to reuse cached state and request newer patches when the cache server can provide them. + +Lower-level helpers under `flamepy.core` and `flamepy.cache` also expose `ObjectKey`, `patch_object()`, `upload_object()`, `download_object()`, and `delete_objects()`. + +## Use Runner + +Runner packages the current Python project, registers a Flame application based on the configured runner template, and exposes Python callables or objects as remote services: + +```python +from flamepy.runner import Runner + + +def square(value: int) -> int: + return value * value + + +with Runner("square-app") as runner: + svc = runner.service(square, warmup=2) + futures = [svc(idx) for idx in range(8)] + print(runner.get(futures)) +``` + +Runner returns `ObjectFuture` values. Use `future.get()` to fetch a concrete result, `future.ref()` to get the `ObjectRef`, `runner.wait()` to wait for a batch, and `runner.select()` to iterate as results complete. + +## API Map + +| Area | Python API | +|------|------------| +| Connect | `flamepy.connect()` | +| Sessions | `create_session()`, `open_session()`, `get_session()`, `list_sessions()`, `close_session()` | +| Tasks | `Session.invoke()`, `Session.run()`, `Session.create_task()`, `Session.watch_task()` | +| Applications | `register_application()`, `unregister_application()`, `get_application()`, `list_applications()` | +| Services | `FlameService`, `flamepy.run()`, `flamepy.service.FlameInstance`, `flamepy.service.Session` | +| Objects | `put_object()`, `get_object()`, `update_object()`, `patch_object()`, `upload_object()`, `download_object()` | +| Runner | `Runner`, `Runner.service()`, `ObjectFuture` | + +See also: + +- [Python SDK API reference](../../sdk/python/docs/API.md) +- [Python SDK README](../../sdk/python/README.md) +- [Python Pi Runner example](../../examples/pi/python/README.md) +- [OpenAI agent service example](../../examples/agents/openai/README.md) diff --git a/docs/sdk/rust.md b/docs/sdk/rust.md new file mode 100644 index 00000000..e9908762 --- /dev/null +++ b/docs/sdk/rust.md @@ -0,0 +1,210 @@ +# Flame Rust SDK + +The Rust SDK lives in this repository as the `flame-rs` crate. It provides: + +- Async client APIs for sessions, tasks, applications, nodes, and executors. +- Typed task payloads through `FlameMessage`. +- Service helpers for host-shim applications. +- Optional macros for concise typed service entrypoints. +- Object-cache helpers for typed objects and files. + +## Add The Dependency + +Inside this repository, use a path dependency and enable the `macros` feature when you want typed service macros: + +```toml +[dependencies] +flame-rs = { path = "sdk/rust", features = ["macros"] } +``` + +Adjust the path for nested examples. The [Rust Pi example](../../examples/pi/rust/Cargo.toml) uses: + +```toml +flame-rs = { path = "../../../sdk/rust", features = ["macros"] } +``` + +## Configure A Client + +The top-level helpers read `~/.flame/flame.yaml` and apply `FLAME_ENDPOINT`, `FLAME_CACHE_ENDPOINT`, and `FLAME_CA_FILE` overrides: + +```yaml +current-context: flame +contexts: + - name: flame + cluster: + endpoint: "http://127.0.0.1:8080" + cache: + endpoint: "grpc://127.0.0.1:9090" +``` + +Use `flame_rs::connect_with_config(Some(path))` or `flame_rs::connect_with_context(context)` when a process needs an explicit config source. + +## Define Typed Messages + +With the `macros` feature enabled, derive `FlameMessage` for request, response, and common-data types: + +```rust +use flame_rs::FlameMessage; +use serde_derive::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, FlameMessage)] +struct EstimateRequest { + samples: u32, +} + +#[derive(Debug, Clone, Serialize, Deserialize, FlameMessage)] +struct EstimateResponse { + inside: u32, +} +``` + +The derive serializes with JSON. For custom formats, implement `flame_rs::FlameMessage` directly with `encode()` and `decode()`. + +## Create Sessions And Run Tasks + +Use `create_session()` when the session should be new, `open_session()` for an existing session, and `open_or_create_session()` when repeated clients may attach to the same session. + +```rust +use flame_rs as flame; +use flame_rs::client::SessionOptions; + +#[tokio::main] +async fn main() -> Result<(), Box> { + flame::apis::init_logger()?; + + let session = flame::create_session( + SessionOptions::new("pi") + .min_instances(1) + .resreq("cpu=1,mem=1g"), + ) + .await?; + + let input = EstimateRequest { samples: 10_000 }; + let handle = session.invoke::<_, EstimateResponse>(&input).await?; + let output = handle.await?.expect("service returned no output"); + + println!("inside = {}", output.inside); + session.close().await?; + + Ok(()) +} +``` + +For bulk submission, `Session::run()` returns a `TaskFuture`. Awaiting it returns `Result, FlameError>`: `Ok` contains task ID, session ID, terminal state, decoded output, and task-level error details, while `Err` reports SDK-level failures such as watch or decode errors. `Session::invoke()` converts that result into a simpler handle that resolves to successful output or `FlameError`. + +## Write A Service + +The shortest Rust service is a typed async function annotated with `#[flame::entrypoint]`: + +```rust +use flame_rs::{self as flame, apis::FlameError}; + +#[flame::entrypoint] +async fn estimate(input: EstimateRequest) -> Result { + Ok(EstimateResponse { + inside: input.samples, + }) +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + flame::run(estimate).await +} +``` + +For stateful services, annotate an inherent `impl` block with `#[flame::instance]` and mark exactly one method as the task entrypoint: + +```rust +use std::sync::Mutex; + +use flame_rs::{self as flame, apis::FlameError}; +use flame_rs::service::FlameInstance; +use serde_derive::{Deserialize, Serialize}; + +#[derive(Clone, Serialize, Deserialize, flame::FlameMessage)] +struct Factor { + factor: u32, +} + +#[derive(Clone, Serialize, Deserialize, flame::FlameMessage)] +struct Number { + value: u32, +} + +#[derive(Default)] +struct Multiplier { + factor: Mutex, +} + +#[flame::instance] +impl Multiplier { + async fn enter(&self, instance: FlameInstance) -> Result<(), FlameError> { + let factor = instance + .common_data::()? + .map(|value| value.factor) + .unwrap_or(1); + *self.factor.lock().unwrap() = factor; + Ok(()) + } + + #[flame::entrypoint] + async fn multiply(&self, input: Number) -> Result { + let factor = *self.factor.lock().unwrap(); + Ok(Number { + value: input.value * factor, + }) + } + + async fn leave(&self) -> Result<(), FlameError> { + Ok(()) + } +} +``` + +By default the instance macro looks for lifecycle hooks named `enter` and `leave`. Implement `FlameService` directly when you need byte-level task control. + +## Use Object Cache + +Object keys use either a prefix, `/`, or a full key, `//`. + +```rust +use flame_rs as flame; + +let reference = flame::put_object("pi/shared", &model_config).await?; +let loaded: ModelConfig = reference.get().await?; + +let updated = flame::update_object(&reference, &next_model_config).await?; +let loaded_again: ModelConfig = flame::get_object(updated).await?; +``` + +Use `patch_object()` for versioned delta updates, `upload_object()` and `download_object()` for files, and `delete_objects()` to remove an object or prefix. `ObjectRef` carries the cache endpoint, full key, and object version. + +## Deploy And Run + +Build the service binary, deploy it with `flmctl deploy`, then use the same application name from the client: + +```bash +cargo build -p pi --release +flmctl deploy --name pi --application target/release/pi-service +cargo run -p pi --bin pi -- --app pi +``` + +Use the exact deployed application name in `SessionOptions::new(...)`. + +## API Map + +| Area | Rust API | +|------|----------| +| Connect | `flame_rs::connect()`, `connect_with_config()`, `connect_with_context()` | +| Sessions | `create_session()`, `open_session()`, `open_or_create_session()`, `SessionOptions` | +| Tasks | `Session::run()`, `Session::invoke()`, `Session::create_task()`, `Session::watch_task()` | +| Services | `flame_rs::run()`, `FlameService`, `#[flame::entrypoint]`, `#[flame::instance]` | +| Messages | `FlameMessage`, `IntoTaskInput`, `FromTaskOutput`, `IntoCommonData` | +| Objects | `put_object()`, `get_object()`, `update_object()`, `patch_object()`, `upload_object()`, `download_object()` | + +See also: + +- [Rust API tutorial](../tutorials/rust-api.md) +- [Rust Pi example](../../examples/pi/rust/README.md) +- [Rust Candle Based example](../../examples/candle/based/README.md) +- [Frontend API reference](../api/frontend.md) diff --git a/docs/tutorials/runner-setup.md b/docs/tutorials/runner-setup.md index b6329ce0..2a492934 100644 --- a/docs/tutorials/runner-setup.md +++ b/docs/tutorials/runner-setup.md @@ -225,5 +225,6 @@ Pickle or import errors: keep service functions and classes importable from the ## See Also - [Local Development](local-development.md) +- [Python SDK](../sdk/python.md) - [Python SDK README](../../sdk/python/README.md) - [Runner implementation](../../sdk/python/src/flamepy/runner/runner.py) diff --git a/docs/tutorials/rust-api.md b/docs/tutorials/rust-api.md new file mode 100644 index 00000000..e932c745 --- /dev/null +++ b/docs/tutorials/rust-api.md @@ -0,0 +1,273 @@ +# Rust API Tutorial + +This tutorial walks through the Rust API by building, deploying, and running the existing Rust Pi example. The example uses typed request and response structs, a Rust service entrypoint, and an async Rust client that submits many Flame tasks in parallel. + +## Prerequisites + +- A running Flame cluster with the session manager, executor manager, and object cache. +- `flmctl` on `PATH`. +- Rust toolchain from this repository. +- Flame client configuration in `~/.flame/flame.yaml` or environment variables. + +A minimal local client configuration is: + +```yaml +current-context: flame +contexts: + - name: flame + cluster: + endpoint: "http://127.0.0.1:8080" + cache: + endpoint: "grpc://127.0.0.1:9090" +``` + +If Flame was installed with `flmadm`, source the generated environment file before running the commands: + +```bash +source /usr/local/flame/sbin/flmenv.sh +``` + +For a source-tree local cluster, follow [Local Development](local-development.md) first. + +## Project Layout + +The tutorial uses `examples/pi/rust`: + +```text +examples/pi/rust/ + Cargo.toml + src/api.rs + src/service.rs + src/client.rs +``` + +`Cargo.toml` defines two binaries: + +- `pi-service`: the Flame service that executors run. +- `pi`: the client that creates a session and submits tasks. + +The example depends on `flame-rs` with the `macros` feature enabled: + +```toml +flame-rs = { path = "../../../sdk/rust", features = ["macros"] } +``` + +## Define Typed Payloads + +The Rust SDK uses `FlameMessage` to encode task input, task output, and common data. The Pi example defines request and response types in [api.rs](../../examples/pi/rust/src/api.rs): + +```rust +use serde_derive::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize, flame_rs::FlameMessage)] +pub struct PiRequest { + pub samples: u32, +} + +#[derive(Debug, Clone, Serialize, Deserialize, flame_rs::FlameMessage)] +pub struct PiResponse { + pub inside: u32, +} +``` + +`#[derive(flame_rs::FlameMessage)]` serializes the payloads with JSON. When the client submits a `PiRequest`, the SDK encodes it before creating the task. When the task finishes, the SDK decodes the returned bytes into `PiResponse`. + +## Write The Service + +The service in [service.rs](../../examples/pi/rust/src/service.rs) is a normal async Rust function annotated with `#[flame::entrypoint]`: + +```rust +use flame_rs::{self as flame, apis::FlameError}; + +use api::{PiRequest, PiResponse}; + +#[flame::entrypoint] +async fn estimate_pi(input: PiRequest) -> Result { + let mut inside = 0u32; + + for _ in 0..input.samples { + // Work happens here. + } + + Ok(PiResponse { inside }) +} +``` + +The entrypoint macro adapts the typed function to the Flame host-shim service protocol. The service binary starts the SDK runtime with `flame::run(...)`: + +```rust +#[tokio::main] +async fn main() -> Result<(), Box> { + flame::run(estimate_pi).await?; + Ok(()) +} +``` + +Inside an executor, Flame sets `FLAME_INSTANCE_ENDPOINT`. The Rust SDK binds a Unix domain socket at that endpoint and receives session and task callbacks from the executor manager. + +## Write The Client + +The client in [client.rs](../../examples/pi/rust/src/client.rs) creates a Flame session for the deployed application name: + +```rust +use futures::future::try_join_all; +use flame_rs as flame; +use flame_rs::client::SessionOptions; + +let ssn = flame::create_session(SessionOptions::new(cli.app.clone())).await?; +``` + +The application name must match the name passed to `flmctl deploy`. The client then submits many tasks: + +```rust +let request = PiRequest { + samples: cli.task_input, +}; + +let handles = + try_join_all((0..cli.task_num).map(|_| ssn.run::<_, PiResponse>(&request))).await?; +let tasks = try_join_all(handles).await?; +``` + +`Session::run()` creates a task and returns `Result, FlameError>`, so the first `try_join_all` handles task creation errors. Each `TaskFuture` then resolves to `Result, FlameError>`, so the second `try_join_all` handles SDK-level wait or decode errors. Remote task failures are still represented inside each `TaskResult` and are checked by `count_inside()`. + +For a single task where failures should become `FlameError`, use `invoke()`: + +```rust +let handle = ssn.invoke::<_, PiResponse>(&request).await?; +let output = handle.await?.expect("service returned no output"); +``` + +Close the session after submitting all work: + +```rust +ssn.close().await?; +``` + +Closing prevents new task submissions and lets Flame release executors after the session drains. + +## Build The Example + +From the repository root: + +```bash +cargo build -p pi --release +``` + +This produces: + +- `target/release/pi-service` +- `target/release/pi` + +## Deploy The Service + +Deploy the service binary as an application named `pi`: + +```bash +flmctl deploy \ + --name pi \ + --application target/release/pi-service +``` + +`flmctl deploy` packages the service binary, uploads it to object cache, and registers the application. Confirm the registration: + +```bash +flmctl list -a +``` + +The output should include an enabled application named `pi`. + +## Run The Client + +Run the client with the same application name: + +```bash +cargo run -p pi --bin pi -- \ + --app pi \ + --task-num 10 \ + --task-input 10000 +``` + +The client prints the estimated value: + +```text +pi = 4*(78542/100000) = 3.14168 +``` + +Actual values vary because the service uses random sampling. + +Inspect the session: + +```bash +flmctl list -s +``` + +The session should eventually show all tasks in `Succeed`. + +## Add Session Options + +`SessionOptions` configures scheduling and task placement. For example: + +```rust +let ssn = flame::create_session( + SessionOptions::new(cli.app.clone()) + .min_instances(1) + .max_instances(4) + .batch_size(1) + .priority(10) + .resreq("cpu=1,mem=1g"), +) +.await?; +``` + +Common fields: + +| Field | Meaning | +|-------|---------| +| `min_instances` | Minimum executors to keep for the session | +| `max_instances` | Maximum executors the scheduler may allocate | +| `batch_size` | Executors to allocate per scheduling batch | +| `priority` | Session priority used by priority scheduling | +| `resreq` | Resource request such as `cpu=1,mem=1g,gpu=0` | + +Use typed common data when every task in the session needs the same configuration: + +```rust +let options = SessionOptions::new(cli.app.clone()) + .common_data(&shared_config)?; +let ssn = flame::create_session(options).await?; +``` + +Services can read common data from `FlameInstance` when using `#[flame::instance]`, or from `SessionContext` when implementing `FlameService` directly. + +## API Summary + +| Goal | API | +|------|-----| +| Connect with default config | `flame_rs::connect()` | +| Create a session | `flame_rs::create_session(SessionOptions::new(app))` | +| Submit a task and keep full task status | `Session::run::<_, Output>(&input)` | +| Submit a task and get successful output | `Session::invoke::<_, Output>(&input)` | +| Close a session | `Session::close()` | +| Define typed payloads | `#[derive(flame_rs::FlameMessage)]` | +| Define a function service | `#[flame::entrypoint]` and `flame::run(handler)` | +| Store shared objects | `flame_rs::put_object()`, `get_object()`, `update_object()` | + +## Troubleshooting + +`flmctl deploy` cannot connect: verify `FLAME_ENDPOINT` and `FLAME_CACHE_ENDPOINT`, then confirm the session manager and object cache are running. + +Client fails with application not found: verify `flmctl list -a` includes the same application name passed to `--app`. + +Tasks remain pending: check executor-manager logs and verify the cluster has available resources for the session `resreq`. + +Service exits immediately outside Flame: `pi-service` expects `FLAME_INSTANCE_ENDPOINT`, which is set by the executor manager. Run the client locally, not the service binary directly, after deploying the service. + +Typed decode errors: make sure the client and service use matching `FlameMessage` request and response types. + +## See Also + +- [Rust SDK](../sdk/rust.md) +- [Rust Pi example](../../examples/pi/rust/README.md) +- [Local Development](local-development.md) +- [Frontend API reference](../api/frontend.md) diff --git a/sdk/python/README.md b/sdk/python/README.md index b66ce761..4fda50f7 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -2,6 +2,8 @@ Python SDK for the Flame, a distributed system for Agentic AI. +For the user guide, see [Flame Python SDK](../../docs/sdk/python.md). For the detailed API surface, see [API.md](docs/API.md). + ## Installation ```bash @@ -124,7 +126,7 @@ mypy flamepy/ ### Requirements -- Python >= 3.8 +- Python >= 3.9 - setuptools >= 61.0 (for building from source) ### Troubleshooting @@ -144,4 +146,4 @@ If you encounter issues with the package name showing as "UNKNOWN": 3. Use `--no-build-isolation` flag when installing: ```bash python3 -m pip install . --user --no-build-isolation - ``` \ No newline at end of file + ``` diff --git a/sdk/rust/Cargo.toml b/sdk/rust/Cargo.toml index a49cb671..299a1f69 100644 --- a/sdk/rust/Cargo.toml +++ b/sdk/rust/Cargo.toml @@ -7,7 +7,7 @@ build = "build.rs" description = "The Rust SDK of Flame" repository = "https://github.com/xflops/flame" license-file = "../../LICENSE" -readme = "../../README.md" +readme = "README.md" [dependencies] stdng = { path = "../../stdng" } diff --git a/sdk/rust/README.md b/sdk/rust/README.md new file mode 100644 index 00000000..d60f21e1 --- /dev/null +++ b/sdk/rust/README.md @@ -0,0 +1,13 @@ +# Flame Rust SDK + +`flame-rs` is the Rust SDK for Flame clients and host-shim services. + +Start with the central guide: [Flame Rust SDK](../../docs/sdk/rust.md). + +## Quick Links + +- [SDK overview](../../docs/sdk/index.md) +- [Rust API tutorial](../../docs/tutorials/rust-api.md) +- [Rust Pi example](../../examples/pi/rust/README.md) +- [Rust Candle Based example](../../examples/candle/based/README.md) +- [Flame API reference](../../docs/api/index.md)