From c1634fcff787b51cadfc9a612ade80a4c91d6324 Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Fri, 30 Jan 2026 03:46:21 +0000 Subject: [PATCH 01/13] chore: enable e2e-bm in ci. Signed-off-by: Klaus Ma --- .github/workflows/e2e-bm.yaml | 11 +++++++++++ ...ame-local-conf.yaml => flame-cluster-local.yaml} | 0 ci/flame-local.yaml | 13 +++++++++++++ 3 files changed, 24 insertions(+) rename ci/{flame-local-conf.yaml => flame-cluster-local.yaml} (100%) create mode 100644 ci/flame-local.yaml diff --git a/.github/workflows/e2e-bm.yaml b/.github/workflows/e2e-bm.yaml index 736f5d11..9f1ce7cc 100644 --- a/.github/workflows/e2e-bm.yaml +++ b/.github/workflows/e2e-bm.yaml @@ -63,6 +63,17 @@ jobs: sudo chmod -R 777 $INSTALL_PREFIX echo "$INSTALL_PREFIX/bin" >> $GITHUB_PATH + - name: Setup local configuration and packages directory + run: | + echo "=== Copy local configuration ===" + cp ci/flame-local.yaml ~/flame.yaml + echo "✓ Copied flame-local.yaml to ~/flame.yaml" + + echo "=== Create packages directory ===" + sudo mkdir -p /opt/flame/packages + sudo chmod 0777 /opt/flame/packages + echo "✓ Created /opt/flame/packages with 0777 permissions" + - name: Install Python SDK for current user run: | echo "=== Installing flamepy for current user ===" diff --git a/ci/flame-local-conf.yaml b/ci/flame-cluster-local.yaml similarity index 100% rename from ci/flame-local-conf.yaml rename to ci/flame-cluster-local.yaml diff --git a/ci/flame-local.yaml b/ci/flame-local.yaml new file mode 100644 index 00000000..76dd3dbd --- /dev/null +++ b/ci/flame-local.yaml @@ -0,0 +1,13 @@ +--- +current-cluster: flame +clusters: + - name: flame + endpoint: "http://127.0.0.1:8080" + cache: + endpoint: "grpc://127.0.0.1:9090" + package: + storage: "file:///opt/flame/packages" + excludes: + - "*.log" + - "*.pkl" + - "*.tmp" \ No newline at end of file From f8520c1a3748c07921cd99c7df47fb6d906b66de Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Fri, 30 Jan 2026 04:00:03 +0000 Subject: [PATCH 02/13] correct flame.yaml path. Signed-off-by: Klaus Ma --- .github/workflows/e2e-bm.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-bm.yaml b/.github/workflows/e2e-bm.yaml index 9f1ce7cc..deb91ce5 100644 --- a/.github/workflows/e2e-bm.yaml +++ b/.github/workflows/e2e-bm.yaml @@ -66,8 +66,9 @@ jobs: - name: Setup local configuration and packages directory run: | echo "=== Copy local configuration ===" - cp ci/flame-local.yaml ~/flame.yaml - echo "✓ Copied flame-local.yaml to ~/flame.yaml" + mkdir -p ~/.flame + cp ci/flame-local.yaml ~/.flame/flame.yaml + echo "✓ Copied flame-local.yaml to ~/.flame/flame.yaml" echo "=== Create packages directory ===" sudo mkdir -p /opt/flame/packages From 5b944cd1a6a4b6b25f9e43e7a4df1db8de45bd27 Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Fri, 30 Jan 2026 06:32:41 +0000 Subject: [PATCH 03/13] fix permission error. Signed-off-by: Klaus Ma --- .github/workflows/e2e-bm.yaml | 1 - flmadm/src/managers/installation.rs | 10 ++++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e-bm.yaml b/.github/workflows/e2e-bm.yaml index deb91ce5..5b01c1e7 100644 --- a/.github/workflows/e2e-bm.yaml +++ b/.github/workflows/e2e-bm.yaml @@ -60,7 +60,6 @@ jobs: - name: Install Flame with flmadm and systemd run: | sudo ./target/release/flmadm install --src-dir . --skip-build --prefix $INSTALL_PREFIX --enable - sudo chmod -R 777 $INSTALL_PREFIX echo "$INSTALL_PREFIX/bin" >> $GITHUB_PATH - name: Setup local configuration and packages directory diff --git a/flmadm/src/managers/installation.rs b/flmadm/src/managers/installation.rs index 9026dd4c..998390e8 100644 --- a/flmadm/src/managers/installation.rs +++ b/flmadm/src/managers/installation.rs @@ -87,6 +87,12 @@ impl InstallationManager { ] { self.user_manager.set_ownership(path)?; } + + // Set ownership for SDK directory parent (sdk/python directory will be set later) + let sdk_parent = paths.sdk_python.parent().unwrap().parent().unwrap(); // ${PREFIX}/sdk + if sdk_parent.exists() { + self.user_manager.set_ownership(sdk_parent)?; + } } Ok(()) @@ -158,8 +164,8 @@ impl InstallationManager { self.copy_dir_all(&sdk_src, &sdk_install_src) .context("Failed to copy SDK to installation directory")?; - // Set ownership to flame:flame - self.user_manager.set_ownership(&sdk_install_src)?; + // Set ownership to flame:flame for the entire sdk/python directory tree + self.user_manager.set_ownership(&paths.sdk_python)?; // Install using pip as flame user with --user flag let output = Command::new("sudo") From 97645773ced31653ea97591f23d9e3965c65c91d Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Fri, 30 Jan 2026 07:11:57 +0000 Subject: [PATCH 04/13] upgrade python version. Signed-off-by: Klaus Ma --- sdk/python/README.md | 37 +++++++++++++++++++++++--- sdk/python/pyproject.toml | 8 +++--- sdk/python/src/flamepy/core/service.py | 18 ++++++++++--- 3 files changed, 53 insertions(+), 10 deletions(-) diff --git a/sdk/python/README.md b/sdk/python/README.md index dea6721a..b66ce761 100644 --- a/sdk/python/README.md +++ b/sdk/python/README.md @@ -102,15 +102,46 @@ git clone https://github.com/xflops/flame.git cd flame/sdk/python # Install in development mode +# Note: Use --no-build-isolation if you have setuptools>=61.0 installed +python3 -m pip install -e . --user --no-build-isolation + +# Or build and install the wheel +python3 -m build --wheel --no-isolation +python3 -m pip install dist/flamepy-0.5.0-py3-none-any.whl --user + +# Install development dependencies pip install -e .[dev] # Run tests pytest # Format code -black flamepy/ -isort flamepy/ +ruff format # Type checking mypy flamepy/ -``` \ No newline at end of file +``` + +### Requirements + +- Python >= 3.8 +- setuptools >= 61.0 (for building from source) + +### Troubleshooting + +If you encounter issues with the package name showing as "UNKNOWN": + +1. Make sure you have `setuptools>=61.0` installed: + ```bash + python3 -m pip install --user --upgrade "setuptools>=61.0" + ``` + +2. Clean any stale build artifacts: + ```bash + rm -rf dist build src/flamepy.egg-info *.egg-info + ``` + +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/python/pyproject.toml b/sdk/python/pyproject.toml index c4146535..99e7cd03 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -7,7 +7,7 @@ name = "flamepy" version = "0.5.0" description = "Python SDK for Flame, a distributed system for Agentic AI" readme = "README.md" -requires-python = ">=3.12" +requires-python = ">=3.8" license-files = ["LICENSE"] authors = [ {name = "XFLOPS Authors", email = "support@xflops.io"} @@ -47,9 +47,9 @@ dev = [ ] [tool.setuptools.packages.find] -where = [ - "src" -] +where = ["src"] +include = ["flamepy*"] +exclude = ["tests*"] [project.urls] Homepage = "https://xflops.io" diff --git a/sdk/python/src/flamepy/core/service.py b/sdk/python/src/flamepy/core/service.py index cd5a7f11..c872fcb3 100644 --- a/sdk/python/src/flamepy/core/service.py +++ b/sdk/python/src/flamepy/core/service.py @@ -13,12 +13,24 @@ import logging import os +import sys import typing from abc import abstractmethod from concurrent import futures from dataclasses import dataclass from typing import Optional +# Handle typing.override compatibility for Python < 3.12 +if sys.version_info >= (3, 12): + from typing import override +else: + try: + from typing_extensions import override + except ImportError: + # If typing_extensions is not available, use a no-op decorator + def override(func): # type: ignore + return func + import grpc from flamepy.core.types import FlameError, FlameErrorCode, Shim, TaskOutput @@ -123,7 +135,7 @@ class FlameInstanceServicer(InstanceServicer): def __init__(self, service: FlameService): self._service = service - @typing.override + @override def OnSessionEnter(self, request, context): """Handle OnSessionEnter RPC call.""" _trace_fn = TraceFn("OnSessionEnter") @@ -167,7 +179,7 @@ def OnSessionEnter(self, request, context): logger.error(f"Error in OnSessionEnter: {e}") return Result(return_code=-1, message=f"{str(e)}") - @typing.override + @override def OnTaskInvoke(self, request, context): """Handle OnTaskInvoke RPC call.""" _trace_fn = TraceFn("OnTaskInvoke") @@ -196,7 +208,7 @@ def OnTaskInvoke(self, request, context): logger.error(f"Error in OnTaskInvoke: {e}") return TaskResultProto(return_code=-1, output=None, message=f"{str(e)}") - @typing.override + @override def OnSessionLeave(self, request, context): """Handle OnSessionLeave RPC call.""" _trace_fn = TraceFn("OnSessionLeave") From 806d388009b4b69f6d12069a7b326404c1743186 Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Fri, 30 Jan 2026 12:53:26 +0000 Subject: [PATCH 05/13] fix installation issue. Signed-off-by: Klaus Ma --- .github/workflows/e2e-bm.yaml | 15 +- common/src/lib.rs | 17 +- docker/Dockerfile.fem | 4 +- docker/Dockerfile.fsm | 7 +- docs/designs/RFE284-flmrun/RFE284-flmrun.md | 28 +++- e2e/pyproject.toml | 15 +- e2e/tests/test_flmrun.py | 2 +- flmadm/src/commands/uninstall.rs | 12 +- flmadm/src/managers/backup.rs | 27 ++++ flmadm/src/managers/installation.rs | 162 ++++++++++---------- flmadm/src/managers/systemd.rs | 2 + hack/local-test.sh | 4 +- sdk/python/pyproject.toml | 2 +- sdk/python/src/flamepy/core/service.py | 2 +- 14 files changed, 183 insertions(+), 116 deletions(-) diff --git a/.github/workflows/e2e-bm.yaml b/.github/workflows/e2e-bm.yaml index 5b01c1e7..80891cd3 100644 --- a/.github/workflows/e2e-bm.yaml +++ b/.github/workflows/e2e-bm.yaml @@ -74,11 +74,13 @@ jobs: sudo chmod 0777 /opt/flame/packages echo "✓ Created /opt/flame/packages with 0777 permissions" - - name: Install Python SDK for current user + - name: Install Python SDK for test client run: | - echo "=== Installing flamepy for current user ===" + echo "=== Installing flamepy for test client (not required for flmrun service) ===" pip3 install --user ./sdk/python - echo "✓ flamepy installed for current user" + echo "✓ flamepy installed for test client" + echo "" + echo "Note: flmrun service uses 'uv run --with' to access flamepy from $INSTALL_PREFIX/sdk/python" - name: Check service status run: | @@ -91,13 +93,16 @@ jobs: echo "✓ Services are running via systemd" - - name: Verify Python SDK installation + - name: Verify Python SDK installation (for test client) run: | - echo "=== Verify flamepy installation ===" + echo "=== Verify flamepy installation for test client ===" pip3 show flamepy echo "" echo "=== Test import ===" python3 -c "import flamepy; print('✓ flamepy imported successfully from:', flamepy.__file__)" + echo "" + echo "=== Verify SDK copied to installation directory ===" + ls -la $INSTALL_PREFIX/sdk/python/ - name: Install Python dependencies run: | diff --git a/common/src/lib.rs b/common/src/lib.rs index cdf7f661..242cfdc1 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -181,6 +181,13 @@ pub fn default_applications() -> HashMap { "description": "The output of the script in UTF-8." }); + // Get FLAME_HOME from environment or use default + let flame_home = std::env::var("FLAME_HOME").unwrap_or_else(|_| "/usr/local/flame".to_string()); + let flmexec_cmd = format!("{}/bin/flmexec-service", flame_home); + let flmping_cmd = format!("{}/bin/flmping-service", flame_home); + let flmping_url = format!("file://{}/bin/flmping-service", flame_home); + let flamepy_sdk_path = format!("file://{}/sdk/python", flame_home); + HashMap::from([ ( "flmexec".to_string(), @@ -189,7 +196,7 @@ pub fn default_applications() -> HashMap { description: Some( "The Flame Executor application, which is used to run scripts.".to_string(), ), - command: Some("/usr/local/flame/bin/flmexec-service".to_string()), + command: Some(flmexec_cmd), schema: Some(ApplicationSchema { input: Some(script_input_schema.to_string()), output: Some(script_output_schema.to_string()), @@ -202,8 +209,8 @@ pub fn default_applications() -> HashMap { "flmping".to_string(), ApplicationAttributes { shim: Shim::Host, - url: Some("file:///opt/flame/bin/flmping-service".to_string()), - command: Some("/usr/local/flame/bin/flmping-service".to_string()), + url: Some(flmping_url), + command: Some(flmping_cmd), ..ApplicationAttributes::default() }, ), @@ -215,13 +222,13 @@ pub fn default_applications() -> HashMap { "The Flame Runner application for executing customized Python applications." .to_string(), ), - command: Some("/bin/uv".to_string()), + command: Some("/usr/bin/uv".to_string()), arguments: vec![ "run".to_string(), "--with".to_string(), "pip".to_string(), "--with".to_string(), - "flamepy @ file:///usr/local/flame/sdk/python".to_string(), + format!("flamepy @ {}", flamepy_sdk_path), "python".to_string(), "-m".to_string(), "flamepy.rl.runpy".to_string(), diff --git a/docker/Dockerfile.fem b/docker/Dockerfile.fem index 401c9834..068edbac 100644 --- a/docker/Dockerfile.fem +++ b/docker/Dockerfile.fem @@ -16,7 +16,7 @@ RUN mkdir -p /usr/local/flame/bin /usr/local/flame/work/tmp /usr/local/flame/sdk WORKDIR /usr/local/flame/work -COPY --from=ghcr.io/astral-sh/uv:0.9.26 /uv /uvx /bin/ +COPY --from=ghcr.io/astral-sh/uv:0.9.26 /uv /uvx /usr/bin/ COPY --from=builder /usr/local/cargo/bin/flame-executor-manager /usr/local/flame/bin/flame-executor-manager COPY --from=builder /usr/local/cargo/bin/flmping-service /usr/local/flame/bin/flmping-service @@ -26,4 +26,6 @@ RUN chmod +x /usr/local/flame/bin/* COPY ./sdk/python /usr/local/flame/sdk/python +ENV FLAME_HOME=/usr/local/flame + ENTRYPOINT ["/usr/local/flame/bin/flame-executor-manager"] diff --git a/docker/Dockerfile.fsm b/docker/Dockerfile.fsm index c74cd75f..9efa2384 100644 --- a/docker/Dockerfile.fsm +++ b/docker/Dockerfile.fsm @@ -10,11 +10,14 @@ FROM ubuntu:24.04 RUN mkdir -p /usr/local/flame/bin RUN mkdir -p /usr/local/flame/work -WORKDIR /usr/local/flame/work +RUN mkdir -p /usr/local/flame/migrations +WORKDIR /usr/local/flame -COPY session_manager/migrations /usr/local/flame/work/migrations +COPY session_manager/migrations /usr/local/flame/migrations COPY --from=builder /usr/local/cargo/bin/flame-session-manager /usr/local/flame/bin/flame-session-manager RUN chmod +x /usr/local/flame/bin/* +ENV FLAME_HOME=/usr/local/flame + ENTRYPOINT ["/usr/local/flame/bin/flame-session-manager"] diff --git a/docs/designs/RFE284-flmrun/RFE284-flmrun.md b/docs/designs/RFE284-flmrun/RFE284-flmrun.md index 24d3e906..e4083561 100644 --- a/docs/designs/RFE284-flmrun/RFE284-flmrun.md +++ b/docs/designs/RFE284-flmrun/RFE284-flmrun.md @@ -51,8 +51,13 @@ spec: command: /usr/bin/uv arguments: - run - - -n - - flamepy.runpy + - --with + - pip + - --with + - flamepy @ file:///usr/local/flame/sdk/python + - python + - -m + - flamepy.rl.runpy ... ``` @@ -137,20 +142,31 @@ dependencies = [ flamepy = { path = "/usr/local/flame/sdk/python" } ``` -When building the image of `flame-executor-manager` and `flame-console`, the `flmrun` directory should be copy into `/usr/local/flame/work/flmrun` which is the working directory of `flmrun` application. The application should be started with `uv`. +When deploying Flame, the `flamepy` SDK source is copied to `${FLAME_HOME}/sdk/python`. The flmrun application uses `uv run --with` to reference flamepy directly from this location, eliminating the need for separate installation. ```yaml metadata: name: flmrun spec: - working_directory: /usr/local/flame/work/flmrun command: /usr/bin/uv arguments: - run - - -n - - flamepy.runpy + - --with + - pip # Provides pip for installing user packages + - --with + - flamepy @ file://${FLAME_HOME}/sdk/python # Provides flamepy SDK + - python + - -m + - flamepy.rl.runpy ``` +This approach: +- **Self-contained**: All dependencies stay within the Flame installation directory +- **No user-level installation**: Flamepy SDK doesn't require separate pip install +- **User packages**: `pip` is available to install user-provided applications from the `url` field +- **Consistent**: Works identically in Docker, bare-metal, and CI environments +- **Isolated**: Multiple Flame versions can coexist without conflicts + ## Use Cases diff --git a/e2e/pyproject.toml b/e2e/pyproject.toml index 98636c52..c6561c42 100644 --- a/e2e/pyproject.toml +++ b/e2e/pyproject.toml @@ -1,12 +1,12 @@ [project] name = "e2e" version = "0.1.0" -description = "Add your description here" +description = "The e2e test of Flame" readme = "README.md" authors = [ { name = "XFLOPS Authors", email = "support@xflops.io" } ] -requires-python = ">=3.12" +requires-python = ">=3.9" dependencies = [ "grpcio>=1.76", "grpcio-tools>=1.76", @@ -17,8 +17,13 @@ dependencies = [ e2e = "e2e:main" [build-system] -requires = ["uv_build>=0.8.15,<0.9.0"] -build-backend = "uv_build" +requires = ["setuptools>=61.0", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.setuptools.packages.find] +where = ["src"] +include = ["e2e*"] +exclude = ["tests*"] [dependency-groups] dev = [ @@ -27,5 +32,3 @@ dev = [ "isort>=5.0.0", ] -[tool.uv.sources] -flamepy = { path = "/usr/local/flame/sdk/python", editable = true } diff --git a/e2e/tests/test_flmrun.py b/e2e/tests/test_flmrun.py index dc9e2dd3..2d0c225a 100644 --- a/e2e/tests/test_flmrun.py +++ b/e2e/tests/test_flmrun.py @@ -79,7 +79,7 @@ def test_flmrun_application_registered(): assert flmrun.name == FLMRUN_E2E_APP assert flmrun.shim == flamepy.Shim.Host assert flmrun.state == flamepy.ApplicationState.ENABLED - assert flmrun.command == "/bin/uv" + assert flmrun.command == "/usr/bin/uv" def test_flmrun_sum_function(): diff --git a/flmadm/src/commands/uninstall.rs b/flmadm/src/commands/uninstall.rs index 5284942f..9b0ae918 100644 --- a/flmadm/src/commands/uninstall.rs +++ b/flmadm/src/commands/uninstall.rs @@ -105,7 +105,14 @@ fn validate_and_confirm(config: &UninstallConfig) -> Result { ); } if paths.work.exists() { - println!(" • Working directory: {}", paths.work.display()); + println!( + " • Working directory (sessions, executors): {}", + paths.work.display() + ); + } + let events_dir = paths.prefix.join("events"); + if events_dir.exists() { + println!(" • Events directory: {}", events_dir.display()); } if !config.preserve_data && paths.data.exists() { println!(" • Data directory: {}", paths.data.display()); @@ -226,7 +233,8 @@ fn print_summary( println!("Removed Components:"); println!(" • Binaries"); println!(" • Python SDK"); - println!(" • Working directories"); + println!(" • Working directory (sessions, executors)"); + println!(" • Events directory"); println!(" • Systemd service files"); if !config.preserve_data { diff --git a/flmadm/src/managers/backup.rs b/flmadm/src/managers/backup.rs index 5b5c5ae7..23f8f0ba 100644 --- a/flmadm/src/managers/backup.rs +++ b/flmadm/src/managers/backup.rs @@ -57,6 +57,23 @@ impl BackupManager { println!(" ✓ Backed up logs"); } + // Backup work directory (sessions, executors) + if paths.work.exists() { + let backup_work = backup_dir.join("work"); + self.copy_directory(&paths.work, &backup_work) + .context("Failed to backup work directory")?; + println!(" ✓ Backed up work directory"); + } + + // Backup events directory (session-manager creates this in prefix) + let events_dir = paths.prefix.join("events"); + if events_dir.exists() { + let backup_events = backup_dir.join("events"); + self.copy_directory(&events_dir, &backup_events) + .context("Failed to backup events directory")?; + println!(" ✓ Backed up events"); + } + println!("✓ Backup created at: {}", backup_dir.display()); Ok(backup_dir) } @@ -85,6 +102,7 @@ impl BackupManager { ("conf", &paths.conf), ("data", &paths.data), ("logs", &paths.logs), + ("work", &paths.work), ] { if src.exists() { let dst = backup_dir.join(name); @@ -94,6 +112,15 @@ impl BackupManager { } } + // Backup events directory (session-manager creates this in prefix) + let events_dir = paths.prefix.join("events"); + if events_dir.exists() { + let dst = backup_dir.join("events"); + self.copy_directory(&events_dir, &dst) + .context("Failed to backup events")?; + println!(" ✓ Backed up events"); + } + println!("✓ Backup created at: {}", backup_dir.display()); Ok(backup_dir) } diff --git a/flmadm/src/managers/installation.rs b/flmadm/src/managers/installation.rs index 998390e8..c0877db4 100644 --- a/flmadm/src/managers/installation.rs +++ b/flmadm/src/managers/installation.rs @@ -3,7 +3,6 @@ use anyhow::{Context, Result}; use std::fs; use std::os::unix::fs::PermissionsExt; use std::path::Path; -use std::process::Command; pub struct InstallationManager { user_manager: super::user::UserManager, @@ -16,26 +15,6 @@ impl InstallationManager { } } - /// Copy directory recursively - fn copy_dir_all(&self, src: &Path, dst: &Path) -> Result<()> { - fs::create_dir_all(dst).context("Failed to create destination directory")?; - - for entry in fs::read_dir(src).context("Failed to read source directory")? { - let entry = entry.context("Failed to read directory entry")?; - let ty = entry.file_type().context("Failed to get file type")?; - let src_path = entry.path(); - let dst_path = dst.join(entry.file_name()); - - if ty.is_dir() { - self.copy_dir_all(&src_path, &dst_path)?; - } else { - fs::copy(&src_path, &dst_path).context(format!("Failed to copy {:?}", src_path))?; - } - } - - Ok(()) - } - /// Create all required directories pub fn create_directories(&self, paths: &InstallationPaths) -> Result<()> { println!("📁 Creating directory structure..."); @@ -142,82 +121,90 @@ impl InstallationManager { pub fn install_python_sdk(&self, src_dir: &Path, paths: &InstallationPaths) -> Result<()> { println!("🐍 Installing Python SDK..."); - // Check if pip is available - let pip_cmd = which::which("pip3") - .or_else(|_| which::which("pip")) - .context("pip not found. Please install pip3")?; - let sdk_src = src_dir.join("sdk/python"); if !sdk_src.exists() { anyhow::bail!("Python SDK source not found at: {:?}", sdk_src); } - // Install as flame user if running as root, otherwise install for current user - if self.user_manager.is_root() && self.user_manager.user_exists()? { - println!(" Installing Python SDK as flame user..."); + // Copy SDK source to the installation directory, excluding development artifacts + // uv will use this directly with --with "flamepy @ file://..." + self.copy_sdk_excluding_artifacts(&sdk_src, &paths.sdk_python) + .context("Failed to copy SDK to installation directory")?; + + // Set ownership if running as root + if self.user_manager.is_root() { + self.user_manager.set_ownership(&paths.sdk_python)?; + } + + println!("✓ Copied Python SDK to: {}", paths.sdk_python.display()); - // Copy SDK to ${PREFIX}/sdk/python (which is owned by flame:flame) - // This allows the flame user to access the source for installation - let sdk_install_src = paths.sdk_python.join("src"); + // Create a note in the sdk_python directory for reference + let readme_path = paths.sdk_python.join("README.txt"); + std::fs::write( + &readme_path, + "Python SDK source copied to this directory.\n\ + Applications use 'uv run --with \"flamepy @ file://...\"' to access it.\n\ + No separate installation required.\n", + ) + .ok(); // Ignore errors for this informational file - // Copy SDK source to the installation directory - self.copy_dir_all(&sdk_src, &sdk_install_src) - .context("Failed to copy SDK to installation directory")?; + Ok(()) + } - // Set ownership to flame:flame for the entire sdk/python directory tree - self.user_manager.set_ownership(&paths.sdk_python)?; + /// Copy SDK directory while excluding development artifacts + fn copy_sdk_excluding_artifacts(&self, src: &Path, dst: &Path) -> Result<()> { + use walkdir::WalkDir; + + let exclude_patterns = [ + ".venv", + "__pycache__", + ".pytest_cache", + ".pyc", + ".pyo", + ".eggs", + ".egg-info", + ".tox", + ".coverage", + ".mypy_cache", + ".ruff_cache", + "build", + "dist", + ]; - // Install using pip as flame user with --user flag - let output = Command::new("sudo") - .args([ - "-u", - "flame", - "-H", // Set HOME to flame user's home directory - pip_cmd.to_str().unwrap(), - "install", - "--user", - sdk_install_src.to_str().unwrap(), - ]) - .output() - .context("Failed to install Python SDK as flame user")?; - - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); - anyhow::bail!("Failed to install Python SDK as flame user: {}", stderr); - } + fs::create_dir_all(dst).context("Failed to create destination directory")?; + + for entry in WalkDir::new(src).into_iter().filter_entry(|e| { + // Filter out directories and files matching exclude patterns + let file_name = e.file_name().to_string_lossy(); + !exclude_patterns + .iter() + .any(|pattern| file_name.contains(pattern) || file_name == *pattern) + }) { + let entry = entry.context("Failed to read directory entry")?; + let entry_path = entry.path(); - println!("✓ Installed Python SDK for flame user"); - - // Create a note in the sdk_python directory for reference - let readme_path = paths.sdk_python.join("README.txt"); - std::fs::write( - &readme_path, - "Python SDK installed for flame user in /var/lib/flame/.local/lib/python*/site-packages\n\ - SDK source copied to this directory for installation.\n\ - To verify: sudo -u flame pip3 show flamepy\n", - ).ok(); // Ignore errors for this informational file - } else { - println!(" Installing Python SDK for current user..."); - - // Install using pip with --user flag for current user - let output = Command::new(&pip_cmd) - .args(["install", "--user", sdk_src.to_str().unwrap()]) - .output() - .context("Failed to install Python SDK")?; - - if !output.status.success() { - let stderr = String::from_utf8_lossy(&output.stderr); - anyhow::bail!("Failed to install Python SDK: {}", stderr); + // Skip the source root itself + if entry_path == src { + continue; } - println!("✓ Installed Python SDK for current user"); + // Calculate relative path and destination + let relative_path = entry_path + .strip_prefix(src) + .context("Failed to strip prefix")?; + let dst_path = dst.join(relative_path); - // Create a note in the sdk_python directory for reference - let readme_path = paths.sdk_python.join("README.txt"); - std::fs::write( - &readme_path, - "Python SDK installed for current user.\nUse 'pip3 show flamepy' to see installation location.\n", - ).ok(); // Ignore errors for this informational file + if entry.file_type().is_dir() { + fs::create_dir_all(&dst_path) + .context(format!("Failed to create directory {:?}", dst_path))?; + } else { + // Ensure parent directory exists + if let Some(parent) = dst_path.parent() { + fs::create_dir_all(parent)?; + } + fs::copy(entry_path, &dst_path) + .context(format!("Failed to copy {:?}", entry_path))?; + } } Ok(()) @@ -285,6 +272,13 @@ impl InstallationManager { println!(" ✓ Removed working directory"); } + // Remove events directory (session-manager creates this in prefix) + let events_dir = paths.prefix.join("events"); + if events_dir.exists() { + fs::remove_dir_all(&events_dir).context("Failed to remove events directory")?; + println!(" ✓ Removed events directory"); + } + // Remove data directory (unless preserved) if !preserve_data && paths.data.exists() { fs::remove_dir_all(&paths.data).context("Failed to remove data directory")?; diff --git a/flmadm/src/managers/systemd.rs b/flmadm/src/managers/systemd.rs index a82e24e1..da1a76aa 100644 --- a/flmadm/src/managers/systemd.rs +++ b/flmadm/src/managers/systemd.rs @@ -249,6 +249,7 @@ User=flame Group=flame Environment="RUST_LOG=info" Environment="HOME=/var/lib/flame" +Environment="FLAME_HOME={prefix}" WorkingDirectory={prefix} ExecStart={prefix}/bin/flame-session-manager --config {prefix}/conf/flame-cluster.yaml StandardOutput=append:{prefix}/logs/fsm.log @@ -279,6 +280,7 @@ User=flame Group=flame Environment="RUST_LOG=info" Environment="HOME=/var/lib/flame" +Environment="FLAME_HOME={prefix}" WorkingDirectory={prefix}/work ExecStart={prefix}/bin/flame-executor-manager --config {prefix}/conf/flame-cluster.yaml StandardOutput=append:{prefix}/logs/fem.log diff --git a/hack/local-test.sh b/hack/local-test.sh index dc4ab0df..b22e12fd 100755 --- a/hack/local-test.sh +++ b/hack/local-test.sh @@ -42,7 +42,7 @@ case "$1" in # Start session manager log_info "Starting session manager..." - "$INSTALL_PREFIX/bin/flame-session-manager" \ + FLAME_HOME="$INSTALL_PREFIX" "$INSTALL_PREFIX/bin/flame-session-manager" \ --config "$INSTALL_PREFIX/conf/flame-cluster.yaml" \ > "$INSTALL_PREFIX/logs/fsm.log" 2>&1 & echo $! > /tmp/flame-fsm.pid @@ -52,7 +52,7 @@ case "$1" in # Start executor manager log_info "Starting executor manager..." - "$INSTALL_PREFIX/bin/flame-executor-manager" \ + FLAME_HOME="$INSTALL_PREFIX" "$INSTALL_PREFIX/bin/flame-executor-manager" \ --config "$INSTALL_PREFIX/conf/flame-cluster.yaml" \ > "$INSTALL_PREFIX/logs/fem.log" 2>&1 & echo $! > /tmp/flame-fem.pid diff --git a/sdk/python/pyproject.toml b/sdk/python/pyproject.toml index 99e7cd03..ac68046f 100644 --- a/sdk/python/pyproject.toml +++ b/sdk/python/pyproject.toml @@ -7,7 +7,7 @@ name = "flamepy" version = "0.5.0" description = "Python SDK for Flame, a distributed system for Agentic AI" readme = "README.md" -requires-python = ">=3.8" +requires-python = ">=3.9" license-files = ["LICENSE"] authors = [ {name = "XFLOPS Authors", email = "support@xflops.io"} diff --git a/sdk/python/src/flamepy/core/service.py b/sdk/python/src/flamepy/core/service.py index c872fcb3..8d5fdeef 100644 --- a/sdk/python/src/flamepy/core/service.py +++ b/sdk/python/src/flamepy/core/service.py @@ -14,7 +14,6 @@ import logging import os import sys -import typing from abc import abstractmethod from concurrent import futures from dataclasses import dataclass @@ -31,6 +30,7 @@ def override(func): # type: ignore return func + import grpc from flamepy.core.types import FlameError, FlameErrorCode, Shim, TaskOutput From b9e9f9e5fcfab15dea355975c70be3320a6ccdf6 Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Fri, 30 Jan 2026 13:13:21 +0000 Subject: [PATCH 06/13] deploy uv to /usr/bin/ in e2e-bm.yaml Signed-off-by: Klaus Ma --- .github/workflows/e2e-bm.yaml | 4 ++++ flmadm/src/managers/installation.rs | 12 ++++++++++++ flmadm/src/types.rs | 12 ++++++++++++ 3 files changed, 28 insertions(+) diff --git a/.github/workflows/e2e-bm.yaml b/.github/workflows/e2e-bm.yaml index 80891cd3..baa84d80 100644 --- a/.github/workflows/e2e-bm.yaml +++ b/.github/workflows/e2e-bm.yaml @@ -31,6 +31,10 @@ jobs: run: | curl -LsSf https://astral.sh/uv/install.sh | sh echo "$HOME/.cargo/bin" >> $GITHUB_PATH + # Install uv to /usr/bin for flmrun service + sudo cp $HOME/.cargo/bin/uv /usr/bin/uv + sudo chmod +x /usr/bin/uv + echo "✓ Installed uv to /usr/bin/uv for flmrun" - name: Install system dependencies run: | diff --git a/flmadm/src/managers/installation.rs b/flmadm/src/managers/installation.rs index c0877db4..97eb44eb 100644 --- a/flmadm/src/managers/installation.rs +++ b/flmadm/src/managers/installation.rs @@ -98,6 +98,18 @@ impl InstallationManager { ), ("flmctl", &artifacts.flmctl, paths.bin.join("flmctl")), ("flmadm", &artifacts.flmadm, paths.bin.join("flmadm")), + ("flmping", &artifacts.flmping, paths.bin.join("flmping")), + ( + "flmping-service", + &artifacts.flmping_service, + paths.bin.join("flmping-service"), + ), + ("flmexec", &artifacts.flmexec, paths.bin.join("flmexec")), + ( + "flmexec-service", + &artifacts.flmexec_service, + paths.bin.join("flmexec-service"), + ), ] { fs::copy(src, &dst).context(format!("Failed to copy {} binary", name))?; diff --git a/flmadm/src/types.rs b/flmadm/src/types.rs index 01bc3f7a..693baf01 100644 --- a/flmadm/src/types.rs +++ b/flmadm/src/types.rs @@ -96,6 +96,10 @@ pub struct BuildArtifacts { pub executor_manager: PathBuf, pub flmctl: PathBuf, pub flmadm: PathBuf, + pub flmping: PathBuf, + pub flmping_service: PathBuf, + pub flmexec: PathBuf, + pub flmexec_service: PathBuf, } impl BuildArtifacts { @@ -108,6 +112,10 @@ impl BuildArtifacts { executor_manager: target_dir.join("flame-executor-manager"), flmctl: target_dir.join("flmctl"), flmadm: target_dir.join("flmadm"), + flmping: target_dir.join("flmping"), + flmping_service: target_dir.join("flmping-service"), + flmexec: target_dir.join("flmexec"), + flmexec_service: target_dir.join("flmexec-service"), }; // Verify all artifacts exist @@ -116,6 +124,10 @@ impl BuildArtifacts { ("flame-executor-manager", &artifacts.executor_manager), ("flmctl", &artifacts.flmctl), ("flmadm", &artifacts.flmadm), + ("flmping", &artifacts.flmping), + ("flmping-service", &artifacts.flmping_service), + ("flmexec", &artifacts.flmexec), + ("flmexec-service", &artifacts.flmexec_service), ] { if !path.exists() { anyhow::bail!("Build artifact not found: {} at {:?}", name, path); From e4c7573e845aa60cec7766744b3682a6b953db4f Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Fri, 30 Jan 2026 13:18:09 +0000 Subject: [PATCH 07/13] fix uv path issue. Signed-off-by: Klaus Ma --- .github/workflows/e2e-bm.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-bm.yaml b/.github/workflows/e2e-bm.yaml index baa84d80..dff6cadf 100644 --- a/.github/workflows/e2e-bm.yaml +++ b/.github/workflows/e2e-bm.yaml @@ -30,9 +30,9 @@ jobs: - name: Install uv run: | curl -LsSf https://astral.sh/uv/install.sh | sh - echo "$HOME/.cargo/bin" >> $GITHUB_PATH + echo "$HOME/.local/bin" >> $GITHUB_PATH # Install uv to /usr/bin for flmrun service - sudo cp $HOME/.cargo/bin/uv /usr/bin/uv + sudo cp $HOME/.local/bin/uv /usr/bin/uv sudo chmod +x /usr/bin/uv echo "✓ Installed uv to /usr/bin/uv for flmrun" From 733f6e080319d2c75933e1729125d33ea1c372d3 Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Fri, 30 Jan 2026 15:35:59 +0000 Subject: [PATCH 08/13] install flamepy before e2e py test. Signed-off-by: Klaus Ma --- Makefile | 5 ++++- docker/Dockerfile.console | 2 +- flmadm/src/commands/install.rs | 11 +++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 6ef0f34a..00cfceb5 100644 --- a/Makefile +++ b/Makefile @@ -103,9 +103,12 @@ e2e-py: ## Run Python E2E tests (use e2e-py-docker for docker compose or e2e-py- @echo "Use 'make e2e-py-docker' for docker compose tests or 'make e2e-py-local' for local cluster tests" e2e-py-docker: ## Run Python E2E tests with docker compose + @echo "Installing flamepy in console container for test client..." + $(CONTAINER_RUNTIME) compose exec flame-console uv pip install --system /usr/local/flame/sdk/python + @echo "Running e2e tests..." $(CONTAINER_RUNTIME) compose exec -w /opt/e2e flame-console uv run -n pytest -vv --durations=0 . -e2e-py-local: ## Run Python E2E tests against local cluster +e2e-py-local: ## Run Python E2E tests against local cluster (requires flamepy installed via pip) cd e2e && FLAME_ENDPOINT=$(FLAME_ENDPOINT) uv run pytest -vv --durations=0 . e2e-rs: ## Run Rust E2E tests diff --git a/docker/Dockerfile.console b/docker/Dockerfile.console index 180151ee..2501bb29 100644 --- a/docker/Dockerfile.console +++ b/docker/Dockerfile.console @@ -14,7 +14,7 @@ COPY --from=builder /usr/local/cargo/bin/flmping /usr/local/bin/flmping COPY --from=builder /usr/local/cargo/bin/flmctl /usr/local/bin/flmctl COPY --from=builder /usr/local/cargo/bin/flmexec /usr/local/bin/flmexec -COPY --from=ghcr.io/astral-sh/uv:0.9.26 /uv /uvx /bin/ +COPY --from=ghcr.io/astral-sh/uv:0.9.26 /uv /uvx /usr/bin/ RUN chmod +x /usr/local/bin/* diff --git a/flmadm/src/commands/install.rs b/flmadm/src/commands/install.rs index 3682abc0..3f3b0f0f 100644 --- a/flmadm/src/commands/install.rs +++ b/flmadm/src/commands/install.rs @@ -80,6 +80,17 @@ fn validate_config(config: &InstallConfig) -> Result<()> { anyhow::bail!("Cannot use --enable without systemd (--no-systemd conflicts with --enable)"); } + // Check if uv is available at /usr/bin/uv (required by flmrun) + let uv_path = std::path::Path::new("/usr/bin/uv"); + if !uv_path.exists() { + anyhow::bail!( + "uv is not installed at /usr/bin/uv (required by flmrun service)\n\ + Please install uv using one of these methods:\n\ + 1. curl -LsSf https://astral.sh/uv/install.sh | sh && sudo cp ~/.local/bin/uv /usr/bin/uv\n\ + 2. Or install uv via your package manager and ensure it's at /usr/bin/uv" + ); + } + println!("✓ Configuration validated"); Ok(()) } From 8a8859518e35a4a1e7b0b646ba327dae9632b776 Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Sat, 31 Jan 2026 00:13:46 +0000 Subject: [PATCH 09/13] install flamepy in flame-console Signed-off-by: Klaus Ma --- Makefile | 5 +---- docker/Dockerfile.console | 5 ++++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 00cfceb5..077c5514 100644 --- a/Makefile +++ b/Makefile @@ -103,13 +103,10 @@ e2e-py: ## Run Python E2E tests (use e2e-py-docker for docker compose or e2e-py- @echo "Use 'make e2e-py-docker' for docker compose tests or 'make e2e-py-local' for local cluster tests" e2e-py-docker: ## Run Python E2E tests with docker compose - @echo "Installing flamepy in console container for test client..." - $(CONTAINER_RUNTIME) compose exec flame-console uv pip install --system /usr/local/flame/sdk/python - @echo "Running e2e tests..." $(CONTAINER_RUNTIME) compose exec -w /opt/e2e flame-console uv run -n pytest -vv --durations=0 . e2e-py-local: ## Run Python E2E tests against local cluster (requires flamepy installed via pip) - cd e2e && FLAME_ENDPOINT=$(FLAME_ENDPOINT) uv run pytest -vv --durations=0 . + cd e2e && PYTHONPATH="$(CURDIR)/e2e/src:$$PYTHONPATH" FLAME_ENDPOINT=$(FLAME_ENDPOINT) pytest -vv --durations=0 . e2e-rs: ## Run Rust E2E tests cargo test --workspace --exclude cri-rs -- --nocapture diff --git a/docker/Dockerfile.console b/docker/Dockerfile.console index 2501bb29..3f2a403a 100644 --- a/docker/Dockerfile.console +++ b/docker/Dockerfile.console @@ -9,7 +9,7 @@ RUN cargo install --path ./flmexec FROM ubuntu:24.04 -RUN apt-get update && apt-get install -y wget vim iputils-ping ssh curl +RUN apt-get update && apt-get install -y wget vim iputils-ping ssh curl python3 python3-pip COPY --from=builder /usr/local/cargo/bin/flmping /usr/local/bin/flmping COPY --from=builder /usr/local/cargo/bin/flmctl /usr/local/bin/flmctl COPY --from=builder /usr/local/cargo/bin/flmexec /usr/local/bin/flmexec @@ -20,4 +20,7 @@ RUN chmod +x /usr/local/bin/* COPY ./sdk/python /usr/local/flame/sdk/python +# Install flamepy for test client using uv +RUN uv pip install --system --no-cache /usr/local/flame/sdk/python + CMD ["service", "ssh", "start", "-D"] From 3e92a0e7f715abd6a2cd73d2c8dbe248a844e9a8 Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Sat, 31 Jan 2026 01:43:55 +0000 Subject: [PATCH 10/13] install flamepy in system-wide. Signed-off-by: Klaus Ma --- docker/Dockerfile.console | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile.console b/docker/Dockerfile.console index 3f2a403a..b4d696ac 100644 --- a/docker/Dockerfile.console +++ b/docker/Dockerfile.console @@ -21,6 +21,6 @@ RUN chmod +x /usr/local/bin/* COPY ./sdk/python /usr/local/flame/sdk/python # Install flamepy for test client using uv -RUN uv pip install --system --no-cache /usr/local/flame/sdk/python +RUN uv pip install --system --break-system-packages --no-cache /usr/local/flame/sdk/python CMD ["service", "ssh", "start", "-D"] From eb3894d01107233e98ff0ebde6a570f1d37ec436 Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Sat, 31 Jan 2026 02:41:45 +0000 Subject: [PATCH 11/13] Update e2e script. Signed-off-by: Klaus Ma --- .dockerignore | 3 +++ Makefile | 2 +- docker/Dockerfile.console | 4 ++-- e2e/src/e2e/basic_svc.py | 5 ++--- e2e/src/e2e/error_svc.py | 3 +-- e2e/src/e2e/helpers.py | 5 ++--- e2e/src/e2e/instance_svc.py | 1 - 7 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.dockerignore b/.dockerignore index 33c749b9..e92ff08f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -18,6 +18,9 @@ ci/ **/.Python **/.pytest_cache **/*.egg-info/ +**/*.egg/ +**/.uv/ +**/.pip/ # Ignore build related stuff **/build/ diff --git a/Makefile b/Makefile index 077c5514..f035e60c 100644 --- a/Makefile +++ b/Makefile @@ -103,7 +103,7 @@ e2e-py: ## Run Python E2E tests (use e2e-py-docker for docker compose or e2e-py- @echo "Use 'make e2e-py-docker' for docker compose tests or 'make e2e-py-local' for local cluster tests" e2e-py-docker: ## Run Python E2E tests with docker compose - $(CONTAINER_RUNTIME) compose exec -w /opt/e2e flame-console uv run -n pytest -vv --durations=0 . + $(CONTAINER_RUNTIME) compose exec -w /opt/e2e -e PYTHONPATH=/opt/e2e/src flame-console python3 -m pytest -vv --durations=0 . e2e-py-local: ## Run Python E2E tests against local cluster (requires flamepy installed via pip) cd e2e && PYTHONPATH="$(CURDIR)/e2e/src:$$PYTHONPATH" FLAME_ENDPOINT=$(FLAME_ENDPOINT) pytest -vv --durations=0 . diff --git a/docker/Dockerfile.console b/docker/Dockerfile.console index b4d696ac..3bee2d15 100644 --- a/docker/Dockerfile.console +++ b/docker/Dockerfile.console @@ -20,7 +20,7 @@ RUN chmod +x /usr/local/bin/* COPY ./sdk/python /usr/local/flame/sdk/python -# Install flamepy for test client using uv -RUN uv pip install --system --break-system-packages --no-cache /usr/local/flame/sdk/python +# Install flamepy and pytest for test client using uv +RUN uv pip install --system --break-system-packages --no-cache /usr/local/flame/sdk/python pytest CMD ["service", "ssh", "start", "-D"] diff --git a/e2e/src/e2e/basic_svc.py b/e2e/src/e2e/basic_svc.py index 60a80316..3f342365 100644 --- a/e2e/src/e2e/basic_svc.py +++ b/e2e/src/e2e/basic_svc.py @@ -15,7 +15,6 @@ import logging from typing import Optional -from flamepy.core.types import TaskOutput from e2e.api import ( TestRequest, @@ -58,7 +57,7 @@ def on_session_enter(self, context: flamepy.SessionContext): f"task count reset to: {self._task_count}" ) - def on_task_invoke(self, context: flamepy.TaskContext) -> Optional[TaskOutput]: + def on_task_invoke(self, context: flamepy.TaskContext) -> Optional[flamepy.TaskOutput]: """Handle task invoke and return response with optional context information.""" logger.info( f"Task invoked: task_id={context.task_id}, " @@ -204,7 +203,7 @@ def on_task_invoke(self, context: flamepy.TaskContext) -> Optional[TaskOutput]: f"Task completed successfully: task_id={context.task_id}, " f"response_size={len(response_bytes)} bytes" ) - return TaskOutput(response_bytes) + return flamepy.TaskOutput(response_bytes) def on_session_leave(self): """Handle session leave.""" diff --git a/e2e/src/e2e/error_svc.py b/e2e/src/e2e/error_svc.py index b7305d2e..f6d22592 100644 --- a/e2e/src/e2e/error_svc.py +++ b/e2e/src/e2e/error_svc.py @@ -14,7 +14,6 @@ import flamepy import logging from typing import Optional -from flamepy.core.types import TaskOutput logger = logging.getLogger(__name__) @@ -31,7 +30,7 @@ def on_session_enter(self, context: flamepy.SessionContext): logger.info(f"Session entered: session_id={context.session_id}") self._session_context = context - def on_task_invoke(self, context: flamepy.TaskContext) -> Optional[TaskOutput]: + def on_task_invoke(self, context: flamepy.TaskContext) -> Optional[flamepy.TaskOutput]: """Handle task invoke by raising an exception.""" logger.info( f"Task invoked: task_id={context.task_id}, session_id={context.session_id}" diff --git a/e2e/src/e2e/helpers.py b/e2e/src/e2e/helpers.py index d9eed5f4..11241acb 100644 --- a/e2e/src/e2e/helpers.py +++ b/e2e/src/e2e/helpers.py @@ -7,9 +7,8 @@ import cloudpickle from dataclasses import asdict from typing import Optional, Any -from flamepy.core import ObjectRef, put_object, get_object -from flamepy.core.types import short_name -from flamepy.rl.types import RunnerContext, RunnerRequest +from flamepy import ObjectRef, put_object, get_object, short_name +from flamepy.rl import RunnerContext, RunnerRequest from e2e.api import ( TestRequest, diff --git a/e2e/src/e2e/instance_svc.py b/e2e/src/e2e/instance_svc.py index 63a821a6..7be818f7 100644 --- a/e2e/src/e2e/instance_svc.py +++ b/e2e/src/e2e/instance_svc.py @@ -11,7 +11,6 @@ limitations under the License. """ -import flamepy from flamepy import agent from e2e.api import TestRequest, TestResponse, TestContext From c33dcd04bf65a31b4b8301d8081a49990bdc0da4 Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Sat, 31 Jan 2026 03:15:30 +0000 Subject: [PATCH 12/13] export ObjectRef in flamepy Signed-off-by: Klaus Ma --- e2e/src/e2e/helpers.py | 3 ++- sdk/python/src/flamepy/__init__.py | 14 ++++++++------ sdk/python/src/flamepy/util/__init__.py | 25 +++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 7 deletions(-) create mode 100644 sdk/python/src/flamepy/util/__init__.py diff --git a/e2e/src/e2e/helpers.py b/e2e/src/e2e/helpers.py index 11241acb..da5d81e2 100644 --- a/e2e/src/e2e/helpers.py +++ b/e2e/src/e2e/helpers.py @@ -7,7 +7,8 @@ import cloudpickle from dataclasses import asdict from typing import Optional, Any -from flamepy import ObjectRef, put_object, get_object, short_name +from flamepy import ObjectRef, put_object, get_object +from flamepy.util import short_name from flamepy.rl import RunnerContext, RunnerRequest from e2e.api import ( diff --git a/sdk/python/src/flamepy/__init__.py b/sdk/python/src/flamepy/__init__.py index 6bd3863b..e2585dd4 100644 --- a/sdk/python/src/flamepy/__init__.py +++ b/sdk/python/src/flamepy/__init__.py @@ -11,8 +11,8 @@ limitations under the License. """ -# Import submodules for rl and agent (only as submodules) -from . import agent, rl +# Import submodules for rl, agent, and util (only as submodules) +from . import agent, rl, util # Export all core classes/types at top level from .core import ( # Type aliases; Constants; Enums; Exception classes; Data classes; Context and utility classes; Client functions; Client classes; Service constants; Service context classes; Service base classes; Service functions @@ -36,6 +36,7 @@ FlamePackage, FlameService, Message, + ObjectRef, Session, SessionAttributes, SessionContext, @@ -54,13 +55,16 @@ connect, create_session, get_application, + get_object, get_session, list_applications, list_sessions, open_session, + put_object, register_application, run, unregister_application, + update_object, ) __version__ = "0.3.0" @@ -125,14 +129,12 @@ "run", # Cache classes "ObjectRef", - "Object", - "ObjectMetadata", # Cache functions "get_object", "put_object", "update_object", - "suppress_dependency_logs", - # Submodules (rl and agent only) + # Submodules "agent", "rl", + "util", ] diff --git a/sdk/python/src/flamepy/util/__init__.py b/sdk/python/src/flamepy/util/__init__.py new file mode 100644 index 00000000..9153916d --- /dev/null +++ b/sdk/python/src/flamepy/util/__init__.py @@ -0,0 +1,25 @@ +""" +Copyright 2025 The Flame Authors. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" + +import random +import string + + +def short_name(prefix: str, length: int = 6) -> str: + """Generate a short name with a prefix.""" + alphabet = string.ascii_letters + string.digits + sn = "".join(random.SystemRandom().choice(alphabet) for _ in range(length)) + return f"{prefix}-{sn}" + + +__all__ = ["short_name"] From 6ae96e6f49ee945621084443fbee403dbc31c2bc Mon Sep 17 00:00:00 2001 From: Klaus Ma Date: Sat, 31 Jan 2026 06:09:49 +0000 Subject: [PATCH 13/13] add flamepy path to e2e. Signed-off-by: Klaus Ma --- e2e/pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/e2e/pyproject.toml b/e2e/pyproject.toml index c6561c42..d88ca7ae 100644 --- a/e2e/pyproject.toml +++ b/e2e/pyproject.toml @@ -32,3 +32,6 @@ dev = [ "isort>=5.0.0", ] +[tool.uv.sources] +flamepy = { path = "/usr/local/flame/sdk/python", editable = true } +