Skip to content

Fix REPL swallowing mid-line slashes; expose provider on CommandContext - #23

Open
aronissac001-beep wants to merge 2 commits into
GPT-AGI:mainfrom
aronissac001-beep:fix/repl-slash-swallowed
Open

Fix REPL swallowing mid-line slashes; expose provider on CommandContext#23
aronissac001-beep wants to merge 2 commits into
GPT-AGI:mainfrom
aronissac001-beep:fix/repl-slash-swallowed

Conversation

@aronissac001-beep

Copy link
Copy Markdown

Two small changes found while building a local-inference provider on top of Clawd-Code. The first is a real bug; the second is a tiny enabling addition you may prefer to drop.

1. The REPL swallows every mid-line /

src/repl/core.py registers a key binding for / that consumes the keypress unconditionally, but only re-inserts the character when the buffer is empty:

@self.bindings.add("/")
def _show_slash_completions(event):
    buf = event.current_buffer
    if buf.text == "":          # <-- only inserts on an empty buffer
        buf.insert_text("/")
        buf.start_completion(select_first=False)

Every / typed after the first character is discarded before it reaches the buffer.

Reproduction

Type into the REPL, without submitting:

a/b/c-d/e

Screen contents, captured through a VT100 emulator (pyte) driving a real Windows pseudo-console, so prompt_toolkit runs for real:

screen shows
main ❯ abc-de
this PR ❯ a/b/c-d/e

Why it matters more than it looks

Every file path, URL and regex typed into a prompt silently loses its separators. Asking the agent to read src/repl/core.py sends srcreplcore.py; the Read tool fails, and the agent burns turns recovering through Glob — when it recovers at all. In one of my runs it took three tool calls to find a file it had been handed the exact path to.

The failure mode is easy to misattribute: it looks like the model is hallucinating paths, because by the time anything is logged the slashes are already gone. It is invisible to any test that does not go through a real terminal — I only found it after driving the REPL through a genuine pty, having earlier "verified" the REPL by calling handle_command()/chat() directly, which bypasses prompt_toolkit entirely.

The fix

Always insert the character; open the command palette only when / is the first character on the line, which is what the binding was for. /help and the palette still behave as before.

2. Expose the active provider on CommandContext

CommandContext carries the conversation, cost tracker and history, but not the provider, so a local command cannot inspect or reconfigure the model it is talking to. Commands that report or switch model state have no supported route to it.

Adds an optional provider field, threads it through create_command_context, and passes it from the REPL. Defaulted to None, so every existing caller is unaffected.

This one is a small enabling change rather than a bug fix, and it has no consumer in this PR — the commands that use it live in my fork. It is a separate commit, so please drop it if you would rather it arrived with its callers. The first commit stands alone.

Testing

  • A/B verified in a real terminal via pywinpty + pyte, shown above.
  • /help and the slash palette still open correctly.
  • Read src/local/router.py resolves on the first attempt instead of the third.
  • Both commits compile; change is 3 files, +14/−2.

The key binding registered for "/" consumes the keypress unconditionally but
only re-inserted the character when the buffer was empty. Any "/" typed after
the first character was therefore discarded before reaching the buffer.

Repro, in the REPL:

    > Repeat this string back exactly: a/b/c-d/e

The prompt line shows "abc-de" and the model receives "abc-de".

The impact is larger than it first appears: every file path, URL and regex
typed into a prompt loses its separators. A request to read src/repl/core.py
arrives as "srcreplcore.py", the Read tool fails, and the agent burns turns
recovering via Glob -- when it recovers at all. The model looks like it is
hallucinating paths, so the failure is easy to misattribute.

Now always inserts the character, and opens the command palette only when "/"
is the first character on the line, which is what the binding was for.

Verified in a real terminal (pywinpty pseudo-console, so prompt_toolkit runs
for real): "a/b/c-d/e" survives intact, "/help" still opens the palette, and
"Read src/local/router.py" resolves on the first attempt instead of the third.
CommandContext carries the conversation, cost tracker and history, but not the
provider, so a local command cannot inspect or reconfigure the model it is
talking to. Commands that report or switch model state have no supported way
to reach it and end up reaching through context.conversation for an attribute
that is not there.

Adds an optional `provider` field, threads it through create_command_context,
and passes it from the REPL. Defaulted to None, so every existing caller and
command is unaffected.

This is a small enabling change rather than a bug fix, and it has no consumer
in this PR -- the commands that use it live downstream. Happy to drop this
commit if you would rather it arrive with its callers.
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.

1 participant