Skip to content

refactor: browser chat frontend#1

Open
sskmlm wants to merge 78 commits into
mainfrom
refactor/browser-chat-fe
Open

refactor: browser chat frontend#1
sskmlm wants to merge 78 commits into
mainfrom
refactor/browser-chat-fe

Conversation

@sskmlm

@sskmlm sskmlm commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • add the browser chat frontend slice on top of the websocket protocol runtime branch
  • harden permission request rendering by replacing inline onclick handlers with DOM event listeners
  • URL-encode websocket session ids during frontend connection setup

Testing

  • ruff check .
  • pytest -q tests/api code_puppy/api/tests

Notes

  • Originally stacked on top of refactor/websocket-protocol-runtime.

mpfaffenberger and others added 30 commits July 9, 2026 21:21
Add the Green Screen palette, improve Purple Puppy contrast, paginate the theme picker, and make prompts plus Termflow markdown and syntax highlighting follow the active theme. Also align shutdown callbacks with their awaited async contract.
…rashing (mpfaffenberger#546)

A gateway 502 from custom_anthropic (e.g. puppy-backend) surfaces as an
anthropic.APIStatusError(502) raised mid-stream. pydantic-ai runs the model
stream inside an anyio task group, so it reaches run_agent_task wrapped in an
ExceptionGroup (hence the except* handler). should_retry_streaming only walked
__cause__/__context__ and never descended into ExceptionGroup.exceptions, so the
retryable 5xx looked opaque -> no retry -> 60-line REPL traceback.

- should_retry_streaming now traverses ExceptionGroup members too (cycle-safe,
  per-chain depth cap preserved via a separate traversal axis).
- OpenAI branch of _is_retryable_one now retries on status_code 429/>=500,
  mirroring the Anthropic and ModelHTTPError branches (HTML-body 5xx match no
  snippet, so status_code is the only reliable signal).
- Add 'bad gateway'/'gateway timeout' snippets as belt-and-braces.
- Tests: ExceptionGroup (nested, cause-chain member, cycle-safe, non-transient)
  and OpenAI status-code retry/no-retry coverage.

Co-authored-by: Julien Ellie <julien.ellie@walmart.com>
…affenberger#545)

Extend the existing run_shell_command callback contract so a plugin
can transparently transform a command before execution, in addition to
the existing allow / block semantics.

A callback may now return {"rewrite": "<new command>"} (optionally with
a "rewrite_reason" string for the UI) alongside the existing
{"blocked": True} response. Rewrites are applied in callback
registration order and always emit a visible info line so users can
see what actually ran -- rewriting must never be sneaky.

Why:

* Unlocks a class of plugins that cannot exist today: secret redaction
  in commands, corporate proxy / mirror injection, path fixup,
  attribution trailers on git commits, etc.
* Fully backward compatible: callbacks that return None or
  {"blocked": True} keep working unchanged. The new behaviour only
  fires when a callback explicitly returns a "rewrite" key with a
  non-empty string value.

Change is intentionally scoped down to just the infrastructure. Any
policy-carrying plugin (attribution trailers, redaction rules, ...)
belongs outside core -- either in a user plugin, a project plugin, or
an external marketplace, depending on how opinionated it is.

Tests:

* tests/tools/test_command_runner_full_coverage.py -- three new cases
  covering the happy path (rewrite is applied and executed), a no-op
  rewrite where the string is unchanged (no notice emitted), and
  defensive handling of empty / non-string rewrite payloads.
* All 259 pre-existing tests across command_runner, shell_safety,
  destructive_command_detector, shell_passthrough, and shell_line_crlf
  still pass -- backward compatibility verified.

Docs:

* AGENTS.md: document the new "rewrite" key alongside "blocked" in the
  run_shell_command hook row.

Co-authored-by: a0s01yh <ashish.singhi@walmart.com>
A skill dir that doesn't exist (e.g. a project without .code_puppy/skills/) is routine, not alarming. Demote 'Skill path does not exist' (and the sibling 'SKILL.md not found' in load_full_skill_content) from WARNING to DEBUG. Real read/list failures still log as errors. Tests now assert zero WARNING+ records while keeping the debug breadcrumb.
…ntion (mpfaffenberger#548)

* fix(statusline): cross-platform Windows support + Unicode crash

Two bugs reported by Windows users:

1. Terminal crash on German umlauts (ä, ö, ü)
   subprocess.run(..., text=True) used cp1252 on Windows by default.
   Any non-ASCII character in script output raised UnicodeDecodeError
   and killed the terminal session (exit code 1).
   Fix: add encoding='utf-8', errors='replace' to subprocess.run().

2. /statusline init broken on Windows
   _do_init() always wrote a bash .sh script and set the command to
   the bare file path. Windows has no bash and cmd.exe cannot run .sh.
   Fix: platform-branch on sys.platform == 'win32':
   - Write statusline.ps1 using a PowerShell template (no bash/jq)
   - Set command to: powershell -ExecutionPolicy Bypass -File '<path>'
   Linux/macOS behaviour is fully unchanged.

Tests: add TestCrossPlatform (9 tests) covering:
- _default_script_path() for win32 / linux / darwin
- PS1 template content guards (no bash-isms, no jq)
- _do_init() sets powershell command on win32, bare path on posix
- subprocess.run kwargs asserted to include encoding + errors
- Umlaut output round-trips without raising

* fix: remove unused `call` import (ruff F401)

* style: ruff format fixes (statusline_command + test file)
mpfaffenberger and others added 29 commits July 11, 2026 16:42
…p sub-agent runs + widen retry spacing (mpfaffenberger#616)

The production 502 that kept crashing the REPL is NOT an HTTP 502. A gateway
(puppy-backend custom_anthropic proxy) delivers the upstream failure as an
in-band SSE 'error' event over a connection that itself returned HTTP 200. The
Anthropic SDK builds the APIStatusError from the *stream* response, so:

  * status_code is 200 (not 502),
  * the class is a plain APIStatusError (not InternalServerError),
  * body.error.type is a generic 'internal_error',
  * the only faithful trace of the failure is a '[HTTP 502]' marker in the text.

The classifier keyed on status_code / snippet / a fixed error-type set, all of
which miss this shape, so should_retry_streaming returned False and no retry
fired. The ExceptionGroup-traversal fix (mpfaffenberger#546) couldn't help because every path
led to a classifier that said 'not retryable'.

- _embedded_http_status(): recover the real upstream status from a '[HTTP NNN]'
  marker (case-insensitive); _is_transient_status() centralizes the 429/5xx rule.
- _is_retryable_one(): provider-agnostic early check on the embedded marker
  (4xx markers still do NOT retry) + add 'internal_error' to the Anthropic
  body-type set.
- streaming_retry: widen the default spacing from (1,2,4) to (5,30). With 3
  attempts only 2 delays fire, so the old budget gave up after ~3s -- but a
  gateway 502 ('try again in 30 seconds') outlasts that every time, exhausting
  the burst before the upstream recovers. (5,30) keeps a quick first retry for
  instant SSE blips, then rides out the advertised ~30s outage (~35s window).
- subagent_invocation: wrap temp_agent.run() in streaming_retry(). This path
  was the ONLY unprotected model-stream call -- run_agent_task has the decorator
  but sub-agents (e.g. docs-oracle) ran raw and surfaced the 5xx straight up.
- Tests: TestInBandSSE5xx (marker shape, ExceptionGroup, internal_error type,
  4xx negative) + TestRetryBudgetSpacing (default (5,30), runner sleeps 5 then 30).

Co-authored-by: Julien Ellie <julien.ellie@walmart.com>
@sskmlm
sskmlm changed the base branch from split/websocket-protocol-runtime to main July 14, 2026 22:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants