2026-06-12 01:58:46 +02:00
# retoor <retoor@molodetz.nl>
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
import asyncio
import importlib
import logging
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
from collections import deque
from datetime import datetime , timedelta , timezone
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
from devplacepy . services . base import BaseService , ConfigField
from devplacepy . services . bot import config
2026-06-14 16:46:36 +02:00
from devplacepy . services . bot . monitor import monitor
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
logger = logging . getLogger ( __name__ )
class BotsService ( BaseService ) :
default_enabled = False
min_interval = 5
title = " Bots "
description = (
" Runs a fleet of Playwright-driven AI personas that browse a DevPlace "
" instance and post, comment, vote, and react like real users. Fleet size, "
" target site, and LLM settings are configurable, with live cost and usage "
" metrics per bot. "
)
config_fields = [
2026-06-09 18:48:08 +02:00
ConfigField (
" bot_fleet_size " ,
" Fleet size (bots) " ,
type = " int " ,
default = 1 ,
minimum = 0 ,
maximum = 20 ,
help = " Number of concurrent bot accounts to run. " ,
group = " Fleet " ,
) ,
ConfigField (
" bot_headless " ,
" Headless browser " ,
type = " bool " ,
default = True ,
help = " Run Chromium headless. Disable only for local debugging on a desktop. " ,
group = " Fleet " ,
) ,
ConfigField (
" bot_max_actions " ,
" Max actions per bot " ,
type = " int " ,
default = 0 ,
minimum = 0 ,
help = " Stop a bot after this many actions (0 = run indefinitely). " ,
group = " Fleet " ,
) ,
ConfigField (
" bot_base_url " ,
" Target site URL " ,
type = " url " ,
default = config . BASE_URL_DEFAULT ,
help = " DevPlace instance the bots browse and post to. " ,
group = " Target " ,
) ,
ConfigField (
" bot_news_api " ,
" News API URL " ,
type = " url " ,
default = config . NEWS_API_DEFAULT ,
help = " Source of articles the bots react to. " ,
group = " Target " ,
) ,
ConfigField (
" bot_api_url " ,
" LLM API URL " ,
type = " url " ,
default = config . API_URL_DEFAULT ,
help = " OpenAI-compatible chat-completions endpoint. " ,
group = " LLM " ,
) ,
ConfigField (
" bot_model " ,
" LLM model " ,
type = " str " ,
default = config . MODEL_DEFAULT ,
help = " Model name sent to the LLM API. " ,
group = " LLM " ,
) ,
ConfigField (
" bot_api_key " ,
" LLM API key " ,
type = " password " ,
default = " " ,
secret = True ,
help = " Defaults to the gateway ' s internal key (the bots use the local AI gateway). " ,
group = " LLM " ,
) ,
ConfigField (
" bot_input_cost_per_1m " ,
" Input cost per 1M tokens ($) " ,
type = " float " ,
default = config . INPUT_COST_PER_1M_DEFAULT ,
minimum = 0 ,
help = " Used to compute live spend per bot and across the fleet. " ,
group = " LLM " ,
) ,
ConfigField (
" bot_output_cost_per_1m " ,
" Output cost per 1M tokens ($) " ,
type = " float " ,
default = config . OUTPUT_COST_PER_1M_DEFAULT ,
minimum = 0 ,
help = " Used to compute live spend per bot and across the fleet. " ,
group = " LLM " ,
) ,
2026-06-11 14:06:17 +02:00
ConfigField (
" bot_max_per_article " ,
" Bots per article " ,
type = " int " ,
default = config . MAX_BOTS_PER_ARTICLE ,
minimum = 1 ,
maximum = 5 ,
help = " How many bots may post about the same news article, each from a different angle. " ,
group = " Behavior " ,
) ,
ConfigField (
" bot_article_ttl_days " ,
" Article cooldown (days) " ,
type = " int " ,
default = config . ARTICLE_TTL_DAYS ,
minimum = 1 ,
maximum = 90 ,
help = " How long an article stays covered before it can be posted about again. " ,
group = " Behavior " ,
) ,
ConfigField (
" bot_gist_min_lines " ,
" Minimum gist lines " ,
type = " int " ,
default = config . GIST_MIN_LINES ,
minimum = 1 ,
maximum = 50 ,
help = " Reject generated code snippets shorter than this many non-empty lines. " ,
group = " Behavior " ,
) ,
ConfigField (
" bot_action_pause_min_seconds " ,
" Min pause between actions (s) " ,
type = " int " ,
default = config . ACTION_PAUSE_MIN_SECONDS ,
minimum = 0 ,
maximum = 3600 ,
help = " Lower bound of the idle pause a bot takes after each action. " ,
group = " Pacing " ,
) ,
ConfigField (
" bot_action_pause_max_seconds " ,
" Max pause between actions (s) " ,
type = " int " ,
default = config . ACTION_PAUSE_MAX_SECONDS ,
minimum = 1 ,
maximum = 7200 ,
help = " Upper bound of the idle pause a bot takes after each action. " ,
group = " Pacing " ,
) ,
ConfigField (
" bot_break_scale " ,
" Break length multiplier " ,
type = " float " ,
default = config . BREAK_SCALE_DEFAULT ,
minimum = 0.1 ,
maximum = 10.0 ,
help = " Scales the between-session break. Below 1 makes the fleet more active (and costlier); above 1 calmer. " ,
group = " Pacing " ,
) ,
2026-06-13 13:19:32 +02:00
ConfigField (
" bot_startup_jitter_seconds " ,
" Startup jitter (s) " ,
type = " int " ,
default = config . STARTUP_JITTER_SECONDS_DEFAULT ,
minimum = 0 ,
maximum = 86400 ,
help = " Each bot waits a random delay up to this many seconds before its first session, spreading fleet activity instead of bursting together when the service starts. " ,
group = " Pacing " ,
) ,
2026-06-11 20:52:56 +02:00
ConfigField (
" bot_ai_decisions " ,
" AI-driven decisions " ,
type = " bool " ,
default = config . AI_DECISIONS_DEFAULT ,
help = " Let each bot ' s persona decide every action via the LLM instead of fixed probabilities. Adds one decision call per page; falls back to the procedural cascade when off. " ,
group = " Decisions " ,
) ,
ConfigField (
" bot_decision_temperature " ,
" Decision temperature " ,
type = " float " ,
default = config . DECISION_TEMPERATURE_DEFAULT ,
minimum = 0.0 ,
maximum = 2.0 ,
help = " Sampling temperature for the per-page decision call. Low values keep structured output stable; variety comes from the identity, not noise. " ,
group = " Decisions " ,
) ,
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
]
def __init__ ( self ) :
super ( ) . __init__ ( name = " bots " , interval_seconds = 15 )
self . _fleet = { }
self . _state_dir = config . STATE_DIR
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
self . _cost_samples = deque ( )
self . _cost_anchor = None
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
def _resolve_api_key ( self , cfg : dict ) - > str :
from devplacepy . database import internal_gateway_key
2026-06-09 18:48:08 +02:00
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
return cfg [ " bot_api_key " ] or internal_gateway_key ( )
@staticmethod
def _ensure_importable ( ) - > None :
importlib . import_module ( " devplacepy.services.bot.bot " )
async def run_once ( self ) - > None :
cfg = self . get_config ( )
desired = cfg [ " bot_fleet_size " ]
api_key = self . _resolve_api_key ( cfg )
if not api_key :
if self . _fleet :
await self . _stop_fleet ( )
2026-06-09 18:48:08 +02:00
self . log (
" No LLM API key available (bot_api_key / gateway internal key); fleet idle "
)
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
return
try :
self . _ensure_importable ( )
except ImportError as e :
if self . _fleet :
await self . _stop_fleet ( )
self . log ( f " Bot dependencies unavailable ( { e } ); install the ' bots ' extra " )
return
for slot in list ( self . _fleet ) :
task = self . _fleet [ slot ] [ " task " ]
if task . done ( ) :
self . _report_exit ( slot , task )
del self . _fleet [ slot ]
while len ( self . _fleet ) > desired :
await self . _stop_slot ( max ( self . _fleet ) )
for slot in range ( desired ) :
if slot not in self . _fleet :
self . _launch_slot ( slot , cfg , api_key )
self . log ( f " Fleet: { len ( self . _fleet ) } / { desired } bots active " )
def _report_exit ( self , slot : int , task ) - > None :
if task . cancelled ( ) :
return
exc = task . exception ( )
if exc :
self . log ( f " bot { slot } exited with error: { exc } ; relaunching " )
else :
self . log ( f " bot { slot } finished; relaunching " )
def _launch_slot ( self , slot : int , cfg : dict , api_key : str ) - > None :
from devplacepy . services . bot . bot import DevPlaceBot
from devplacepy . services . bot . runtime import BotRuntimeConfig
2026-06-09 18:48:08 +02:00
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
rc = BotRuntimeConfig (
state_path = self . _state_dir / f " state_slot { slot } .json " ,
base_url = cfg [ " bot_base_url " ] ,
api_url = cfg [ " bot_api_url " ] ,
news_api = cfg [ " bot_news_api " ] ,
model = cfg [ " bot_model " ] ,
api_key = api_key ,
input_cost_per_1m = cfg [ " bot_input_cost_per_1m " ] ,
output_cost_per_1m = cfg [ " bot_output_cost_per_1m " ] ,
headless = cfg [ " bot_headless " ] ,
registry_path = config . ARTICLE_REGISTRY_PATH ,
2026-06-11 14:06:17 +02:00
max_per_article = cfg [ " bot_max_per_article " ] ,
article_ttl_days = cfg [ " bot_article_ttl_days " ] ,
gist_min_lines = cfg [ " bot_gist_min_lines " ] ,
action_pause_min = cfg [ " bot_action_pause_min_seconds " ] ,
action_pause_max = cfg [ " bot_action_pause_max_seconds " ] ,
break_scale = cfg [ " bot_break_scale " ] ,
2026-06-13 13:19:32 +02:00
startup_jitter_seconds = cfg [ " bot_startup_jitter_seconds " ] ,
2026-06-11 20:52:56 +02:00
ai_decisions = cfg [ " bot_ai_decisions " ] ,
decision_temperature = cfg [ " bot_decision_temperature " ] ,
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
)
2026-06-14 16:46:36 +02:00
bot = DevPlaceBot ( rc , on_event = self . log , slot = slot )
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
task = asyncio . create_task ( self . _run_slot ( slot , bot , cfg [ " bot_max_actions " ] ) )
self . _fleet [ slot ] = { " bot " : bot , " task " : task }
self . log ( f " Launched bot { slot } " )
async def _run_slot ( self , slot : int , bot , max_actions : int ) - > None :
try :
await bot . run_forever ( action_limit = max_actions )
except asyncio . CancelledError :
raise
except Exception as e :
self . log ( f " bot { slot } crashed: { e } " )
async def on_disable ( self ) - > None :
await self . _stop_fleet ( )
async def _stop_fleet ( self ) - > None :
2026-06-09 06:41:27 +02:00
slots = list ( self . _fleet )
if slots :
2026-06-09 18:48:08 +02:00
await asyncio . gather (
* ( self . _stop_slot ( slot ) for slot in slots ) , return_exceptions = True
)
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
async def _stop_slot ( self , slot : int ) - > None :
entry = self . _fleet . pop ( slot , None )
if not entry :
return
task = entry [ " task " ]
task . cancel ( )
try :
await asyncio . wait_for ( task , timeout = 30 )
except ( asyncio . CancelledError , asyncio . TimeoutError ) :
pass
except Exception as e :
self . log ( f " bot { slot } stop error: { e } " )
2026-06-09 06:41:27 +02:00
await self . _close_bot ( slot , entry . get ( " bot " ) )
2026-06-14 16:46:36 +02:00
monitor . drop ( slot )
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
self . log ( f " Stopped bot { slot } " )
2026-06-09 06:41:27 +02:00
async def _close_bot ( self , slot : int , bot ) - > None :
browser = getattr ( bot , " b " , None )
if browser is None :
return
try :
await asyncio . wait_for ( browser . close ( ) , timeout = 15 )
except ( asyncio . CancelledError , asyncio . TimeoutError ) :
pass
except Exception as e :
self . log ( f " bot { slot } browser close error: { e } " )
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
def collect_metrics ( self ) - > dict :
rows = [ ]
total_cost = 0.0
total_calls = total_in = total_out = 0
posts = comments = votes = running = 0
for slot in sorted ( self . _fleet ) :
entry = self . _fleet [ slot ]
bot = entry [ " bot " ]
alive = not entry [ " task " ] . done ( )
running + = 1 if alive else 0
llm = getattr ( bot , " llm " , None )
st = getattr ( bot , " state " , None )
cost = llm . total_cost if llm else 0.0
calls = llm . total_calls if llm else 0
total_cost + = cost
total_calls + = calls
total_in + = llm . total_in_tokens if llm else 0
total_out + = llm . total_out_tokens if llm else 0
if st :
posts + = st . created_posts
comments + = st . comments_posted
votes + = st . votes_cast
2026-06-16 00:44:12 +02:00
username = ( st . username if st else " " ) or " "
user_cell = (
{
" text " : username ,
" href " : f " /profile/ { username } " ,
" avatar " : username ,
}
if username
else " - "
)
2026-06-09 18:48:08 +02:00
rows . append (
[
f " bot { slot } " ,
2026-06-16 00:44:12 +02:00
user_cell ,
2026-06-09 18:48:08 +02:00
( st . persona if st else " " ) or " - " ,
" running " if alive else " stopped " ,
st . created_posts if st else 0 ,
st . comments_posted if st else 0 ,
st . votes_cast if st else 0 ,
calls ,
f " $ { cost : .4f } " ,
]
)
window , observed_cost , ready = self . _sample_cost (
datetime . now ( timezone . utc ) , total_cost
)
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
cost_per_hour = observed_cost / window * 3600 if ready else 0.0
projected_24h = observed_cost / window * 86400 if ready else 0.0
rate_value = f " $ { cost_per_hour : .4f } /h " if ready else " warming up "
projected_value = f " $ { projected_24h : .2f } " if ready else " warming up "
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
stats = [
{ " label " : " Bots running " , " value " : running } ,
{ " label " : " Fleet cost " , " value " : f " $ { total_cost : .4f } " } ,
{ " label " : " Observed window " , " value " : f " { window : .0f } s " } ,
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
{ " label " : " Cost rate " , " value " : rate_value } ,
{ " label " : " Projected 24h cost " , " value " : projected_value } ,
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
{ " label " : " LLM calls " , " value " : total_calls } ,
{ " label " : " Tokens in " , " value " : total_in } ,
{ " label " : " Tokens out " , " value " : total_out } ,
{ " label " : " Posts " , " value " : posts } ,
{ " label " : " Comments " , " value " : comments } ,
{ " label " : " Votes " , " value " : votes } ,
]
table = {
2026-06-09 18:48:08 +02:00
" columns " : [
" Bot " ,
" User " ,
" Persona " ,
" Status " ,
" Posts " ,
" Comments " ,
" Votes " ,
" Calls " ,
" Cost " ,
] ,
feat: add api key auth, devii agent, openai gateway, and admin service management
This commit introduces a comprehensive set of new features including API key authentication with CLI management commands (get, reset, backfill), a Devii agentic assistant with WebSocket terminal and session bootstrap, an OpenAI-compatible LLM gateway service, and an admin service management panel. It also adds Playwright browser automation for bot support, configures internal gateway URLs, refactors content editing/deletion to support JSON API responses, and updates documentation across AGENTS.md, README.md, and the developer docs site.
2026-06-08 17:38:33 +02:00
" rows " : rows ,
}
2026-06-14 16:46:36 +02:00
return { " stats " : stats , " table " : table , " frames " : monitor . snapshot ( ) }
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
2026-06-09 18:48:08 +02:00
def _sample_cost (
self , now : datetime , total_cost : float
) - > tuple [ float , float , bool ] :
feat: add project file system with CRUD, upload, inline editing, and video attachment support
- Add new `/projects/{slug}/files` endpoint group for per-project filesystem operations including directory and file CRUD, upload, and inline editing with public read and owner write access
- Extend attachment system to support video formats (webm, ogv, mov, m4v) with proper file icons and MIME types
- Implement configurable allowed file types via `allowed_file_types` site setting, replacing hardcoded `ALLOWED_UPLOAD_TYPES` with dynamic `allowed_extensions()` and `is_extension_allowed()` functions
- Add `delete_all_project_files()` call in `delete_content_item()` to clean up project files when a project is deleted
- Create database indexes on `project_files` table for `(project_uid, path)` and `(project_uid, parent_path)` to optimize file lookups
- Introduce `docs_prose.py` module with `render_prose()` function that renders Markdown content inside `data-render` divs using mistune, enabling dynamic prose rendering in documentation pages
- Enhance docs search with Markdown-aware text stripping (`_demarkdown()`) and improved HTML/script/style sanitization for better search indexing
- Update documentation API samples to reflect new attachment response fields (`is_image`, `is_video`, `mime_type`) and note video format support
- Update README to document the new project files endpoint and clarify AI gateway attribution for guest Devii sessions
2026-06-08 22:51:09 +02:00
if self . _started_at is None :
self . _cost_samples . clear ( )
self . _cost_anchor = None
return 0.0 , 0.0 , False
if self . _cost_anchor != self . _started_at :
self . _cost_samples . clear ( )
self . _cost_anchor = self . _started_at
self . _cost_samples . append ( ( now , total_cost ) )
cutoff = now - timedelta ( seconds = config . COST_WINDOW_SECONDS )
while len ( self . _cost_samples ) > 2 and self . _cost_samples [ 0 ] [ 0 ] < cutoff :
self . _cost_samples . popleft ( )
start_at , start_cost = self . _cost_samples [ 0 ]
window = ( now - start_at ) . total_seconds ( )
observed_cost = max ( 0.0 , total_cost - start_cost )
ready = window > = config . COST_WARMUP_SECONDS
return window , observed_cost , ready