Two ephemeral breakpoints per request (last system block, final message's
last block) so append-only history re-reads the prior turns' cache;
outbound-only, persisted history stays clean.
Quiet chip (context-fill meter + session total) opening a per-model
input/output/cache breakdown popover; accumulation from live events,
rebuilt from persisted sidecars on load; unit + e2e coverage.
Normalized TokenUsage (input/output/cache split) captured in every provider's
stream and complete paths, persisted as an assistant-message sidecar and sent
on the assistant_message event; matrix gains verified context-window sizes.
Model listing 403/404s under plain ADC; countTokens is free and proves
project+location+API in one call. Verified live: Gemini (global), Qwen MaaS (us-south1).
Segmented track + inset per-method panel with its own Test & save footer.
Vertex gains the same treatment: Google Cloud login (default), service account,
and API key (express mode, Gemini-only with a clear error elsewhere).
'Connect with' segmented choice (API key / profile / IAM keys) shows only that
method's fields; non-selected fields are dropped at build so stale values can't leak.
New optional field: paste the console-generated key, no CLI/IAM setup needed.
Takes precedence over SigV4 credentials, matching boto3; live-tested on Converse.
Test button and saved pill follow the required-secret field (or the first field for
cloud providers); Bedrock/Vertex add-model rows get a family selector.
gemini/ and claude/ ids reuse the native providers; openweight/ goes through the
MaaS OpenAI-compat endpoint with an auto-refreshed google-auth bearer.
Credentials: service-account JSON or Application Default Credentials.
claude/ ids use Anthropic's native Bedrock client; everything else goes via Converse.
Credentials: explicit keys, named profile (incl. SSO), or the ambient AWS chain.
The picker gates ollama:* on a live local probe, so this passed only where Ollama runs and failed in CI.
The probe's own behaviour stays covered by test_ollama_models_gated_on_liveness.
Boundary-hardening pass addressing three audit findings on the local sidecar.
Shell command allowlist (andrewyng/openworker#28):
- Replace prefix-string matching in PermissionEngine._command_allowed with
argv-aware matching: reject any command containing shell operators
(; & | > < ` $( ( and newlines) before consulting the allowlist, then require
the allowlisted entry's tokens to be an exact argv prefix. This closes the
auto-run bypass where an allowlisted "git status" also auto-ran
"git status && rm -rf ~", pipes, redirection, and command substitution.
- Drop language interpreters / package managers (python, python3, node, npm,
npx) from DEFAULT_ALLOWED_COMMANDS — allowlisting an interpreter allowlists
arbitrary code (python3 -c "..."), defeating approval gating. Read-only
inspection commands and pytest remain.
MCP OAuth loopback (andrewyng/openworker#29):
- Verify the OAuth state at the loopback boundary. The MCP SDK already validates
state (compare_digest), so this is not a CSRF fix but defense-in-depth: capture
the state from the authorize URL and have deliver_callback ignore a callback
whose state does not match WITHOUT consuming the pending future, so a stray or
forged local hit can no longer abort a user's in-progress sign-in. Falls back to
prior accept-any behavior when no state was captured.
WebSocket ingestion caps (andrewyng/openworker#38):
- Bound a single user_message frame in the session WS loop: max text length,
max attachment count, and max total attachment bytes. Oversized frames get a
visible error frame and are dropped instead of being buffered into a turn; the
socket stays alive. Guards the unauthenticated loopback socket against cheap
memory spikes.
Tests:
- Allowlist: reject operator chaining (8 variants), argv-boundary matching, and
interpreters-not-auto-allowed-by-default.
- OAuth: state extraction, and mismatched/missing state ignored without consuming
the flow while the matching state still resolves it.
- WS: oversized text and too-many-attachments rejected with an error frame, and a
normal message still works afterwards.
Full suite: 865 passed (1 pre-existing unrelated failure in
test_provider_router::test_manager_curated_models, present on origin/main).
Switch notices no longer consume the retry guard or hide the button.
Error, switch model, Retry is the intended recovery path; retry runs on the new model.
Splash shows the real 6-point OpenWorker star, not the 4-point sparkle glyph.
Settings reload after the health check lands, so the picker can't stay on Loading models.
Gmail/Calendar/Drive show a disabled Coming-soon button; the server refuses the flow too.
Manual token connect and already-connected accounts are untouched.