aevp: opt-in Pi Profile (lower particle + render cost)#111
aevp: opt-in Pi Profile (lower particle + render cost)#111webdevtodayjason wants to merge 1 commit intomainfrom
Conversation
New module dashboard/src/aevp/pi-profile.ts exposes three knobs the AEVP system reads at runtime: - getMaxParticlesCap() → 60 (default 180) — hard ceiling on active particles, layered on top of identity preset density. - getDensityScale() → 0.5 (default 1.0) — multiplier applied to presence.particleDensity so identity presets keep their relative character but cost half as much. - getFrameIntervalMs() → 33 (default 0) — minimum ms between render ticks, i.e. ~30fps cap on the AEVP loop. The profile activates if any of these are set: PI_PROFILE=1 (env) VITE_PI_PROFILE=1 (Vite build env) localStorage "argent.piProfile" = "1" (browser runtime) URL ?piProfile=1 (one-shot) Identity presets and personality modulation (warmth/energy/openness/ formality) are untouched — the orb keeps its character, it just costs ~60% less to draw. Buffer allocation (MAX_PARTICLES = 180 in particles.ts) is unchanged; the profile only caps the runtime active count, so it can be flipped on/off without reallocation. Files: - dashboard/src/aevp/pi-profile.ts (new, 94 lines, pure functions) - dashboard/src/aevp/colorMapping.ts (2-line import + 5-line call site) - dashboard/src/aevp/renderer.ts (1-line import + 5-line frame gate) - dashboard/docs/pi-profile.md (new, usage + verification notes) Use case: ArgentOS dashboard running on a Raspberry Pi 5 with a 7" touchscreen, software rendering, no dedicated GPU. Measured reduction pending — review against a baseline tab before/after enabling. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughA new Pi Profile performance mode is introduced for the ArgentOS dashboard's particle system. The feature reduces the particle cap from 180 to 60, applies a 0.5 density scale, and throttles frame rendering to ~30 fps via multiple activation mechanisms. Configuration is evaluated at module load from environment variables, localStorage, and URL parameters. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
dashboard/src/aevp/colorMapping.ts (1)
1-1:⚠️ Potential issue | 🟡 MinorFormatter failure is blocking CI here too.
Run
oxfmton this file; current branch won’t pass checks as-is.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dashboard/src/aevp/colorMapping.ts` at line 1, Run the formatter (oxfmt) on dashboard/src/aevp/colorMapping.ts and commit the resulting changes so the file passes CI; specifically, format the entire file (fix indentation, trailing spaces, comment blocks, and any broken JSDoc starting at the top of the file) and re-run the linter/CI locally to confirm; ensure the formatted file is staged and pushed so the branch no longer fails the oxfmt check.dashboard/src/aevp/renderer.ts (1)
1-1:⚠️ Potential issue | 🟡 MinorCI is red on formatting in this file.
oxfmt --checkis failing here; run formatter and re-push so the pipeline goes green.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@dashboard/src/aevp/renderer.ts` at line 1, This file fails the oxfmt style check; run the formatter (oxfmt) on dashboard/src/aevp/renderer.ts (or run oxfmt --check locally then oxfmt to fix) and re-commit the formatted changes so the CI style check passes; ensure you stage and push the updated file after formatting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@dashboard/docs/pi-profile.md`:
- Around line 22-24: Doc inconsistency: update the sentence that currently
claims the profile can be flipped “without a reload” to match the rest of the
doc which states activation is evaluated once at module load and requires a
reload; reference the fixed buffer capacity (MAX_PARTICLES in aevp/particles.ts)
but clarify that while the buffer is preallocated for 180 particles, the profile
activation/enablement is determined at module initialization and changing the
profile requires a reload to take effect.
- Line 1: The markdown file with header "# Pi Profile — low-intensity AEVP mode"
is failing formatter checks; run the repository's formatter (oxfmt) on this
document to reformat it, verify the changes, and commit the formatted file so CI
passes (e.g., run `oxfmt dashboard/docs/pi-profile.md`, review the diff, then
stage and commit the updated file).
In `@dashboard/src/aevp/colorMapping.ts`:
- Around line 449-455: The computed maxParticles (from piCap, piScale, and
presence.particleDensity) is intended as a hard upper bound but is later
overridden by a clamp to 100 and a fixed lower bound of 5; update the downstream
particle count logic (the place that clamps to 100 and enforces 5) so the final
particleCount is always <= maxParticles — for example compute the tentative
count as now, then set particleCount = Math.min(maxParticles,
Math.max(minAllowedButNotAboveMax, tentativeCount)); ensure minAllowed is itself
constrained to <= maxParticles (use Math.min(5, maxParticles) or similar) so
low-density cases cannot force particleCount above maxParticles.
In `@dashboard/src/aevp/pi-profile.ts`:
- Line 1: The new module pi-profile.ts is not formatted according to the repo
style; run the formatter (oxfmt --apply or your project's preferred formatter)
on pi-profile.ts and re-run oxfmt --check to ensure it passes, then stage and
commit the formatting changes; if your editor uses Prettier/ESLint, run those
commands (or the project's format script) so the module header/comments and the
rest of the file match repository formatting rules.
- Around line 30-35: Replace the non-existent custom Vite bridge
(globalThis.__ARGENT_VITE_ENV__) in pi-profile.ts with the real Vite environment
object import.meta.env: locate the block that creates the local meta variable
and checks meta?.[name] (the code that reads globalThis.__ARGENT_VITE_ENV__),
and change it to read from import.meta.env (checking import.meta.env[name],
treating "0" and "" as falsy as before) so VITE_PI_PROFILE and other VITE_* vars
work the same way as the rest of the app.
---
Outside diff comments:
In `@dashboard/src/aevp/colorMapping.ts`:
- Line 1: Run the formatter (oxfmt) on dashboard/src/aevp/colorMapping.ts and
commit the resulting changes so the file passes CI; specifically, format the
entire file (fix indentation, trailing spaces, comment blocks, and any broken
JSDoc starting at the top of the file) and re-run the linter/CI locally to
confirm; ensure the formatted file is staged and pushed so the branch no longer
fails the oxfmt check.
In `@dashboard/src/aevp/renderer.ts`:
- Line 1: This file fails the oxfmt style check; run the formatter (oxfmt) on
dashboard/src/aevp/renderer.ts (or run oxfmt --check locally then oxfmt to fix)
and re-commit the formatted changes so the CI style check passes; ensure you
stage and push the updated file after formatting.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 067cb78c-b703-40a7-bb4c-83e134e9177d
📒 Files selected for processing (4)
dashboard/docs/pi-profile.mddashboard/src/aevp/colorMapping.tsdashboard/src/aevp/pi-profile.tsdashboard/src/aevp/renderer.ts
| @@ -0,0 +1,68 @@ | |||
| # Pi Profile — low-intensity AEVP mode | |||
There was a problem hiding this comment.
Docs file is also failing formatter checks.
Run oxfmt for this markdown file so CI passes cleanly.
🧰 Tools
🪛 GitHub Actions: CI
[error] 1-1: Oxfmt --check reported formatting issues in this file. Run oxfmt without --check (e.g., 'oxfmt' or 'oxfmt --write') to fix.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@dashboard/docs/pi-profile.md` at line 1, The markdown file with header "# Pi
Profile — low-intensity AEVP mode" is failing formatter checks; run the
repository's formatter (oxfmt) on this document to reformat it, verify the
changes, and commit the formatted file so CI passes (e.g., run `oxfmt
dashboard/docs/pi-profile.md`, review the diff, then stage and commit the
updated file).
| The hard allocation (`MAX_PARTICLES = 180` in `aevp/particles.ts`) is | ||
| unchanged — the buffer still holds room for 180 — so the profile can | ||
| be flipped on and off without a reload or re-alloc. |
There was a problem hiding this comment.
Small but important doc mismatch on reload behavior.
Line 24 says profile can be flipped “without a reload,” but Lines 28-30 and Line 38 say activation is evaluated once at module load and needs reload. Please make this consistent.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@dashboard/docs/pi-profile.md` around lines 22 - 24, Doc inconsistency: update
the sentence that currently claims the profile can be flipped “without a reload”
to match the rest of the doc which states activation is evaluated once at module
load and requires a reload; reference the fixed buffer capacity (MAX_PARTICLES
in aevp/particles.ts) but clarify that while the buffer is preallocated for 180
particles, the profile activation/enablement is determined at module
initialization and changing the profile requires a reload to take effect.
| // Pi profile: scale density + apply a hard cap on top of identity preset. | ||
| const piCap = getMaxParticlesCap(); | ||
| const piScale = getDensityScale(); | ||
| const maxParticles = Math.min( | ||
| piCap, | ||
| Math.round(100 * presence.particleDensity * piScale), | ||
| ); |
There was a problem hiding this comment.
Big issue: Pi cap is not enforced end-to-end.
Strong concept, but the hard cap can be broken downstream. maxParticles is computed here, then Line 486 clamps to 100, which can push counts above Pi cap. Also, fixed lower bound 5 can exceed maxParticles when density is low.
✅ Proposed fix to keep particleCount always ≤ maxParticles
const maxParticles = Math.min(
piCap,
Math.round(100 * presence.particleDensity * piScale),
);
+ const baseFloor = Math.min(5, maxParticles);
let particleCount = Math.round(
clamp(
maxParticles * (0.3 + moodVis.brightness * 0.4 + arousal * 0.3) * energyMul,
- 5,
+ baseFloor,
maxParticles,
),
);
@@
- particleCount = Math.round(clamp(particleCount * (0.7 + p.energy * 0.6), 3, 100));
+ const personalityFloor = Math.min(3, maxParticles);
+ particleCount = Math.round(
+ clamp(particleCount * (0.7 + p.energy * 0.6), personalityFloor, maxParticles),
+ );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@dashboard/src/aevp/colorMapping.ts` around lines 449 - 455, The computed
maxParticles (from piCap, piScale, and presence.particleDensity) is intended as
a hard upper bound but is later overridden by a clamp to 100 and a fixed lower
bound of 5; update the downstream particle count logic (the place that clamps to
100 and enforces 5) so the final particleCount is always <= maxParticles — for
example compute the tentative count as now, then set particleCount =
Math.min(maxParticles, Math.max(minAllowedButNotAboveMax, tentativeCount));
ensure minAllowed is itself constrained to <= maxParticles (use Math.min(5,
maxParticles) or similar) so low-density cases cannot force particleCount above
maxParticles.
| @@ -0,0 +1,95 @@ | |||
| /** | |||
There was a problem hiding this comment.
Formatting is also failing in this new module.
oxfmt --check reports issues here; please format before merge.
🧰 Tools
🪛 GitHub Actions: CI
[error] 1-1: Oxfmt --check reported formatting issues in this file. Run oxfmt without --check (e.g., 'oxfmt' or 'oxfmt --write') to fix.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@dashboard/src/aevp/pi-profile.ts` at line 1, The new module pi-profile.ts is
not formatted according to the repo style; run the formatter (oxfmt --apply or
your project's preferred formatter) on pi-profile.ts and re-run oxfmt --check to
ensure it passes, then stage and commit the formatting changes; if your editor
uses Prettier/ESLint, run those commands (or the project's format script) so the
module header/comments and the rest of the file match repository formatting
rules.
| try { | ||
| // Vite (import.meta.env is statically available only inside Vite-processed | ||
| // modules; protect with a typeof check so this file compiles under raw tsc) | ||
| const meta = (globalThis as { __ARGENT_VITE_ENV__?: Record<string, string | undefined> }) | ||
| .__ARGENT_VITE_ENV__; | ||
| if (meta?.[name] && meta[name] !== "0" && meta[name] !== "") return true; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify whether the custom bridge actually exists and is initialized.
# Expected good result:
# 1) A concrete assignment to globalThis.__ARGENT_VITE_ENV__ appears in startup code, OR
# 2) This module (or equivalent) reads import.meta.env directly.
rg -n -C3 '__ARGENT_VITE_ENV__|import\.meta\.env|VITE_PI_PROFILE'Repository: ArgentAIOS/argentos-core
Length of output: 6417
The custom Vite env bridge is a loser — it's never initialized anywhere.
Look, this code reads globalThis.__ARGENT_VITE_ENV__ for VITE_PI_PROFILE, but that custom global doesn't exist in the codebase. Zero occurrences. Not initialized, not set up, nothing. Every other file uses standard import.meta.env directly — the beautiful, normal way. Meanwhile your documentation says users should set VITE_PI_PROFILE=1, but it won't work because this code is looking in the wrong place. Sad!
Fix it to use import.meta.env like the rest of the app. It's the right move, it's the smart move.
Suggested fix
- const meta = (globalThis as { __ARGENT_VITE_ENV__?: Record<string, string | undefined> })
- .__ARGENT_VITE_ENV__;
+ const meta = (import.meta as { env?: Record<string, string | undefined> }).env;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| try { | |
| // Vite (import.meta.env is statically available only inside Vite-processed | |
| // modules; protect with a typeof check so this file compiles under raw tsc) | |
| const meta = (globalThis as { __ARGENT_VITE_ENV__?: Record<string, string | undefined> }) | |
| .__ARGENT_VITE_ENV__; | |
| if (meta?.[name] && meta[name] !== "0" && meta[name] !== "") return true; | |
| try { | |
| // Vite (import.meta.env is statically available only inside Vite-processed | |
| // modules; protect with a typeof check so this file compiles under raw tsc) | |
| const meta = (import.meta as { env?: Record<string, string | undefined> }).env; | |
| if (meta?.[name] && meta[name] !== "0" && meta[name] !== "") return true; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@dashboard/src/aevp/pi-profile.ts` around lines 30 - 35, Replace the
non-existent custom Vite bridge (globalThis.__ARGENT_VITE_ENV__) in
pi-profile.ts with the real Vite environment object import.meta.env: locate the
block that creates the local meta variable and checks meta?.[name] (the code
that reads globalThis.__ARGENT_VITE_ENV__), and change it to read from
import.meta.env (checking import.meta.env[name], treating "0" and "" as falsy as
before) so VITE_PI_PROFILE and other VITE_* vars work the same way as the rest
of the app.
Summary
Adds an opt-in Pi Profile to AEVP that lowers the per-frame cost without changing identity presets or personality modulation. Motivation: the ArgentOS dashboard is going to run on a Raspberry Pi 5 with a 7" touchscreen and software rendering — the 180-particle / 60+ fps default pins the CPU.
What changes
The buffer allocation (`MAX_PARTICLES = 180` in `particles.ts`) is untouched — the profile only caps the runtime active count, so it can be flipped on/off without reallocation.
Activation (any ONE of these)
Files
Not touched
Test plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation