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
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
/cli/azd/extensions/azure.ai.inspector/ @JeffreyCA @glharper @trangevi @trrwilson @therealjohn @anchenyi @XiaofuHuang
/cli/azd/extensions/azure.ai.models/ @JeffreyCA @trangevi @achauhan-scc @kingernupur @saanikaguptamicrosoft
/cli/azd/extensions/azure.ai.projects/ @JeffreyCA @glharper @trangevi @trrwilson @therealjohn @huimiu @hund030
/cli/azd/extensions/azure.ai.rle/ @JeffreyCA @glharper @trangevi @trrwilson @therealjohn @huimiu @hund030
/cli/azd/extensions/azure.ai.routines/ @JeffreyCA @glharper @trangevi @trrwilson @therealjohn @huimiu @hund030
/cli/azd/extensions/azure.ai.skills/ @JeffreyCA @glharper @trangevi @trrwilson @therealjohn @huimiu @hund030
/cli/azd/extensions/azure.ai.toolboxes/ @JeffreyCA @glharper @trangevi @trrwilson @therealjohn @huimiu @hund030
Expand Down
22 changes: 22 additions & 0 deletions .github/workflows/lint-ext-azure-ai-rle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: ext-azure-ai-rle-ci

on:
pull_request:
paths:
- "cli/azd/extensions/azure.ai.rle/**"
- ".github/workflows/lint-ext-azure-ai-rle.yml"
branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

permissions:
contents: read
pull-requests: write

jobs:
lint:
uses: ./.github/workflows/lint-go.yml
with:
working-directory: cli/azd/extensions/azure.ai.rle
2 changes: 1 addition & 1 deletion .github/workflows/test-ext-azure-ai-agents.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
# Build azure.ai.inspector from source to ensure PR CI always has a
# compatible version — dependency releases are post-merge, but PRs may
# include inspector changes from this same repo.
pwsh -File ci-build.ps1 -OutputFileName azure-ai-inspector-linux-amd64 -Version $(cat version.txt | tr -d '\r\n')
pwsh -File ci-build.ps1 -OutputFileName azure-ai-inspector-linux-amd64 -Version "$(cat version.txt | tr -d '\r\n')"
mkdir -p bin
mv azure-ai-inspector-linux-amd64 bin/
azd x pack
Expand Down
3 changes: 3 additions & 0 deletions cli/azd/extensions/azure.ai.rle/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
bin/
artifacts/
registry-artifacts/
17 changes: 17 additions & 0 deletions cli/azd/extensions/azure.ai.rle/.golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: "2"

linters:
default: none
enable:
- gosec
- lll
- unused
- errorlint
settings:
lll:
line-length: 220
tab-width: 4

formatters:
enable:
- gofmt
5 changes: 5 additions & 0 deletions cli/azd/extensions/azure.ai.rle/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Release History

## 0.1.0-preview

- Initial preview scaffold for the RLE extension with `init`, `run`, `invoke`, `deploy`, and `version` commands.
172 changes: 172 additions & 0 deletions cli/azd/extensions/azure.ai.rle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# Azure AI RLE extension for azd

Quickstart for the `azd ai rle` preview extension. The extension manages an OpenEnv-style RLE environment lifecycle: init, build and run the environment container, test it through a playground UI or shell, and deploy the environment image to the RLE control plane.

## Prerequisites

Install:

- Azure Developer CLI (`azd`): https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd
- Docker Desktop: https://www.docker.com/products/docker-desktop/
- Go, if building from source: https://go.dev/doc/install
- Git, if building from source: https://git-scm.com/downloads

Verify:

```powershell
azd version
docker version
```

## Install the extension from this checkout

From `cli\azd\extensions\azure.ai.rle`:

```powershell
azd extension install microsoft.azd.extensions
azd x build
azd x pack
azd x publish
azd extension install azure.ai.rle --source local --force
```

Verify:

```powershell
azd ai rle --help
azd ai rle version
```

After code changes, rerun:

```powershell
azd x build
azd x pack
azd x publish
azd extension install azure.ai.rle --source local --force
```

## Configure the RLE control plane

The extension defaults to the local RLE control plane at `http://localhost:5000`. To target another control plane:

```powershell
$env:RLE_ENDPOINT = "https://<rle-control-plane>"
```

Deploy uses a Foundry project endpoint and an ACR image for the registered RLE environment. Set them once:

```powershell
$env:FOUNDRY_PROJECT_ENDPOINT = "https://<account>.services.ai.azure.com/api/projects/<project>"
$env:AZURE_CONTAINER_REGISTRY_ENDPOINT = "<registry>.azurecr.io"
```

## Quickstart

Discovery for all commands is currently disabled using `AZD_AI_RLE_ENABLE`. To enable:

```powershell
$env:AZD_AI_RLE_ENABLE = "true"
```

### 1. Initialize an environment session

Default echo session:

```powershell
azd ai rle init
cd .\echo_env
```

The default echo session downloads the Hugging Face `OpenEnv` repo, copies `envs/echo_env` into the session folder,
and writes `.azd-rle.json` with the local environment name.

The copied session does not keep `.git` metadata from the upstream repository.

Name the copied echo session:

```powershell
azd ai rle init code_rl
```

For an existing source folder, skip `init` and run commands directly from that folder.

### 2. Run locally

```powershell
azd ai rle run
```

`run` builds a local Docker image from the current source folder, removes any stale local container for the
same environment name, starts a fresh container, waits for `/health`, opens the playground UI at `/web`, and
keeps an OpenEnv shell attached. When the shell exits or Ctrl+C is received, `run` removes the local container.

If `.azd-rle.json`
does not exist, `run` creates it with only the inferred local environment name.

Use a custom host port:

```powershell
azd ai rle run --port 9000
```

`run` looks for `Dockerfile` at the source root, then `server\Dockerfile`. If the Dockerfile is elsewhere,
pass it explicitly:

```powershell
azd ai rle run --dockerfile server\Dockerfile
```

Rebuild automatically while editing local source:

```powershell
azd ai rle run --watch
```

The shell supports the standard OpenEnv commands:

```text
rle> health
rle> reset {"seed":0}
rle> step {"message":"hello"}
rle> state
rle> exit
```

Supported shell commands:

| Command | Calls |
|---|---|
| `health` | `GET /health` |
| `reset [json]` | `POST /reset` |
| `step <json-action>` | `POST /step` with `{ "action": <json-action> }` |
| `state` | `GET /state` |
| `metadata` | `GET /metadata` |
| `schema` | `GET /schema` |
| `exit` / `quit` | Exit shell |

### 3. Deploy/register

```powershell
$env:FOUNDRY_PROJECT_ENDPOINT = "https://<account>.services.ai.azure.com/api/projects/<project>"
$env:AZURE_CONTAINER_REGISTRY_ENDPOINT = "<registry>.azurecr.io"
azd ai rle deploy
```

Deploy reads the Foundry project endpoint from `FOUNDRY_PROJECT_ENDPOINT` and the ACR registry from `AZURE_CONTAINER_REGISTRY_ENDPOINT` in the terminal environment. It derives the project route segment from `/api/projects/<project>`, builds the Docker image as `<registry>.azurecr.io/<project>-<environment>:latest`, pushes it to ACR, registers that image with the RLE control plane, and saves the project/environment details in `.azd-rle.json`.
The deploy command prints a CLI-friendly summary using `environmentId`, `acrImage`, `version`, `createdAt`, and `updatedAt`.

If needed, override the Dockerfile path the same way as local run:

```powershell
azd ai rle deploy --dockerfile server\Dockerfile
```

### 4. Invoke remotely

Remote invoke uses the deployed environment, leases a sandbox, opens the sandbox `/web` UI when available
(or a local proxy UI otherwise), keeps the shell attached, and releases the sandbox when the shell exits:

```powershell
azd ai rle invoke --timeout 60
```
78 changes: 78 additions & 0 deletions cli/azd/extensions/azure.ai.rle/build.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Ensure script fails on any error
$ErrorActionPreference = 'Stop'

# Get the directory of the script
$EXTENSION_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path

# Change to the script directory
Set-Location -Path $EXTENSION_DIR

# Create a safe version of EXTENSION_ID replacing dots with dashes
$EXTENSION_ID_SAFE = $env:EXTENSION_ID -replace '\.', '-'

# Define output directory
$OUTPUT_DIR = if ($env:OUTPUT_DIR) { $env:OUTPUT_DIR } else { Join-Path $EXTENSION_DIR "bin" }

