ucode-agent 1.24.0 → 1.26.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 +48 -24
- package/src/tools/files.js +737 -706
- package/src/ui/screen.js +14 -5
package/package.json
CHANGED
package/src/core/loop.js
CHANGED
|
@@ -435,13 +435,13 @@ function systemPrompt({ cwd, skills, mode, check, map, memory }) {
|
|
|
435
435
|
'',
|
|
436
436
|
'## How to work',
|
|
437
437
|
'',
|
|
438
|
-
'AN APP THAT IS AWKWARD TO USE IS NOT FINISHED. Before you call it done, look at',
|
|
439
|
-
'what you built as someone using it for the first time: is the button inside its',
|
|
440
|
-
'field or sitting on top of it, is there room to breathe between things, does the',
|
|
441
|
-
'empty state say anything, can every control be reached from the keyboard, does',
|
|
442
|
-
'it hold together at 360px wide. Controls that overlap or crowd each other are a',
|
|
443
|
-
'bug in the same way a crash is - fix it before you say a word about being done.',
|
|
444
|
-
'',
|
|
438
|
+
'AN APP THAT IS AWKWARD TO USE IS NOT FINISHED. Before you call it done, look at',
|
|
439
|
+
'what you built as someone using it for the first time: is the button inside its',
|
|
440
|
+
'field or sitting on top of it, is there room to breathe between things, does the',
|
|
441
|
+
'empty state say anything, can every control be reached from the keyboard, does',
|
|
442
|
+
'it hold together at 360px wide. Controls that overlap or crowd each other are a',
|
|
443
|
+
'bug in the same way a crash is - fix it before you say a word about being done.',
|
|
444
|
+
'',
|
|
445
445
|
'Before building anything, turn the request into a list of what it must do — every',
|
|
446
446
|
'feature named, and the ones any user would expect whether or not they were named',
|
|
447
447
|
'(an empty state, an error state, the keyboard doing the obvious thing, working on',
|
|
@@ -491,20 +491,20 @@ function systemPrompt({ cwd, skills, mode, check, map, memory }) {
|
|
|
491
491
|
'steps already show on screen, and repeating them in words buries the few',
|
|
492
492
|
'sentences worth reading.',
|
|
493
493
|
'',
|
|
494
|
-
'YOUR FIRST WORDS, BEFORE ANY TOOL CALL, EVERY TIME. Nothing else appears on',
|
|
495
|
-
'screen while you work, so if you say nothing the user watches a blank page.',
|
|
496
|
-
'Open with one line: I will build Tide for you - a tasks app in a single HTML',
|
|
497
|
-
'file. Then one line each time you start a new piece of the work: Now the',
|
|
498
|
-
'components. / Now making the filter row. / Onto the animations. Then one',
|
|
499
|
-
'line at the end saying it is done. Do not explain where the file is or how to',
|
|
500
|
-
'open it - they asked for it, they know where it went, and being told reads as',
|
|
501
|
-
'being talked down to.',
|
|
502
|
-
'',
|
|
503
|
-
'Those lines are the whole of what the user reads. They are not thinking out',
|
|
504
|
-
'loud: never "I need to", never "Let me", never "The user wants", never a plan',
|
|
505
|
-
'of which files you will touch. Say what you are doing, the way you would to',
|
|
506
|
-
'someone watching over your shoulder.',
|
|
507
|
-
'',
|
|
494
|
+
'YOUR FIRST WORDS, BEFORE ANY TOOL CALL, EVERY TIME. Nothing else appears on',
|
|
495
|
+
'screen while you work, so if you say nothing the user watches a blank page.',
|
|
496
|
+
'Open with one line: I will build Tide for you - a tasks app in a single HTML',
|
|
497
|
+
'file. Then one line each time you start a new piece of the work: Now the',
|
|
498
|
+
'components. / Now making the filter row. / Onto the animations. Then one',
|
|
499
|
+
'line at the end saying it is done. Do not explain where the file is or how to',
|
|
500
|
+
'open it - they asked for it, they know where it went, and being told reads as',
|
|
501
|
+
'being talked down to.',
|
|
502
|
+
'',
|
|
503
|
+
'Those lines are the whole of what the user reads. They are not thinking out',
|
|
504
|
+
'loud: never "I need to", never "Let me", never "The user wants", never a plan',
|
|
505
|
+
'of which files you will touch. Say what you are doing, the way you would to',
|
|
506
|
+
'someone watching over your shoulder.',
|
|
507
|
+
'',
|
|
508
508
|
|
|
509
509
|
'',
|
|
510
510
|
'Before you guess at an API, ask: type_of gives the exact signature from the',
|
|
@@ -1015,6 +1015,7 @@ export class Agent {
|
|
|
1015
1015
|
let argRetries = 0;
|
|
1016
1016
|
let continuations = 0;
|
|
1017
1017
|
let askedToVerify = false;
|
|
1018
|
+
let squeezed = false;
|
|
1018
1019
|
let askedToSpeak = false;
|
|
1019
1020
|
let fixRounds = 0;
|
|
1020
1021
|
this.failovers = 0;
|
|
@@ -1100,6 +1101,23 @@ export class Agent {
|
|
|
1100
1101
|
continue;
|
|
1101
1102
|
}
|
|
1102
1103
|
|
|
1104
|
+
// An oversized conversation is a recoverable thing, not a dead end.
|
|
1105
|
+
//
|
|
1106
|
+
// The provider rejects the request, ucode prints the error and the
|
|
1107
|
+
// half-built app stops there; typing "continue" sends the same
|
|
1108
|
+
// oversized conversation again and fails the same way. Folding it and
|
|
1109
|
+
// trying once is what the user would be told to do, so it happens
|
|
1110
|
+
// without asking.
|
|
1111
|
+
if (err.kind === 'bad_request' && !squeezed && !this.abort.signal.aborted) {
|
|
1112
|
+
squeezed = true;
|
|
1113
|
+
const before = this.working.length;
|
|
1114
|
+
await this.maybeFold({ force: true });
|
|
1115
|
+
if (this.working.length < before) {
|
|
1116
|
+
this.ui.note('the conversation had grown too large — folded it and carried on');
|
|
1117
|
+
continue;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1103
1121
|
// Busy, slow or down: move to the next model and carry on, rather
|
|
1104
1122
|
// than ending a half-built app with an error.
|
|
1105
1123
|
if (passing(err) && !this.abort.signal.aborted && (await this.failover(err))) continue;
|
|
@@ -1841,10 +1859,16 @@ export class Agent {
|
|
|
1841
1859
|
total.turns += 1;
|
|
1842
1860
|
}
|
|
1843
1861
|
|
|
1844
|
-
/**
|
|
1845
|
-
|
|
1862
|
+
/**
|
|
1863
|
+
* Fold older turns into a summary when the window gets tight.
|
|
1864
|
+
*
|
|
1865
|
+
* `force` is for when the provider has already said the conversation is too
|
|
1866
|
+
* large: its word beats our estimate of the same thing, and the estimate is
|
|
1867
|
+
* what let it get here.
|
|
1868
|
+
*/
|
|
1869
|
+
async maybeFold({ force = false } = {}) {
|
|
1846
1870
|
const limit = contextLimit();
|
|
1847
|
-
if (!tooBig(this.working, limit)) return;
|
|
1871
|
+
if (!force && !tooBig(this.working, limit)) return;
|
|
1848
1872
|
|
|
1849
1873
|
this.ui.startSpinner('context is filling up — summarizing earlier turns');
|
|
1850
1874
|
try {
|