Map unknown finish_reason values (e.g. "end" from Ollama/LM Studio) to
"stop" instead of throwing, since assistant content is already produced.
fixes#2142
0x08 (BS) was treated as plain backspace alongside 0x7f (DEL). On
Windows Terminal, Backspace sends 0x7f and Ctrl+Backspace sends 0x08,
making ctrl+backspace bindings unreachable.
Now 0x08 matches ctrl+backspace (and ctrl+h, same byte) but not plain
backspace. 0x7f remains plain backspace.
fixes#2139
Use pipeline() instead of finished(readable.pipe(writable)) so stream
errors from abort signals are caught as promise rejections. Increase
download timeout from 10s to 120s for multi-MB archives.
closes#2066
* feat(session-manager): allow supplying custom session ID in newSession()
Add optional `id` field to `NewSessionOptions`. When provided, this ID
is used as the session ID instead of generating a random UUID. Existing
callers are unaffected since the field is optional and falls back to
`randomUUID()`.
Closes#2097
* test(session-manager): add tests for custom session ID in newSession()
Verify that newSession() uses the provided id when supplied, falls back
to randomUUID() when omitted, and includes the custom id in the session
header.
The _isRetryableError() regex used literal spaces ("server error",
"internal error") but Codex SSE error events use underscores
("server_error"). Change to .? so both space and underscore (and
direct concatenation) are matched, enabling automatic retry on
transient Codex SSE errors.
fixes#2091
* feat(tui): treat paste markers as atomic segments in editor
Paste markers like `[paste #1 +123 lines]` are now treated as single
atomic units for cursor movement, word navigation, deletion, and
wrapping. Only markers with valid paste IDs (present in the editor's
pastes Map) are treated atomically.
* fix(tui): word-wrap oversized atomic segments in editor
Some OpenAI-compatible providers (e.g., Moonshot/Kimi) return usage
data in chunk.choices[0].usage instead of the standard chunk.usage.
Extract usage parsing into a helper and check choice.usage as fallback.
closes#2017
The OpenAI Chat Completions API standard format for assistant message
content is a plain string. Sending it as an array of
{type:"text", text:"..."} objects causes some models (notably DeepSeek
V3.2 via NVIDIA NIM) to mirror the content-block structure literally
in their output. This produces recursive nesting where each turn wraps
the previous content blocks deeper:
[{'type':'text','text':'[{\'type\':\'text\',\'text\':...}]'}]
The fix unifies the assistant content serialization to always use a
joined string — the same approach already used for the github-copilot
provider — for all openai-completions backends.
Affected models observed: deepseek-ai/deepseek-v3.2 (nvidia provider).
Models like GLM-5, GPT-4, Claude were unaffected as they tolerate
array content, but sending a standard string is safer for all.
Co-authored-by: geraldoaax <geraldoaax@users.noreply.github.com>
* fix(coding-agent): use supported Anthropic compaction model
The Anthropic compaction test was pinned to claude-3-7-sonnet-latest, which now fails with a 404 because that model line was retired. Switch the test to the existing claude-sonnet-4-5 convention used elsewhere in coding-agent tests.
* test(coding-agent): disable git prompts in HTTPS parsing test
The HTTPS URL parsing test intentionally clones a nonexistent GitHub repo to verify that bare HTTPS sources dispatch to git. Under a TTY, git can prompt on that path and hang the test run.
Set GIT_TERMINAL_PROMPT=0 in that test so it still exercises real git but fails fast instead of waiting for terminal input.