Files
wehub-resource-sync e9a2f726c9
CI / test (3.11) (push) Has been cancelled
CI / test (3.12) (push) Has been cancelled
CI / test (3.13) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:29:51 +08:00

99 lines
3.2 KiB
Python

"""Pi integration."""
from __future__ import annotations
import os
import re
from pathlib import Path
from omlx.integrations.base import Integration, IntegrationContext
from omlx.utils.install import get_cli_command_prefix
def _get_agent_dir() -> Path:
"""Get the pi agent config directory, respecting PI_CODING_AGENT_DIR."""
env_dir = os.environ.get("PI_CODING_AGENT_DIR")
if env_dir:
return Path(env_dir).expanduser()
return Path.home() / ".pi" / "agent"
class PiIntegration(Integration):
"""Pi integration that configures the pi agent config directory."""
AGENT_DIR = _get_agent_dir()
MODELS_PATH = AGENT_DIR / "models.json"
SETTINGS_PATH = AGENT_DIR / "settings.json"
def __init__(self):
super().__init__(
name="pi",
display_name="Pi",
type="config_file",
install_check="pi",
install_hint="npm install -g @mariozechner/pi-coding-agent",
)
def get_command(self, ctx: IntegrationContext) -> str:
return (
f"{get_cli_command_prefix()} "
f"launch pi --model {ctx.model or 'select-a-model'}"
)
@staticmethod
def _is_reasoning_model(model: str | None) -> bool:
return bool(re.search(r"\b(thinking|o1|o3|r1)\b", (model or "").lower()))
def configure(self, ctx: IntegrationContext) -> None:
def update_models(config: dict) -> None:
config.setdefault("providers", {})
provider_config: dict = {
"baseUrl": ctx.openai_base_url,
"api": "openai-completions",
"apiKey": ctx.auth_token,
"authHeader": True,
}
if ctx.model:
reasoning = (
bool(ctx.reasoning)
if ctx.reasoning is not None
else self._is_reasoning_model(ctx.model)
)
model_entry: dict = {
"id": ctx.model,
"name": ctx.model,
"reasoning": reasoning,
"input": ["text", "image"] if ctx.supports_images else ["text"],
"cost": {
"input": 0,
"output": 0,
"cacheRead": 0,
"cacheWrite": 0,
},
}
if ctx.context_window:
model_entry["contextWindow"] = ctx.context_window
if ctx.max_tokens:
model_entry["maxTokens"] = ctx.max_tokens
provider_config["models"] = [model_entry]
config["providers"]["omlx"] = provider_config
def update_settings(config: dict) -> None:
config["defaultProvider"] = "omlx"
if ctx.model:
config["defaultModel"] = ctx.model
self._write_json_config(self.MODELS_PATH, update_models)
self._write_json_config(self.SETTINGS_PATH, update_settings)
def launch(self, ctx: IntegrationContext) -> None:
self.configure(ctx)
env = self._scrubbed_env()
args = ["pi"]
if ctx.model:
args.extend(["--model", f"omlx/{ctx.model}"])
args.extend(ctx.extra_args)
os.execvpe("pi", args, env)