mirror of
https://github.com/katanemo/plano.git
synced 2026-05-08 07:12:42 +02:00
Merge branch 'main' of https://github.com/katanemo/plano into musa/codex-cli
This commit is contained in:
commit
102223d011
13 changed files with 50 additions and 60 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
|
@ -133,13 +133,13 @@ jobs:
|
||||||
load: true
|
load: true
|
||||||
tags: |
|
tags: |
|
||||||
${{ env.PLANO_DOCKER_IMAGE }}
|
${{ env.PLANO_DOCKER_IMAGE }}
|
||||||
${{ env.DOCKER_IMAGE }}:0.4.10
|
${{ env.DOCKER_IMAGE }}:0.4.11
|
||||||
${{ env.DOCKER_IMAGE }}:latest
|
${{ env.DOCKER_IMAGE }}:latest
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
|
|
||||||
- name: Save image as artifact
|
- name: Save image as artifact
|
||||||
run: docker save ${{ env.PLANO_DOCKER_IMAGE }} ${{ env.DOCKER_IMAGE }}:0.4.10 ${{ env.DOCKER_IMAGE }}:latest -o /tmp/plano-image.tar
|
run: docker save ${{ env.PLANO_DOCKER_IMAGE }} ${{ env.DOCKER_IMAGE }}:0.4.11 ${{ env.DOCKER_IMAGE }}:latest -o /tmp/plano-image.tar
|
||||||
|
|
||||||
- name: Upload image artifact
|
- name: Upload image artifact
|
||||||
uses: actions/upload-artifact@v6
|
uses: actions/upload-artifact@v6
|
||||||
|
|
@ -163,7 +163,7 @@ jobs:
|
||||||
python-version: "3.14"
|
python-version: "3.14"
|
||||||
|
|
||||||
- name: Install planoai
|
- name: Install planoai
|
||||||
run: pip install ./cli
|
run: pip install -e ./cli
|
||||||
|
|
||||||
- name: Validate plano config
|
- name: Validate plano config
|
||||||
run: bash config/validate_plano_config.sh
|
run: bash config/validate_plano_config.sh
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ COPY cli/README.md ./
|
||||||
COPY config/plano_config_schema.yaml /config/plano_config_schema.yaml
|
COPY config/plano_config_schema.yaml /config/plano_config_schema.yaml
|
||||||
COPY config/envoy.template.yaml /config/envoy.template.yaml
|
COPY config/envoy.template.yaml /config/envoy.template.yaml
|
||||||
|
|
||||||
RUN uv run pip install --no-cache-dir .
|
RUN pip install --no-cache-dir -e .
|
||||||
|
|
||||||
COPY cli/planoai planoai/
|
COPY cli/planoai planoai/
|
||||||
COPY config/envoy.template.yaml .
|
COPY config/envoy.template.yaml .
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export function Hero() {
|
||||||
>
|
>
|
||||||
<div className="inline-flex flex-wrap items-center gap-1.5 sm:gap-2 px-3 sm:px-4 py-1 rounded-full bg-[rgba(185,191,255,0.4)] border border-[var(--secondary)] shadow backdrop-blur hover:bg-[rgba(185,191,255,0.6)] transition-colors cursor-pointer">
|
<div className="inline-flex flex-wrap items-center gap-1.5 sm:gap-2 px-3 sm:px-4 py-1 rounded-full bg-[rgba(185,191,255,0.4)] border border-[var(--secondary)] shadow backdrop-blur hover:bg-[rgba(185,191,255,0.6)] transition-colors cursor-pointer">
|
||||||
<span className="text-xs sm:text-sm font-medium text-black/65">
|
<span className="text-xs sm:text-sm font-medium text-black/65">
|
||||||
v0.4.10
|
v0.4.11
|
||||||
</span>
|
</span>
|
||||||
<span className="text-xs sm:text-sm font-medium text-black ">
|
<span className="text-xs sm:text-sm font-medium text-black ">
|
||||||
—
|
—
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
docker build -f Dockerfile . -t katanemo/plano -t katanemo/plano:0.4.10
|
docker build -f Dockerfile . -t katanemo/plano -t katanemo/plano:0.4.11
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
"""Plano CLI - Intelligent Prompt Gateway."""
|
"""Plano CLI - Intelligent Prompt Gateway."""
|
||||||
|
|
||||||
__version__ = "0.4.10"
|
__version__ = "0.4.11"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ PLANO_COLOR = "#969FF4"
|
||||||
|
|
||||||
SERVICE_NAME_ARCHGW = "plano"
|
SERVICE_NAME_ARCHGW = "plano"
|
||||||
PLANO_DOCKER_NAME = "plano"
|
PLANO_DOCKER_NAME = "plano"
|
||||||
PLANO_DOCKER_IMAGE = os.getenv("PLANO_DOCKER_IMAGE", "katanemo/plano:0.4.10")
|
PLANO_DOCKER_IMAGE = os.getenv("PLANO_DOCKER_IMAGE", "katanemo/plano:0.4.11")
|
||||||
DEFAULT_OTEL_TRACING_GRPC_ENDPOINT = "http://localhost:4317"
|
DEFAULT_OTEL_TRACING_GRPC_ENDPOINT = "http://localhost:4317"
|
||||||
|
|
||||||
# Native mode constants
|
# Native mode constants
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ def build(docker):
|
||||||
cwd=crates_dir,
|
cwd=crates_dir,
|
||||||
check=True,
|
check=True,
|
||||||
)
|
)
|
||||||
console.print("[green]✓[/green] WASM plugins built")
|
log.info("WASM plugins built")
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
console.print(f"[red]✗[/red] WASM build failed: {e}")
|
console.print(f"[red]✗[/red] WASM build failed: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
@ -197,7 +197,7 @@ def build(docker):
|
||||||
cwd=crates_dir,
|
cwd=crates_dir,
|
||||||
check=True,
|
check=True,
|
||||||
)
|
)
|
||||||
console.print("[green]✓[/green] brightstaff built")
|
log.info("brightstaff built")
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
console.print(f"[red]✗[/red] brightstaff build failed: {e}")
|
console.print(f"[red]✗[/red] brightstaff build failed: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
@ -319,7 +319,7 @@ def up(file, path, foreground, with_tracing, tracing_port, docker):
|
||||||
console.print(f" [dim]{validation_stderr.strip()}[/dim]")
|
console.print(f" [dim]{validation_stderr.strip()}[/dim]")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
console.print(f"[green]✓[/green] Configuration valid")
|
log.info("Configuration valid")
|
||||||
|
|
||||||
# Set up environment
|
# Set up environment
|
||||||
default_otel = (
|
default_otel = (
|
||||||
|
|
|
||||||
|
|
@ -100,15 +100,13 @@ def ensure_envoy_binary():
|
||||||
with open(version_path, "r") as f:
|
with open(version_path, "r") as f:
|
||||||
cached_version = f.read().strip()
|
cached_version = f.read().strip()
|
||||||
if cached_version == ENVOY_VERSION:
|
if cached_version == ENVOY_VERSION:
|
||||||
log.info(f"Envoy {ENVOY_VERSION} found at {envoy_path}")
|
log.info(f"Envoy {ENVOY_VERSION} (cached)")
|
||||||
return envoy_path
|
return envoy_path
|
||||||
print(
|
log.info(
|
||||||
f"Envoy version changed ({cached_version} → {ENVOY_VERSION}), re-downloading..."
|
f"Envoy version changed ({cached_version} → {ENVOY_VERSION}), re-downloading..."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
log.info(
|
log.info("Envoy binary found (unknown version, re-downloading...)")
|
||||||
f"Envoy binary found at {envoy_path} (unknown version, re-downloading...)"
|
|
||||||
)
|
|
||||||
|
|
||||||
slug = _get_platform_slug()
|
slug = _get_platform_slug()
|
||||||
url = (
|
url = (
|
||||||
|
|
@ -123,6 +121,7 @@ def ensure_envoy_binary():
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_download_file(url, tmp_path, label=f"Envoy {ENVOY_VERSION}")
|
_download_file(url, tmp_path, label=f"Envoy {ENVOY_VERSION}")
|
||||||
|
log.info(f"Extracting Envoy {ENVOY_VERSION}...")
|
||||||
with tarfile.open(tmp_path, "r:xz") as tar:
|
with tarfile.open(tmp_path, "r:xz") as tar:
|
||||||
# Find the envoy binary inside the archive
|
# Find the envoy binary inside the archive
|
||||||
envoy_member = None
|
envoy_member = None
|
||||||
|
|
@ -150,7 +149,6 @@ def ensure_envoy_binary():
|
||||||
os.chmod(envoy_path, 0o755)
|
os.chmod(envoy_path, 0o755)
|
||||||
with open(version_path, "w") as f:
|
with open(version_path, "w") as f:
|
||||||
f.write(ENVOY_VERSION)
|
f.write(ENVOY_VERSION)
|
||||||
log.info(f"Envoy {ENVOY_VERSION} installed at {envoy_path}")
|
|
||||||
return envoy_path
|
return envoy_path
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
|
|
@ -187,7 +185,7 @@ def ensure_wasm_plugins():
|
||||||
# 1. Local source build (inside repo)
|
# 1. Local source build (inside repo)
|
||||||
local = _find_local_wasm_plugins()
|
local = _find_local_wasm_plugins()
|
||||||
if local:
|
if local:
|
||||||
log.info(f"Using locally-built WASM plugins: {local[0]}")
|
log.info("Using locally-built WASM plugins")
|
||||||
return local
|
return local
|
||||||
|
|
||||||
# 2. Cached download
|
# 2. Cached download
|
||||||
|
|
@ -201,9 +199,9 @@ def ensure_wasm_plugins():
|
||||||
with open(version_path, "r") as f:
|
with open(version_path, "r") as f:
|
||||||
cached_version = f.read().strip()
|
cached_version = f.read().strip()
|
||||||
if cached_version == version:
|
if cached_version == version:
|
||||||
log.info(f"WASM plugins {version} found at {PLANO_PLUGINS_DIR}")
|
log.info(f"WASM plugins {version} (cached)")
|
||||||
return prompt_gw_path, llm_gw_path
|
return prompt_gw_path, llm_gw_path
|
||||||
print(
|
log.info(
|
||||||
f"WASM plugins version changed ({cached_version} → {version}), re-downloading..."
|
f"WASM plugins version changed ({cached_version} → {version}), re-downloading..."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
@ -220,6 +218,7 @@ def ensure_wasm_plugins():
|
||||||
url = f"{PLANO_RELEASE_BASE_URL}/{version}/{gz_name}"
|
url = f"{PLANO_RELEASE_BASE_URL}/{version}/{gz_name}"
|
||||||
gz_dest = dest + ".gz"
|
gz_dest = dest + ".gz"
|
||||||
_download_file(url, gz_dest, label=f"{name} ({version})")
|
_download_file(url, gz_dest, label=f"{name} ({version})")
|
||||||
|
log.info(f"Decompressing {name}...")
|
||||||
with gzip.open(gz_dest, "rb") as f_in, open(dest, "wb") as f_out:
|
with gzip.open(gz_dest, "rb") as f_in, open(dest, "wb") as f_out:
|
||||||
shutil.copyfileobj(f_in, f_out)
|
shutil.copyfileobj(f_in, f_out)
|
||||||
os.unlink(gz_dest)
|
os.unlink(gz_dest)
|
||||||
|
|
@ -235,7 +234,7 @@ def ensure_brightstaff_binary():
|
||||||
# 1. Local source build (inside repo)
|
# 1. Local source build (inside repo)
|
||||||
local = _find_local_brightstaff()
|
local = _find_local_brightstaff()
|
||||||
if local:
|
if local:
|
||||||
log.info(f"Using locally-built brightstaff: {local}")
|
log.info("Using locally-built brightstaff")
|
||||||
return local
|
return local
|
||||||
|
|
||||||
# 2. Cached download
|
# 2. Cached download
|
||||||
|
|
@ -248,9 +247,9 @@ def ensure_brightstaff_binary():
|
||||||
with open(version_path, "r") as f:
|
with open(version_path, "r") as f:
|
||||||
cached_version = f.read().strip()
|
cached_version = f.read().strip()
|
||||||
if cached_version == version:
|
if cached_version == version:
|
||||||
log.info(f"brightstaff {version} found at {brightstaff_path}")
|
log.info(f"brightstaff {version} (cached)")
|
||||||
return brightstaff_path
|
return brightstaff_path
|
||||||
print(
|
log.info(
|
||||||
f"brightstaff version changed ({cached_version} → {version}), re-downloading..."
|
f"brightstaff version changed ({cached_version} → {version}), re-downloading..."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
@ -265,6 +264,7 @@ def ensure_brightstaff_binary():
|
||||||
|
|
||||||
gz_path = brightstaff_path + ".gz"
|
gz_path = brightstaff_path + ".gz"
|
||||||
_download_file(url, gz_path, label=f"brightstaff ({version}, {slug})")
|
_download_file(url, gz_path, label=f"brightstaff ({version}, {slug})")
|
||||||
|
log.info("Decompressing brightstaff...")
|
||||||
with gzip.open(gz_path, "rb") as f_in, open(brightstaff_path, "wb") as f_out:
|
with gzip.open(gz_path, "rb") as f_in, open(brightstaff_path, "wb") as f_out:
|
||||||
shutil.copyfileobj(f_in, f_out)
|
shutil.copyfileobj(f_in, f_out)
|
||||||
os.unlink(gz_path)
|
os.unlink(gz_path)
|
||||||
|
|
@ -272,7 +272,6 @@ def ensure_brightstaff_binary():
|
||||||
os.chmod(brightstaff_path, 0o755)
|
os.chmod(brightstaff_path, 0o755)
|
||||||
with open(version_path, "w") as f:
|
with open(version_path, "w") as f:
|
||||||
f.write(version)
|
f.write(version)
|
||||||
log.info(f"brightstaff {version} installed at {brightstaff_path}")
|
|
||||||
return brightstaff_path
|
return brightstaff_path
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -161,19 +161,10 @@ def start_native(plano_config_file, env, foreground=False, with_tracing=False):
|
||||||
"""Start Envoy and brightstaff natively."""
|
"""Start Envoy and brightstaff natively."""
|
||||||
from planoai.core import _get_gateway_ports
|
from planoai.core import _get_gateway_ports
|
||||||
|
|
||||||
console = None
|
# Stop any existing instance first
|
||||||
try:
|
if os.path.exists(NATIVE_PID_FILE):
|
||||||
from rich.console import Console
|
log.info("Stopping existing Plano instance...")
|
||||||
|
stop_native()
|
||||||
console = Console()
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def status_print(msg):
|
|
||||||
if console:
|
|
||||||
console.print(msg)
|
|
||||||
else:
|
|
||||||
print(msg)
|
|
||||||
|
|
||||||
envoy_path = ensure_envoy_binary()
|
envoy_path = ensure_envoy_binary()
|
||||||
ensure_wasm_plugins()
|
ensure_wasm_plugins()
|
||||||
|
|
@ -182,7 +173,7 @@ def start_native(plano_config_file, env, foreground=False, with_tracing=False):
|
||||||
plano_config_file, env, with_tracing=with_tracing
|
plano_config_file, env, with_tracing=with_tracing
|
||||||
)
|
)
|
||||||
|
|
||||||
status_print(f"[green]✓[/green] Configuration rendered")
|
log.info("Configuration rendered")
|
||||||
|
|
||||||
log_dir = os.path.join(PLANO_RUN_DIR, "logs")
|
log_dir = os.path.join(PLANO_RUN_DIR, "logs")
|
||||||
os.makedirs(log_dir, exist_ok=True)
|
os.makedirs(log_dir, exist_ok=True)
|
||||||
|
|
@ -233,7 +224,7 @@ def start_native(plano_config_file, env, foreground=False, with_tracing=False):
|
||||||
|
|
||||||
# Health check
|
# Health check
|
||||||
gateway_ports = _get_gateway_ports(plano_config_file)
|
gateway_ports = _get_gateway_ports(plano_config_file)
|
||||||
status_print(f"[dim]Waiting for listeners to become healthy...[/dim]")
|
log.info("Waiting for listeners to become healthy...")
|
||||||
|
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
timeout = 60
|
timeout = 60
|
||||||
|
|
@ -244,35 +235,35 @@ def start_native(plano_config_file, env, foreground=False, with_tracing=False):
|
||||||
all_healthy = False
|
all_healthy = False
|
||||||
|
|
||||||
if all_healthy:
|
if all_healthy:
|
||||||
status_print(f"[green]✓[/green] Plano is running (native mode)")
|
log.info("Plano is running (native mode)")
|
||||||
for port in gateway_ports:
|
for port in gateway_ports:
|
||||||
status_print(f" [cyan]http://localhost:{port}[/cyan]")
|
log.info(f" http://localhost:{port}")
|
||||||
break
|
break
|
||||||
|
|
||||||
# Check if processes are still alive
|
# Check if processes are still alive
|
||||||
if not _is_pid_alive(brightstaff_pid):
|
if not _is_pid_alive(brightstaff_pid):
|
||||||
status_print("[red]✗[/red] brightstaff exited unexpectedly")
|
log.error("brightstaff exited unexpectedly")
|
||||||
status_print(f" Check logs: {os.path.join(log_dir, 'brightstaff.log')}")
|
log.error(f" Check logs: {os.path.join(log_dir, 'brightstaff.log')}")
|
||||||
_kill_pid(envoy_pid)
|
_kill_pid(envoy_pid)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if not _is_pid_alive(envoy_pid):
|
if not _is_pid_alive(envoy_pid):
|
||||||
status_print("[red]✗[/red] envoy exited unexpectedly")
|
log.error("envoy exited unexpectedly")
|
||||||
status_print(f" Check logs: {os.path.join(log_dir, 'envoy.log')}")
|
log.error(f" Check logs: {os.path.join(log_dir, 'envoy.log')}")
|
||||||
_kill_pid(brightstaff_pid)
|
_kill_pid(brightstaff_pid)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if time.time() - start_time > timeout:
|
if time.time() - start_time > timeout:
|
||||||
status_print(f"[red]✗[/red] Health check timed out after {timeout}s")
|
log.error(f"Health check timed out after {timeout}s")
|
||||||
status_print(f" Check logs in: {log_dir}")
|
log.error(f" Check logs in: {log_dir}")
|
||||||
stop_native()
|
stop_native()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
if foreground:
|
if foreground:
|
||||||
status_print(f"[dim]Running in foreground. Press Ctrl+C to stop.[/dim]")
|
log.info("Running in foreground. Press Ctrl+C to stop.")
|
||||||
status_print(f"[dim]Logs: {log_dir}[/dim]")
|
log.info(f"Logs: {log_dir}")
|
||||||
try:
|
try:
|
||||||
import glob
|
import glob
|
||||||
|
|
||||||
|
|
@ -290,13 +281,13 @@ def start_native(plano_config_file, env, foreground=False, with_tracing=False):
|
||||||
)
|
)
|
||||||
tail_proc.wait()
|
tail_proc.wait()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
status_print(f"\n[dim]Stopping Plano...[/dim]")
|
log.info("Stopping Plano...")
|
||||||
if tail_proc.poll() is None:
|
if tail_proc.poll() is None:
|
||||||
tail_proc.terminate()
|
tail_proc.terminate()
|
||||||
stop_native()
|
stop_native()
|
||||||
else:
|
else:
|
||||||
status_print(f"[dim]Logs: {log_dir}[/dim]")
|
log.info(f"Logs: {log_dir}")
|
||||||
status_print(f"[dim]Run 'planoai down' to stop.[/dim]")
|
log.info("Run 'planoai down' to stop.")
|
||||||
|
|
||||||
|
|
||||||
def _daemon_exec(args, env, log_path):
|
def _daemon_exec(args, env, log_path):
|
||||||
|
|
@ -364,7 +355,7 @@ def _kill_pid(pid):
|
||||||
def stop_native():
|
def stop_native():
|
||||||
"""Stop natively-running Envoy and brightstaff processes."""
|
"""Stop natively-running Envoy and brightstaff processes."""
|
||||||
if not os.path.exists(NATIVE_PID_FILE):
|
if not os.path.exists(NATIVE_PID_FILE):
|
||||||
print("No native Plano instance found (PID file missing).")
|
log.info("No native Plano instance found (PID file missing).")
|
||||||
return
|
return
|
||||||
|
|
||||||
with open(NATIVE_PID_FILE, "r") as f:
|
with open(NATIVE_PID_FILE, "r") as f:
|
||||||
|
|
@ -383,7 +374,7 @@ def stop_native():
|
||||||
log.info(f"{name} (PID {pid}) already stopped")
|
log.info(f"{name} (PID {pid}) already stopped")
|
||||||
continue
|
continue
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
log.info(f"Permission denied stopping {name} (PID {pid})")
|
log.error(f"Permission denied stopping {name} (PID {pid})")
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Wait for graceful shutdown
|
# Wait for graceful shutdown
|
||||||
|
|
@ -403,7 +394,7 @@ def stop_native():
|
||||||
pass
|
pass
|
||||||
|
|
||||||
os.unlink(NATIVE_PID_FILE)
|
os.unlink(NATIVE_PID_FILE)
|
||||||
print("Plano stopped (native mode).")
|
log.info("Plano stopped (native mode).")
|
||||||
|
|
||||||
|
|
||||||
def native_validate_config(plano_config_file):
|
def native_validate_config(plano_config_file):
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[project]
|
[project]
|
||||||
name = "planoai"
|
name = "planoai"
|
||||||
version = "0.4.10"
|
version = "0.4.11"
|
||||||
description = "Python-based CLI tool to manage Plano."
|
description = "Python-based CLI tool to manage Plano."
|
||||||
authors = [{name = "Katanemo Labs, Inc."}]
|
authors = [{name = "Katanemo Labs, Inc."}]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ from sphinxawesome_theme.postprocess import Icons
|
||||||
project = "Plano Docs"
|
project = "Plano Docs"
|
||||||
copyright = "2025, Katanemo Labs, Inc"
|
copyright = "2025, Katanemo Labs, Inc"
|
||||||
author = "Katanemo Labs, Inc"
|
author = "Katanemo Labs, Inc"
|
||||||
release = " v0.4.10"
|
release = " v0.4.11"
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ Plano's CLI allows you to manage and interact with the Plano efficiently. To ins
|
||||||
|
|
||||||
.. code-block:: console
|
.. code-block:: console
|
||||||
|
|
||||||
$ uv tool install planoai==0.4.10
|
$ uv tool install planoai==0.4.11
|
||||||
|
|
||||||
**Option 2: Install with pip (Traditional)**
|
**Option 2: Install with pip (Traditional)**
|
||||||
|
|
||||||
|
|
@ -51,7 +51,7 @@ Plano's CLI allows you to manage and interact with the Plano efficiently. To ins
|
||||||
|
|
||||||
$ python -m venv venv
|
$ python -m venv venv
|
||||||
$ source venv/bin/activate # On Windows, use: venv\Scripts\activate
|
$ source venv/bin/activate # On Windows, use: venv\Scripts\activate
|
||||||
$ pip install planoai==0.4.10
|
$ pip install planoai==0.4.11
|
||||||
|
|
||||||
|
|
||||||
.. _llm_routing_quickstart:
|
.. _llm_routing_quickstart:
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ Create a ``docker-compose.yml`` file with the following configuration:
|
||||||
# docker-compose.yml
|
# docker-compose.yml
|
||||||
services:
|
services:
|
||||||
plano:
|
plano:
|
||||||
image: katanemo/plano:0.4.10
|
image: katanemo/plano:0.4.11
|
||||||
container_name: plano
|
container_name: plano
|
||||||
ports:
|
ports:
|
||||||
- "10000:10000" # ingress (client -> plano)
|
- "10000:10000" # ingress (client -> plano)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue