ucode-agent 1.61.1 → 1.62.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/README.md +3 -0
- package/package.json +1 -1
- package/src/core/loop.js +3 -1
- package/src/core/provider.js +11 -1
package/README.md
CHANGED
|
@@ -96,6 +96,9 @@ Served by Google (aistudio.google.com), free with a key.
|
|
|
96
96
|
|
|
97
97
|
`/model` shows them and switches. `ucode -m gemini-3.5-flash` starts on one.
|
|
98
98
|
|
|
99
|
+
When Google is overloaded and Flash-Lite stops answering, ucode carries on with
|
|
100
|
+
3.5 Flash by itself and goes back to Flash-Lite a few minutes later.
|
|
101
|
+
|
|
99
102
|
## What it does
|
|
100
103
|
|
|
101
104
|
**Twenty-one tools.** `create_app`, `read_file`, `read_files`, `write_file`,
|
package/package.json
CHANGED
package/src/core/loop.js
CHANGED
|
@@ -27,7 +27,7 @@ import { spawn } from 'node:child_process';
|
|
|
27
27
|
|
|
28
28
|
import {
|
|
29
29
|
ask, model, setModel, modelName, modelList, contextLimit, rateLimits,
|
|
30
|
-
estimateConversation, MODELS, DEFAULT_MODEL, PROVIDER, fallbackFor,
|
|
30
|
+
estimateConversation, MODELS, DEFAULT_MODEL, PROVIDER, fallbackFor, backupFor,
|
|
31
31
|
} from './provider.js';
|
|
32
32
|
import {
|
|
33
33
|
tools, runTool, describe, setRoot, setConfirm, setRequest,
|
|
@@ -2095,6 +2095,8 @@ export class Agent {
|
|
|
2095
2095
|
if (++this.failovers > MAX_FAILOVERS) return false;
|
|
2096
2096
|
const from = model();
|
|
2097
2097
|
let next = fallbackFor(from, this.tried);
|
|
2098
|
+
const backup = err.kind !== 'rate_limit' && backupFor(from);
|
|
2099
|
+
if (!next && backup && !this.tried?.has(backup)) next = backup;
|
|
2098
2100
|
|
|
2099
2101
|
const why = err.kind === 'rate_limit' ? 'busy' : err.kind === 'timeout' ? 'too slow to answer' : 'not answering';
|
|
2100
2102
|
|
package/src/core/provider.js
CHANGED
|
@@ -104,6 +104,15 @@ export function fallbackFor(id, tried = new Set()) {
|
|
|
104
104
|
return null;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Where a Flash-Lite model goes when Google is overloaded (503) or it freezes.
|
|
109
|
+
* Unlike fallbackFor this is on by default: both Lite models go down together
|
|
110
|
+
* at peak hours while Flash keeps answering, and a build that waits on them
|
|
111
|
+
* can wait for hours. UCODE_BACKUP=0 turns it off.
|
|
112
|
+
*/
|
|
113
|
+
export const backupFor = (id) =>
|
|
114
|
+
/flash-lite/.test(id) && process.env.UCODE_BACKUP !== '0' ? 'gemini-3.5-flash' : null;
|
|
115
|
+
|
|
107
116
|
/** Seconds to wait on successive rate limits that come with no retry-after. */
|
|
108
117
|
const RATE_LIMIT_BACKOFF = [5, 10, 20];
|
|
109
118
|
|
|
@@ -711,7 +720,7 @@ export async function ask(messages, tools = [], opts = {}) {
|
|
|
711
720
|
kind: 'stalled',
|
|
712
721
|
attempted: `asking ${modelName(id)} for a reply`,
|
|
713
722
|
failed: `${modelName(id)} froze ${MAX_STALLS} times in a row — it took the request and then sent nothing.`,
|
|
714
|
-
fix: '
|
|
723
|
+
fix: 'Google is struggling with it right now. Run /model and pick another one.',
|
|
715
724
|
cause: problem,
|
|
716
725
|
});
|
|
717
726
|
}
|
|
@@ -741,6 +750,7 @@ export async function ask(messages, tools = [], opts = {}) {
|
|
|
741
750
|
if (!worthRetrying || attempt === attempts || opts.signal?.aborted) break;
|
|
742
751
|
if (printed > 0) break; // half an answer is on screen; do not print it twice
|
|
743
752
|
if (problem.detail?.handed) break; // its first tool calls are already running
|
|
753
|
+
if (problem.kind === 'timeout' && backupFor(id)) break; // one freeze is enough: the loop moves to the backup
|
|
744
754
|
|
|
745
755
|
// A stalled provider needs longer to come back than a dropped socket
|
|
746
756
|
// does, and the wait is narrated so a slow turn never looks like a hang.
|