From ecbdd05058ee4e12e9242e4a8231995fd0a21ce9 Mon Sep 17 00:00:00 2001 From: Yuriy Mayatnikov Date: Wed, 27 May 2026 18:09:04 +0300 Subject: [PATCH] chore(v0.3.0): rename fast-LLM env vars to TIMEWEB_* (match other projects) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Aligns with the user's other repos (proso) which use TIMEWEB_API_GROK / TIMEWEB_URL_GROK. Single naming convention across projects avoids the 'which env var was it for this repo' mental tax. PEPA_FAST_LLM_BASE_URL → TIMEWEB_BASE_URL PEPA_FAST_LLM_API_KEY → TIMEWEB_API_KEY PEPA_FAST_LLM_MODEL → TIMEWEB_MODEL PEPA_FAST_LLM_TIMEOUT_MS → TIMEWEB_TIMEOUT_MS Provider still works with any OpenAI-compatible endpoint — TimeWeb is the default but the variable name doesn't lock us in. Tests + docs + .env / .env.example updated. Co-Authored-By: Claude Opus 4.7 --- .env.example | 20 ++++++++------------ dev/v0.3.0/PLAN.md | 2 +- dev/v0.3.0/STATUS.md | 14 +++++++------- runtime/coach/fast-advisor.js | 2 +- runtime/coach/fast-advisor.test.js | 7 ++++--- runtime/llm/provider.js | 18 ++++++++++-------- 6 files changed, 31 insertions(+), 32 deletions(-) diff --git a/.env.example b/.env.example index bbdec81..b93203a 100644 --- a/.env.example +++ b/.env.example @@ -29,24 +29,20 @@ GOOGLE_API_KEY= PI_DEFAULT_PROVIDER=openai PI_DEFAULT_MODEL=gpt-5-mini -# --- Fast LLM tier (v0.3.0+) -------------------------------------------------- +# --- Fast LLM tier (TimeWeb / OpenAI-compatible, v0.3.0+) -------------------- # Pi (CLI) handles slow deep analytics — post-mortem and 30-min reflection. # A parallel "fast advisor" tier handles tactical "what to do RIGHT NOW" -# decisions when the reflex is stuck / preempted. Any OpenAI-compatible -# endpoint works: TimeWeb, OpenAI direct, Groq, OpenRouter, local Ollama. +# decisions when the reflex is stuck / preempted. The default expectation +# is TimeWeb, but any OpenAI-compatible endpoint works (OpenAI direct, +# Groq, OpenRouter, local Ollama with the OpenAI shim). # # Leave blank to disable — the bot then runs without the fast tier # (rc.1 scaffold is a safe no-op when API_KEY is unset). -# -# Example for TimeWeb (replace with your own endpoint + key + model): -# PEPA_FAST_LLM_BASE_URL=https://api.gen-api.ru/api/v1 -# PEPA_FAST_LLM_API_KEY= -# PEPA_FAST_LLM_MODEL=gpt-5-mini -PEPA_FAST_LLM_BASE_URL= -PEPA_FAST_LLM_API_KEY= -PEPA_FAST_LLM_MODEL= +TIMEWEB_BASE_URL= +TIMEWEB_API_KEY= +TIMEWEB_MODEL= # Optional: request timeout in ms (default 8000) -PEPA_FAST_LLM_TIMEOUT_MS= +TIMEWEB_TIMEOUT_MS= # --- Bot behaviour ------------------------------------------------------------ # How often (seconds) the autonomous tick prompt fires. Set to 0 to disable. diff --git a/dev/v0.3.0/PLAN.md b/dev/v0.3.0/PLAN.md index 62a191c..47a99a1 100644 --- a/dev/v0.3.0/PLAN.md +++ b/dev/v0.3.0/PLAN.md @@ -65,7 +65,7 @@ L10 village_full глобальная цель (ферма + дом + сосе - `runtime/coach/advice.js`: `normalisePreferSkill` строго отбрасывает всё, что не в реестре (raise log, не дрейфит на fuzzy) - `runtime/llm/provider.js` — OpenAI-совместимый клиент, конфигурируется - через env (`PEPA_FAST_LLM_BASE_URL`, `_API_KEY`, `_MODEL`); graceful + через env (`TIMEWEB_BASE_URL`, `TIMEWEB_API_KEY`, `TIMEWEB_MODEL`); graceful fallback "no-op" если env не задан (бот не падает) - `runtime/coach/fast-advisor.js` — функция `advise({snapshot, reason})` с rate-limit (макс. 6 вызовов/час), таймаут 8с, JSON-парсинг ответа diff --git a/dev/v0.3.0/STATUS.md b/dev/v0.3.0/STATUS.md index 5834587..238ccc8 100644 --- a/dev/v0.3.0/STATUS.md +++ b/dev/v0.3.0/STATUS.md @@ -22,10 +22,10 @@ fixed: (a) Pi now sees the real registry in its system prompt, namespace, with "USE ONLY THESE, never invent" instruction - [`runtime/llm/provider.js`](../../runtime/llm/provider.js) — OpenAI-compatible chat client, env-driven: - - `PEPA_FAST_LLM_BASE_URL` (default `https://api.openai.com/v1`) - - `PEPA_FAST_LLM_API_KEY` (required to enable; safe no-op otherwise) - - `PEPA_FAST_LLM_MODEL` (required) - - `PEPA_FAST_LLM_TIMEOUT_MS` (default 8000) + - `TIMEWEB_BASE_URL` (default `https://api.openai.com/v1`) + - `TIMEWEB_API_KEY` (required to enable; safe no-op otherwise) + - `TIMEWEB_MODEL` (required) + - `TIMEWEB_TIMEOUT_MS` (default 8000) - Supports JSON-mode via `response_format: { type: "json_object" }` - Surfaces `not_configured`, `no_model`, `http_`, `network_error`, `timeout`, `bad_json` codes @@ -167,9 +167,9 @@ Tests: 332 green (was 315 on rc.2, +17 new): start growing as the registry feedback closes the loop. 3. **Set fast-advisor env when ready to test**: ```bash - export PEPA_FAST_LLM_BASE_URL="https:///v1" - export PEPA_FAST_LLM_API_KEY="" - export PEPA_FAST_LLM_MODEL="gpt-5-mini" + export TIMEWEB_BASE_URL="https:///v1" + export TIMEWEB_API_KEY="" + export TIMEWEB_MODEL="gpt-5-mini" ``` The advisor still isn't auto-triggered in rc.1 — it's wired in rc.3. 4. **Pick the next rc** from PLAN.md. diff --git a/runtime/coach/fast-advisor.js b/runtime/coach/fast-advisor.js index 2d4f818..13f4201 100644 --- a/runtime/coach/fast-advisor.js +++ b/runtime/coach/fast-advisor.js @@ -50,7 +50,7 @@ export async function advise({ force = false, } = {}) { if (!isAvailable()) { - return { ok: false, code: "not_configured", detail: "set PEPA_FAST_LLM_API_KEY", latencyMs: 0 }; + return { ok: false, code: "not_configured", detail: "set TIMEWEB_API_KEY", latencyMs: 0 }; } const now = Date.now(); diff --git a/runtime/coach/fast-advisor.test.js b/runtime/coach/fast-advisor.test.js index 909d09b..6cab23c 100644 --- a/runtime/coach/fast-advisor.test.js +++ b/runtime/coach/fast-advisor.test.js @@ -3,9 +3,9 @@ import assert from "node:assert/strict"; import { advise, isAvailable, _resetForTest, __testing } from "./fast-advisor.js"; -const API_KEY = "PEPA_FAST_LLM_API_KEY"; -const MODEL = "PEPA_FAST_LLM_MODEL"; -const BASE = "PEPA_FAST_LLM_BASE_URL"; +const API_KEY = "TIMEWEB_API_KEY"; +const MODEL = "TIMEWEB_MODEL"; +const BASE = "TIMEWEB_BASE_URL"; function withEnv(env, fn) { const prev = {}; @@ -43,6 +43,7 @@ test("advise: not_configured without API key", async () => { const res = await advise({ reason: "stuck" }); assert.equal(res.ok, false); assert.equal(res.code, "not_configured"); + assert.match(res.detail, /TIMEWEB_API_KEY/); }); }); diff --git a/runtime/llm/provider.js b/runtime/llm/provider.js index c78f271..0f73b25 100644 --- a/runtime/llm/provider.js +++ b/runtime/llm/provider.js @@ -6,19 +6,21 @@ // right now ("I'm wedged in a pit, what should I do?"). // // This provider opens a parallel path: any OpenAI-compatible HTTP endpoint -// (TimeWeb, OpenAI direct, Groq, OpenRouter, local Ollama with the OpenAI -// shim, …) producing a structured JSON answer in ≤8 seconds. +// (TimeWeb is the default — same env var convention as the user's other +// projects — but OpenAI direct, Groq, OpenRouter, and local Ollama with +// the OpenAI shim all work with the same plumbing) producing a structured +// JSON answer in ≤8 seconds. // // Configuration is strictly env-driven. The provider is a NO-OP unless -// PEPA_FAST_LLM_API_KEY is set, so it's safe to ship the code disabled. +// TIMEWEB_API_KEY is set, so it's safe to ship the code disabled. import { info, warn } from "../log.js"; const ENV = { - BASE_URL: "PEPA_FAST_LLM_BASE_URL", - API_KEY: "PEPA_FAST_LLM_API_KEY", - MODEL: "PEPA_FAST_LLM_MODEL", - TIMEOUT_MS: "PEPA_FAST_LLM_TIMEOUT_MS", + BASE_URL: "TIMEWEB_BASE_URL", + API_KEY: "TIMEWEB_API_KEY", + MODEL: "TIMEWEB_MODEL", + TIMEOUT_MS: "TIMEWEB_TIMEOUT_MS", }; const DEFAULT_BASE_URL = "https://api.openai.com/v1"; @@ -58,7 +60,7 @@ export async function complete({ } const useModel = model || cfg.model; if (!useModel) { - return { ok: false, code: "no_model", detail: `set ${ENV.MODEL} or pass model arg`, latencyMs: 0 }; + return { ok: false, code: "no_model", detail: `set ${ENV.MODEL} env or pass model arg`, latencyMs: 0 }; } const body = {