v0.3.0: Maslow + Awareness — self-learning bot with needs ladder, event-driven reflex, and TimeWeb fast advisor #27

Merged
halofourteen merged 8 commits from v0.3.0 into main 2026-05-27 19:37:57 +03:00
6 changed files with 31 additions and 32 deletions
Showing only changes of commit ecbdd05058 - Show all commits
+8 -12
View File
@@ -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=<paste your key here>
# 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.
+1 -1
View File
@@ -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-парсинг ответа
+7 -7
View File
@@ -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_<status>`,
`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://<timeweb-endpoint>/v1"
export PEPA_FAST_LLM_API_KEY="<key>"
export PEPA_FAST_LLM_MODEL="gpt-5-mini"
export TIMEWEB_BASE_URL="https://<timeweb-endpoint>/v1"
export TIMEWEB_API_KEY="<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.
+1 -1
View File
@@ -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();
+4 -3
View File
@@ -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/);
});
});
+10 -8
View File
@@ -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 = {