# Create output directory if it doesn't exist
if (-not (Test-Path -Path $OUTPUT_DIR)) {
New-Item -ItemType Directory -Path $OUTPUT_DIR | Out-Null
}

# Get Git commit hash and build date
$COMMIT = git rev-parse HEAD
if ($LASTEXITCODE -ne 0) {
Write-Host "Error: Failed to get git commit hash"
exit 1
}
$BUILD_DATE = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")

# List of OS and architecture combinations
if ($env:EXTENSION_PLATFORM) {
$PLATFORMS = @($env:EXTENSION_PLATFORM)
}
else {
$PLATFORMS = @(
"windows/amd64",
"windows/arm64",
"darwin/amd64",
"darwin/arm64",
"linux/amd64",
"linux/arm64"
)
}

$APP_PATH = "$env:EXTENSION_ID/internal/cmd"

# Loop through platforms and build
foreach ($PLATFORM in $PLATFORMS) {
$OS, $ARCH = $PLATFORM -split '/'

$OUTPUT_NAME = Join-Path $OUTPUT_DIR "$EXTENSION_ID_SAFE-$OS-$ARCH"

if ($OS -eq "windows") {
$OUTPUT_NAME += ".exe"
}

Write-Host "Building for $OS/$ARCH..."

# Delete the output file if it already exists
if (Test-Path -Path $OUTPUT_NAME) {
Remove-Item -Path $OUTPUT_NAME -Force
}

# Set environment variables for Go build
$env:GOOS = $OS
$env:GOARCH = $ARCH

go build `
-ldflags="-X '$APP_PATH.Version=$env:EXTENSION_VERSION' -X '$APP_PATH.Commit=$COMMIT' -X '$APP_PATH.BuildDate=$BUILD_DATE'" `
-o $OUTPUT_NAME

if ($LASTEXITCODE -ne 0) {
Write-Host "An error occurred while building for $OS/$ARCH"
exit 1
}
}

Write-Host "Build completed successfully!"
Write-Host "Binaries are located in the $OUTPUT_DIR directory."
66 changes: 66 additions & 0 deletions cli/azd/extensions/azure.ai.rle/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/bash

# Get the directory of the script
EXTENSION_DIR="$(cd "$(dirname "$0")" && pwd)"

# Change to the script directory
cd "$EXTENSION_DIR" || exit

# Create a safe version of EXTENSION_ID replacing dots with dashes
EXTENSION_ID_SAFE="${EXTENSION_ID//./-}"

# Define output directory
OUTPUT_DIR="${OUTPUT_DIR:-$EXTENSION_DIR/bin}"

# Create output and target directories if they don't exist
mkdir -p "$OUTPUT_DIR"

# Get Git commit hash and build date
COMMIT=$(git rev-parse HEAD)
BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)

# List of OS and architecture combinations
if [ -n "$EXTENSION_PLATFORM" ]; then
PLATFORMS=("$EXTENSION_PLATFORM")
else
PLATFORMS=(
"windows/amd64"
"windows/arm64"
"darwin/amd64"
"darwin/arm64"
"linux/amd64"
"linux/arm64"
)
fi

APP_PATH="$EXTENSION_ID/internal/cmd"

# Loop through platforms and build
for PLATFORM in "${PLATFORMS[@]}"; do
OS=$(echo "$PLATFORM" | cut -d'/' -f1)
ARCH=$(echo "$PLATFORM" | cut -d'/' -f2)

OUTPUT_NAME="$OUTPUT_DIR/$EXTENSION_ID_SAFE-$OS-$ARCH"

if [ "$OS" = "windows" ]; then
OUTPUT_NAME+='.exe'
fi

echo "Building for $OS/$ARCH..."

# Delete the output file if it already exists
[ -f "$OUTPUT_NAME" ] && rm -f "$OUTPUT_NAME"

# Set environment variables for Go build
GOOS=$OS GOARCH=$ARCH go build \
-ldflags="-X '$APP_PATH.Version=$EXTENSION_VERSION' -X '$APP_PATH.Commit=$COMMIT' -X '$APP_PATH.BuildDate=$BUILD_DATE'" \
-o "$OUTPUT_NAME"

if [ $? -ne 0 ]; then
echo "An error occurred while building for $OS/$ARCH"
exit 1
fi
done

echo "Build completed successfully!"
echo "Binaries are located in the $OUTPUT_DIR directory."
Loading
Loading