Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
C
coderai
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexlab
coderai
Commits
0c31d3fd
Commit
0c31d3fd
authored
Mar 01, 2026
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix thinking display to use single line with proper timer updates
parent
0d76e514
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
71 additions
and
46 deletions
+71
-46
coder
coder
+71
-46
No files found.
coder
View file @
0c31d3fd
...
@@ -452,45 +452,56 @@ class CoderClient:
...
@@ -452,45 +452,56 @@ class CoderClient:
def
_handle_streaming_response
(
self
,
response
:
requests
.
Response
)
->
str
:
def
_handle_streaming_response
(
self
,
response
:
requests
.
Response
)
->
str
:
"""Handle streaming response from API."""
"""Handle streaming response from API."""
import
time
import
time
import
re
full_content
=
""
full_content
=
""
tool_calls
=
[]
tool_calls
=
[]
current_tool_call
=
None
in_thinking
=
False
in_thinking
=
False
thinking_content
=
""
thinking_content
=
""
thinking_start_time
=
0
thinking_start_time
=
0
last_elapsed
=
-
1
last_elapsed
=
-
1
printed_final_thinking
=
False
thinking_line_printed
=
False
def
update_thinking_display
(
force
=
False
):
def
print_thinking_line
(
elapsed
,
content
,
final
=
False
):
"""Update the thinking display line."""
"""Print or update the thinking line."""
nonlocal
last_elapsed
nonlocal
thinking_line_printed
if
not
in_thinking
:
# Filter out <tool> tags and newlines for display
return
display_content
=
re
.
sub
(
r'<tool[^>]*>.*?</tool>'
,
''
,
content
,
flags
=
re
.
DOTALL
)
current_time
=
time
.
time
()
display_content
=
display_content
.
replace
(
'
\n
'
,
' '
)
.
replace
(
'
\r
'
,
''
)
elapsed
=
int
(
current_time
-
thinking_start_time
)
display_content
=
display_content
.
strip
()
if
elapsed
!=
last_elapsed
or
force
:
last_elapsed
=
elapsed
# Get last 60 chars to fit on screen
# Clear line and redraw
if
len
(
display_content
)
>
60
:
display_text
=
thinking_content
[
-
70
:]
# Last 70 chars to fit on screen
display_content
=
"..."
+
display_content
[
-
60
:]
if
len
(
thinking_content
)
>
70
:
display_text
=
"..."
+
display_text
line
=
f
"[{elapsed}s] Thinking: [{display_content}]"
# Use carriage return to overwrite the line
line
=
f
"[{elapsed}s] Thinking: [{display_text}]"
if
not
thinking_line_printed
:
# Pad with spaces to clear previous content
# First time - just print
print
(
f
"
\r
{Colors.DIM}{line:<100}{Colors.RESET}"
,
end
=
''
,
flush
=
True
)
print
(
f
"
\r
{Colors.DIM}{line}{Colors.RESET}"
,
end
=
''
,
flush
=
True
)
thinking_line_printed
=
True
else
:
# Overwrite existing line
# Clear to end of line and print new content
print
(
f
"
\r\033
[K{Colors.DIM}{line}{Colors.RESET}"
,
end
=
''
,
flush
=
True
)
if
final
:
print
()
# Move to new line
# Use iter_content with smaller chunk size for better real-time handling
# Use iter_content with smaller chunk size for better real-time handling
buffer
=
""
buffer
=
""
last_update
=
time
.
time
()
last_
timer_
update
=
time
.
time
()
for
chunk
in
response
.
iter_content
(
chunk_size
=
256
,
decode_unicode
=
True
):
for
chunk
in
response
.
iter_content
(
chunk_size
=
256
,
decode_unicode
=
True
):
current_time
=
time
.
time
()
current_time
=
time
.
time
()
# Update thinking timer every second even without new content
# Update thinking timer every second
if
in_thinking
and
current_time
-
last_update
>=
1.0
:
if
in_thinking
:
update_thinking_display
()
elapsed
=
int
(
current_time
-
thinking_start_time
)
last_update
=
current_time
if
elapsed
!=
last_elapsed
and
current_time
-
last_timer_update
>=
1.0
:
last_elapsed
=
elapsed
last_timer_update
=
current_time
print_thinking_line
(
elapsed
,
thinking_content
)
if
chunk
:
if
chunk
:
buffer
+=
chunk
buffer
+=
chunk
...
@@ -520,35 +531,35 @@ class CoderClient:
...
@@ -520,35 +531,35 @@ class CoderClient:
if
'<think>'
in
content
:
if
'<think>'
in
content
:
in_thinking
=
True
in_thinking
=
True
thinking_start_time
=
time
.
time
()
thinking_start_time
=
time
.
time
()
last_update
=
thinking_start_time
last_timer_update
=
thinking_start_time
last_elapsed
=
0
thinking_content
=
""
thinking_content
=
""
thinking_line_printed
=
False
# Print initial thinking line
print_thinking_line
(
0
,
""
)
continue
continue
if
in_thinking
:
if
in_thinking
:
if
'</think>'
in
content
:
if
'</think>'
in
content
:
# End of thinking
# End of thinking
in_thinking
=
False
in_thinking
=
False
# Show final thinking line
parts
=
content
.
split
(
'</think>'
,
1
)
elapsed
=
int
(
current_time
-
thinking_start_time
)
think_part
=
parts
[
0
]
think_part
=
content
.
split
(
'</think>'
)[
0
]
if
think_part
:
if
think_part
:
thinking_content
+=
think_part
thinking_content
+=
think_part
# Clear line and show final thinking
display_text
=
thinking_content
[
-
70
:]
# Last 70 chars
# Show final thinking line
if
len
(
thinking_content
)
>
70
:
elapsed
=
int
(
current_time
-
thinking_start_time
)
display_text
=
"..."
+
display_text
print_thinking_line
(
elapsed
,
thinking_content
,
final
=
True
)
line
=
f
"[{elapsed}s] Thinking: [{display_text}]"
print
(
f
"
\r
{Colors.DIM}{line:<100}{Colors.RESET}
\n
"
,
end
=
''
,
flush
=
True
)
printed_final_thinking
=
True
# Get content after </think>
# Get content after </think>
actual_content
=
content
.
split
(
'</think>'
,
1
)[
-
1
]
actual_content
=
parts
[
1
]
if
len
(
parts
)
>
1
else
""
if
actual_content
:
if
actual_content
:
print
(
actual_content
,
end
=
''
,
flush
=
True
)
print
(
actual_content
,
end
=
''
,
flush
=
True
)
full_content
+=
actual_content
full_content
+=
actual_content
else
:
else
:
# Still thinking - accumulate
and display
# Still thinking - accumulate
thinking_content
+=
content
thinking_content
+=
content
update_thinking_display
(
force
=
True
)
else
:
else
:
# Normal content
# Normal content
print
(
content
,
end
=
''
,
flush
=
True
)
print
(
content
,
end
=
''
,
flush
=
True
)
...
@@ -580,8 +591,8 @@ class CoderClient:
...
@@ -580,8 +591,8 @@ class CoderClient:
except
json
.
JSONDecodeError
:
except
json
.
JSONDecodeError
:
continue
continue
if
in_thinking
and
not
printed_final_thinking
:
if
in_thinking
:
print
(
"
\n
"
,
end
=
''
,
flush
=
True
)
print
(
)
# End thinking line if still in thinking
print
()
# Newline after streaming
print
()
# Newline after streaming
# Execute tool calls if any
# Execute tool calls if any
...
@@ -625,16 +636,30 @@ class CoderClient:
...
@@ -625,16 +636,30 @@ class CoderClient:
else
:
else
:
result
=
self
.
tool_executor
.
execute
(
tool_name
,
arguments
)
result
=
self
.
tool_executor
.
execute
(
tool_name
,
arguments
)
# Show result summary
if
"error"
in
result
:
print
(
f
"{Colors.RED}Error: {result['error']}{Colors.RESET}"
)
elif
result
.
get
(
'declined'
):
pass
# Already printed "Skipped"
else
:
print
(
f
"{Colors.GREEN}Success{Colors.RESET}"
)
# Show command output for execute_command
if
tool_name
==
'execute_command'
and
'stdout'
in
result
:
stdout
=
result
[
'stdout'
]
.
strip
()
if
stdout
:
# Show first few lines of output
lines
=
stdout
.
split
(
'
\n
'
)[:
20
]
print
(
f
"{Colors.CYAN}Output:{Colors.RESET}"
)
for
line
in
lines
:
print
(
f
" {line}"
)
if
len
(
stdout
.
split
(
'
\n
'
))
>
20
:
print
(
f
" {Colors.DIM}... ({len(stdout.split(chr(10))) - 20} more lines){Colors.RESET}"
)
tool_results
.
append
({
tool_results
.
append
({
"tool_call_id"
:
tc
[
'id'
],
"tool_call_id"
:
tc
[
'id'
],
"role"
:
"tool"
,
"role"
:
"tool"
,
"content"
:
json
.
dumps
(
result
)
"content"
:
json
.
dumps
(
result
)
})
})
if
"error"
in
result
:
print
(
f
"{Colors.RED}Error: {result['error']}{Colors.RESET}"
)
elif
not
result
.
get
(
'declined'
):
print
(
f
"{Colors.GREEN}Success{Colors.RESET}"
)
# Add assistant message with tool calls to history
# Add assistant message with tool calls to history
self
.
conversation_history
.
append
({
self
.
conversation_history
.
append
({
...
@@ -653,7 +678,7 @@ class CoderClient:
...
@@ -653,7 +678,7 @@ class CoderClient:
self
.
conversation_history
.
extend
(
tool_results
)
self
.
conversation_history
.
extend
(
tool_results
)
# Get follow-up response with tool results
# Get follow-up response with tool results
print
(
"
\n
[Getting follow-up response...]
"
)
print
(
f
"
\n
{Colors.DIM}[Getting follow-up response...]{Colors.RESET}
"
)
return
self
.
_get_follow_up_response
()
return
self
.
_get_follow_up_response
()
# Add assistant response to history
# Add assistant response to history
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment