repl + renderer: streaming assistant output (Phase 1)
repl.ask_ai now drives broker.chat_stream and pumps each delta into renderer.assistant_delta(delta) as it arrives. renderer.assistant_flush is called when the stream ends to add a trailing newline if missing. The full reassembled response is then handed to executor.extract_cmd_lines for the CMD: confirm-and-execute path (unchanged from Phase 0). renderer.assistant() is kept for non-streaming callers (none in tree right now, but cheap to keep around). assistant_delta/flush share no state with assistant(); they use a module-local stream_buf that tracks the in-progress streamed block. Q12 deferred: incremental CMD: highlighting (cursor-positioning re- render on flush) is not implemented in Phase 1 — deltas emit raw. The §6 CMD: marker is still extractable on the reassembled string post- stream, which is what executor cares about. Renderer's bold+cyan treatment for CMD: lines stays available via M.assistant(). Broker error / SSE-framed api-error path still pops the user turn and restores ctx.pending_exec_output. Order: assistant_flush always runs (even on error) so the cursor lands on a fresh line before the broker- error status renders. Live verification: `Count one to ten` against hossenfelder fast streams deltas through to stdout incrementally; CMD: extraction works on the reassembled string; confirm gate intact. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -68,21 +68,30 @@ function M.run(config)
|
||||
end
|
||||
end
|
||||
|
||||
-- Send user text to the active model, render the response, and (per
|
||||
-- §6 + config.shell.confirm_cmd) optionally execute extracted CMD: lines.
|
||||
-- Send user text to the active model, render the response token-by-token
|
||||
-- via broker.chat_stream, and (per §6 + config.shell.confirm_cmd) optionally
|
||||
-- execute extracted CMD: lines on the reassembled full text.
|
||||
local function ask_ai(text)
|
||||
local prev_pending = ctx.pending_exec_output
|
||||
ctx:append_user(text) -- flushes any pending [exec output] as prefix
|
||||
local resp, err = broker.chat(active_cfg, ctx:to_messages())
|
||||
if not resp then
|
||||
|
||||
local parts = {}
|
||||
local ok, err = broker.chat_stream(active_cfg, ctx:to_messages(),
|
||||
function(delta)
|
||||
parts[#parts + 1] = delta
|
||||
renderer.assistant_delta(delta)
|
||||
end)
|
||||
renderer.assistant_flush()
|
||||
|
||||
if not ok then
|
||||
renderer.status("broker error: " .. tostring(err))
|
||||
table.remove(ctx.turns) -- back out the merged user turn
|
||||
ctx.pending_exec_output = prev_pending -- restore buffered exec output
|
||||
return
|
||||
end
|
||||
local resp = table.concat(parts)
|
||||
ctx:append({ role = "assistant", content = resp })
|
||||
status_evictions(ctx:enforce_budget())
|
||||
renderer.assistant(resp)
|
||||
|
||||
for _, cmd in ipairs(executor.extract_cmd_lines(resp)) do
|
||||
local doit
|
||||
|
||||
Reference in New Issue
Block a user