ucode-agent 1.14.0 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/core/loop.js +18 -1
- package/src/ui/screen.js +45 -7
package/package.json
CHANGED
package/src/core/loop.js
CHANGED
|
@@ -434,6 +434,23 @@ function systemPrompt({ cwd, skills, mode, check, map, memory }) {
|
|
|
434
434
|
'',
|
|
435
435
|
'## How to work',
|
|
436
436
|
'',
|
|
437
|
+
'Before building anything, turn the request into a list of what it must do — every',
|
|
438
|
+
'feature named, and the ones any user would expect whether or not they were named',
|
|
439
|
+
'(an empty state, an error state, the keyboard doing the obvious thing, working on',
|
|
440
|
+
'a phone). Keep it as the plan. Build against it, then go through it one item at a',
|
|
441
|
+
'time before you say a word about being finished. Most of what gets missed was',
|
|
442
|
+
'never written down.',
|
|
443
|
+
'',
|
|
444
|
+
'Do not put code in your reply. Not a snippet, not "here is the key part", not a',
|
|
445
|
+
'summary of the file. It is already in the file and the user can open it; pasting',
|
|
446
|
+
'it again buries the one or two sentences that actually matter. Say what it does',
|
|
447
|
+
'and what to try.',
|
|
448
|
+
'',
|
|
449
|
+
'Do not claim it is done while anything is still running or unchecked. "I have',
|
|
450
|
+
'built it" said before the build finishes is worse than saying nothing: the user',
|
|
451
|
+
'believes you, looks, and finds it broken. Finish, check, then say so — and if',
|
|
452
|
+
'something is incomplete, say which part and why.',
|
|
453
|
+
'',
|
|
437
454
|
'FIRST, EVERY TIME: one short line saying what you are about to do, then the tool',
|
|
438
455
|
'calls. Never open a turn with a tool call and no words. "Right, the HTML',
|
|
439
456
|
'structure first." / "Now the state and the render loop." / "That is the layout',
|
|
@@ -986,7 +1003,7 @@ export class Agent {
|
|
|
986
1003
|
};
|
|
987
1004
|
// Only a real terminal has somewhere to stream into.
|
|
988
1005
|
if (this.full) {
|
|
989
|
-
opts.onThinking = () => this.ui.thinkingDelta();
|
|
1006
|
+
opts.onThinking = (delta) => this.ui.thinkingDelta(delta);
|
|
990
1007
|
opts.onText = (delta) => {
|
|
991
1008
|
if (!streaming) {
|
|
992
1009
|
streaming = true;
|
package/src/ui/screen.js
CHANGED
|
@@ -532,17 +532,54 @@ export class Screen {
|
|
|
532
532
|
// than silence. The spinner counts the seconds so the wait is visibly alive,
|
|
533
533
|
// and the transcript gets one line afterwards saying how long it took.
|
|
534
534
|
|
|
535
|
-
|
|
535
|
+
/**
|
|
536
|
+
* The model's reasoning, live, one line at a time.
|
|
537
|
+
*
|
|
538
|
+
* Models reach for a tool before they say anything, so the first words of a
|
|
539
|
+
* step were arriving a minute after it began — while the reasoning channel
|
|
540
|
+
* had been streaming words the whole time and we were throwing them away to
|
|
541
|
+
* keep a timer. Its latest sentence now shows on one line that rewrites
|
|
542
|
+
* itself, which is something to read from the first second.
|
|
543
|
+
*
|
|
544
|
+
* It is scaffolding, not the answer: it shimmers while it is live and it is
|
|
545
|
+
* taken off the screen the moment the real reply starts.
|
|
546
|
+
*/
|
|
547
|
+
thinkingDelta(text = '') {
|
|
536
548
|
if (this.thoughtSince === undefined) this.thoughtSince = Date.now();
|
|
549
|
+
if (!text) return;
|
|
550
|
+
|
|
551
|
+
this.thought = ((this.thought ?? '') + text).slice(-2000);
|
|
552
|
+
// The last sentence it has finished, or what it has written of the next.
|
|
553
|
+
const parts = this.thought.split(/(?<=[.!?])\s+/).filter((p) => p.trim());
|
|
554
|
+
const latest = (parts[parts.length - 1] ?? '').replace(/\s+/g, ' ').trim();
|
|
555
|
+
if (!latest) return;
|
|
556
|
+
|
|
557
|
+
const line = ` ${shimmer(clip(latest, Math.max(20, this.width() - 6)), this.tick * FRAME_MS)}`;
|
|
558
|
+
if (this.thinkAt === undefined || this.lines[this.thinkAt] === undefined) {
|
|
559
|
+
this.thinkAt = this.lines.length;
|
|
560
|
+
this.push(line);
|
|
561
|
+
} else {
|
|
562
|
+
this.lines[this.thinkAt] = line;
|
|
563
|
+
this.render();
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/** Keep the live thought moving between deltas. */
|
|
568
|
+
paintLiveThought() {
|
|
569
|
+
if (this.thinkAt !== undefined && this.lines[this.thinkAt] !== undefined) this.thinkingDelta('');
|
|
537
570
|
}
|
|
538
571
|
|
|
539
572
|
thinkingEnd() {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
573
|
+
// The thought was the wait; once there is a reply it has nothing to add,
|
|
574
|
+
// so it comes off the screen rather than settling into the transcript.
|
|
575
|
+
if (this.thinkAt !== undefined) {
|
|
576
|
+
this.lines.splice(this.thinkAt, 1);
|
|
577
|
+
if (this.run && this.run.at > this.thinkAt) this.run.at--;
|
|
578
|
+
for (const run of this.segment?.values() ?? []) if (run.at > this.thinkAt) run.at--;
|
|
579
|
+
this.thinkAt = undefined;
|
|
580
|
+
this.render();
|
|
581
|
+
}
|
|
582
|
+
this.thought = '';
|
|
546
583
|
this.thoughtSince = undefined;
|
|
547
584
|
}
|
|
548
585
|
|
|
@@ -886,6 +923,7 @@ export class Screen {
|
|
|
886
923
|
this.spinTimer = setInterval(() => {
|
|
887
924
|
this.tick++;
|
|
888
925
|
this.paintLiveRun();
|
|
926
|
+
this.paintLiveThought();
|
|
889
927
|
this.paintStatus();
|
|
890
928
|
}, FRAME_MS);
|
|
891
929
|
this.spinTimer.unref?.();
|