User hit 'API error 402: ... You requested up to 131072 tokens, but can
only afford 4511' on the assist alias: no provider ever sent max_tokens,
so OpenRouter's credit pre-check billed the routed model's full
worst-case output; user also asked to bound session history to the last
5 requests/responses.
Architect decisions:
- AI_MAX_TOKENS (num, default 2048): sent as max_tokens on OpenRouter
and generationConfig.maxOutputTokens on Gemini — a real per-request
cost ceiling. llamacpp unchanged (local/free, no pre-check).
- AI_SESSION_TURNS (num, default 40 kept back-compat; messages, 2 per
exchange — 10 = last 5 conversations): resolved lazily in session_push
because config loads after the hardcoded line-25 default.
- Both registered in the bin/pos-ai POS_CONFIG @General section, so they
appear in 'pos config ai' with num: validation.
Reviewer hardening (CHANGES_REQUIRED -> fixed): unguarded env input could
reach jq tonumber (0/-5/010/abc all savable via config-ui's ^-?[0-9]+$)
and abort the CLI; both providers and session_push now guard with
^[1-9][0-9]*$ and fall back to the default.
Verified: fake-curl shim smoke (16 provider-body + 12 session-window
checks incl. the 010-regression proof), make gen idempotent, make check
OK, make lint 0 FAIL/0 WARN, make test 17 files / 299 checks / 0 fail
(~49s), bash -n clean, git diff --check clean. Reviewer ACCEPT (twice).
Tester regression round (permanent provider-body + session-pruning
coverage) intentionally not run this cycle — user's call; remains a
documented follow-up.
LLAMACPP_* keys lived under a generic General group. Added a conditional
'@[AI_PROVIDER=llamacpp] llamacpp' caption (mirrors OpenRouter), so the
provider gets its own section; General now only holds AI_SYSTEM_PROMPT
plus the HF keys that arrive from pos-ai-hf. AI_PROVIDER description and
usage text mention llamacpp.
Also: inactive config groups no longer dim the key name — keys stay bold
so an inactive provider block is not one uniform grey wall; only values
and descriptions dim, and the caption still carries the inactive reason.
Missing '=' in LLAMACPP_CTX_SIZE/GPU_LAYERS/THREADS POS_CONFIG entries
made the parser treat the whole string as a key, and a stray bare
'llamacpp' field created a bogus 'llamacpp' entry. Removed the stray
field, added the '=' delimiters, moved *providers=llamacpp to the end.
pos config ai now renders all keys correctly with num flags and intact
colons in descriptions.
Service manager (start/stop/status/models/logs) with systemd user
service generation, GPU auto-detection, model selection from pos ai hf
downloads. Provider adapter integrates with pos ai ask as --provider
llamacpp. Config extends existing ai scope with LLAMACPP_* keys.
87 test cases / 0 failed. make gen/check/lint 0 FAIL / 0 WARN.
Add an optional5th 'trusted' field to aliases
(name|provider|session|prompt|trusted). Trusted aliases pass --trust to
pos ai, which makes _prompt_run_command auto-execute the agent's detected
commands without the Y/n confirmation (command still printed for audit).
- bin/pos-ai: new --trust global flag; _prompt_run_command takes trusted
arg and skips the prompt when set; POS_FLAGS + usage updated
- bin/pos-ai-alias: _ALIAS_TRUSTED array, 5-field env format (backward
compat: missing field defaults to untrusted), Trust column in table,
trust row in show, trust step (5/5) in create wizard with security
warning, trust toggle (4/4) with diff tag in edit wizard, wrapper
scripts get --trust when alias is trusted
- completions/pos.bash + gen docs updated
Gates: make gen && make check && make lint = 0 FAIL, 0 WARN
edited="\$(read ...)" was always empty because read writes to a variable
name, not stdout. Changed to: read -e -p "Command: " -i "\$flat" edited
which stores directly into \$edited.
read -e -i only handles single-line text. Multi-line commands (docker
install etc) broke it. Now flattens newlines to spaces before pre-filling
the readline buffer. User sees a single editable line.
- _inject_command tries: xclip/wl-copy (clipboard) -> xdotool (typing) -> tmux -> history
- Clipboard is primary: user pastes with Ctrl+Shift+V
- preinstall.sh: add xdotool and xclip to PACKAGES
- e: xdotool type (X11/Wayland) -> tmux send-keys -> history fallback
- Command appears on active terminal line for editing before Enter
- Y/Enter: execute, n: add to history
- _extract_commands() parses bash/sh/shell fenced code blocks
- _prompt_run_command() prompts [Y/n] via /dev/tty after AI response
- Y/Enter: execute via run helper (respects DRY_RUN)
- n: command added to history (press up-arrow to recall, edit, run)
- Integrated in both cmd_ask() and cmd_chat()
- Skipped when output is piped/redirected
Each provider now has its own key: AI_GEMINI_API_KEY and OPENROUTER_API_KEY.
No more shared AI_API_KEY that caused cross-provider key leakage (gemini
getting openrouter key → 400 error). resolve_key() sets AI_API_KEY internally
from the active provider's key for adapter use. Config UI shows both keys.
- POS_CONFIG header: replace | with 'or' in AI_PROVIDER description
(bare | was parsed as field separator, splitting one entry into two)
- render_markdown: check /dev/tty as fallback when shell hook redirects
stdout through tee (breaks [ -t 1 ] but /dev/tty stays writable)