zames_pro 2.49.0 → 2.49.2
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/dist/agent-loop.js +22 -2
- package/dist/i18n.js +4 -0
- package/dist/input.js +68 -12
- package/package.json +1 -1
package/dist/agent-loop.js
CHANGED
|
@@ -201,6 +201,12 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
201
201
|
// the (fresh) chat grows past this plus a margin, so a chat that starts
|
|
202
202
|
// above the threshold does not compact on every tool call.
|
|
203
203
|
let lastAutoCompactTokens = -1;
|
|
204
|
+
// Set when an auto-compact returned the SAME chat id it started in — i.e.
|
|
205
|
+
// the "fresh chat" never opened and the compaction did nothing. Without this
|
|
206
|
+
// guard a broken newChat() (see B2) made the loop compact on EVERY tool call
|
|
207
|
+
// while the context kept growing. Defense in depth: the root cause is fixed,
|
|
208
|
+
// but a future regression must not turn into an endless "compacting" loop.
|
|
209
|
+
let autoCompactDisabled = false;
|
|
204
210
|
// The message of a respond that arrived TOGETHER with real tool calls.
|
|
205
211
|
// It is not delivered immediately (the tools must run first), but if the
|
|
206
212
|
// model then stops without calling respond again, this is the best final
|
|
@@ -735,7 +741,7 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
735
741
|
// (plus a small margin), so a fresh chat does not compact again on
|
|
736
742
|
// every tool call.
|
|
737
743
|
const armed = !firedRecently || tokens > lastAutoCompactTokens + 1;
|
|
738
|
-
if (pct >= autoCompactPct && armed) {
|
|
744
|
+
if (pct >= autoCompactPct && armed && !autoCompactDisabled) {
|
|
739
745
|
lastAutoCompactTokens = tokens;
|
|
740
746
|
safeWarning(translate(locale)('compact.auto_trigger', {
|
|
741
747
|
pct: String(Math.round(pct)),
|
|
@@ -743,9 +749,23 @@ export async function runAgentLoop({ browser, tools, task, workdir, maxIteration
|
|
|
743
749
|
}));
|
|
744
750
|
transcript?.log('auto_compact_trigger', { tokens, pct });
|
|
745
751
|
try {
|
|
752
|
+
const beforeChat = await browser
|
|
753
|
+
.getCurrentChatId()
|
|
754
|
+
.catch(() => null);
|
|
746
755
|
const newChat = await onAutoCompact();
|
|
747
756
|
if (newChat) {
|
|
748
|
-
|
|
757
|
+
if (beforeChat && newChat === beforeChat) {
|
|
758
|
+
// The chat did NOT change: the summary was posted back into
|
|
759
|
+
// the old chat and the context was not reset. Warn once and
|
|
760
|
+
// stop auto-compacting for the rest of the task instead of
|
|
761
|
+
// looping on every tool call.
|
|
762
|
+
autoCompactDisabled = true;
|
|
763
|
+
safeWarning(translate(locale)('compact.auto_same_chat'));
|
|
764
|
+
transcript?.log('auto_compact_same_chat', { chatId: newChat });
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
transcript?.log('auto_compact_done', { chatId: newChat });
|
|
768
|
+
}
|
|
749
769
|
// Continue in the fresh chat. The next send is a tool-result
|
|
750
770
|
// (agent: true), which is fine: the new chat already holds the
|
|
751
771
|
// system prompt + carryover. `lastAutoCompactTokens` stays at the
|
package/dist/i18n.js
CHANGED
|
@@ -289,6 +289,10 @@ const CATALOG = {
|
|
|
289
289
|
ru: '🗜️ Контекст заполнен на {pct}% ({tokens} токенов) — сжимаю историю и открываю новый чат...',
|
|
290
290
|
en: '🗜️ Context at {pct}% ({tokens} tokens) — compacting the history and opening a fresh chat...',
|
|
291
291
|
},
|
|
292
|
+
'compact.auto_same_chat': {
|
|
293
|
+
ru: '🗜️ Сжатие не открыло новый чат (тот же id) — отключаю авто-сжатие до конца задачи, чтобы не зациклиться.',
|
|
294
|
+
en: '🗜️ Compaction did not open a fresh chat (same id) — disabling auto-compact for the rest of the task to avoid a loop.',
|
|
295
|
+
},
|
|
292
296
|
'compact.start': {
|
|
293
297
|
ru: '🗜️ Сжимаю историю чата (DeepSeek)...',
|
|
294
298
|
en: '🗜️ Compacting the chat history (DeepSeek)...',
|
package/dist/input.js
CHANGED
|
@@ -93,7 +93,12 @@ export function visRows(s, cols) {
|
|
|
93
93
|
const len = visLen(s);
|
|
94
94
|
return Math.max(1, Math.ceil(len / width));
|
|
95
95
|
}
|
|
96
|
-
// Visible length of a line without ANSI sequences.
|
|
96
|
+
// Visible length of a line without ANSI sequences. WIDE characters (emoji,
|
|
97
|
+
// CJK) count as 2 columns — a plain code-point count made the status-line
|
|
98
|
+
// arithmetic (right-align, wrapping, block erase) disagree with the real
|
|
99
|
+
// screen, so a status containing an emoji/CJK could wrap past the edge and
|
|
100
|
+
// make the block erase miss (status "stacking"). Combining marks and the
|
|
101
|
+
// zero-width joiner/space/variation selectors count as 0.
|
|
97
102
|
export function visLen(s) {
|
|
98
103
|
s = String(s);
|
|
99
104
|
let n = 0;
|
|
@@ -109,11 +114,48 @@ export function visLen(s) {
|
|
|
109
114
|
}
|
|
110
115
|
continue;
|
|
111
116
|
}
|
|
112
|
-
|
|
113
|
-
|
|
117
|
+
const cp = s.codePointAt(i);
|
|
118
|
+
n += charWidth(cp);
|
|
119
|
+
i += cp > 0xffff ? 2 : 1;
|
|
114
120
|
}
|
|
115
121
|
return n;
|
|
116
122
|
}
|
|
123
|
+
// Display width of one code point in columns (0, 1 or 2). Based on the
|
|
124
|
+
// conventional wcwidth ranges — good enough for terminal layout, and it makes
|
|
125
|
+
// the emoji used in the status line (🧠🌐) count as 2, while math symbols like
|
|
126
|
+
// ⧗ (U+29D7) stay 1, matching a real terminal.
|
|
127
|
+
export function charWidth(cp) {
|
|
128
|
+
// Zero width: combining marks, ZWJ/ZWNJ, variation selectors.
|
|
129
|
+
if (cp === 0x200b ||
|
|
130
|
+
cp === 0x200c ||
|
|
131
|
+
cp === 0x200d ||
|
|
132
|
+
(cp >= 0x0300 && cp <= 0x036f) ||
|
|
133
|
+
(cp >= 0x1ab0 && cp <= 0x1aff) ||
|
|
134
|
+
(cp >= 0x1dc0 && cp <= 0x1dff) ||
|
|
135
|
+
(cp >= 0x20d0 && cp <= 0x20ff) ||
|
|
136
|
+
(cp >= 0xfe00 && cp <= 0xfe0f) ||
|
|
137
|
+
(cp >= 0xfe20 && cp <= 0xfe2f)) {
|
|
138
|
+
return 0;
|
|
139
|
+
}
|
|
140
|
+
// Wide: CJK, Hangul, fullwidth forms, emoji.
|
|
141
|
+
if ((cp >= 0x1100 && cp <= 0x115f) ||
|
|
142
|
+
(cp >= 0x2e80 && cp <= 0x303e) ||
|
|
143
|
+
(cp >= 0x3041 && cp <= 0x33ff) ||
|
|
144
|
+
(cp >= 0x3400 && cp <= 0x4dbf) ||
|
|
145
|
+
(cp >= 0x4e00 && cp <= 0x9fff) ||
|
|
146
|
+
(cp >= 0xa000 && cp <= 0xa4cf) ||
|
|
147
|
+
(cp >= 0xac00 && cp <= 0xd7a3) ||
|
|
148
|
+
(cp >= 0xf900 && cp <= 0xfaff) ||
|
|
149
|
+
(cp >= 0xfe30 && cp <= 0xfe4f) ||
|
|
150
|
+
(cp >= 0xff00 && cp <= 0xff60) ||
|
|
151
|
+
(cp >= 0xffe0 && cp <= 0xffe6) ||
|
|
152
|
+
(cp >= 0x1f000 && cp <= 0x1f02f) ||
|
|
153
|
+
(cp >= 0x1f300 && cp <= 0x1faff) ||
|
|
154
|
+
(cp >= 0x20000 && cp <= 0x3fffd)) {
|
|
155
|
+
return 2;
|
|
156
|
+
}
|
|
157
|
+
return 1;
|
|
158
|
+
}
|
|
117
159
|
export function layoutInput(promptStr, buf, cursor, cols) {
|
|
118
160
|
const width = Math.max(20, Number(cols) || 80);
|
|
119
161
|
const promptW = visLen(promptStr);
|
|
@@ -128,21 +170,29 @@ export function layoutInput(promptStr, buf, cursor, cols) {
|
|
|
128
170
|
const avail = Math.max(1, width - promptW);
|
|
129
171
|
const start = i;
|
|
130
172
|
// Build the next visual line. First we take as many
|
|
131
|
-
// characters as fit (
|
|
173
|
+
// characters as fit (columns < avail). If we hit the width
|
|
132
174
|
// and the next character is not the end of the line, we roll back to the
|
|
133
175
|
// last space so we don't split a word in the middle (word-wrap).
|
|
176
|
+
// Wrapping and the cursor column are measured in COLUMNS (charWidth),
|
|
177
|
+
// not code points — otherwise a CJK/emoji input would overflow the row
|
|
178
|
+
// and put the cursor on the wrong cell.
|
|
134
179
|
let text = '';
|
|
135
|
-
let
|
|
136
|
-
let
|
|
137
|
-
|
|
180
|
+
let widthUsed = 0;
|
|
181
|
+
let charIdx = 0;
|
|
182
|
+
let lastSpace = -1; // char index of the space within text
|
|
183
|
+
while (i < chars.length && chars[i] !== NL) {
|
|
184
|
+
const w = charWidth(chars[i].codePointAt(0));
|
|
185
|
+
if (widthUsed + w > avail)
|
|
186
|
+
break;
|
|
138
187
|
if (chars[i] === ' ')
|
|
139
|
-
lastSpace =
|
|
188
|
+
lastSpace = charIdx;
|
|
140
189
|
text += chars[i];
|
|
141
190
|
i++;
|
|
142
|
-
|
|
191
|
+
charIdx++;
|
|
192
|
+
widthUsed += w;
|
|
143
193
|
}
|
|
144
194
|
const atLineEnd = i >= chars.length || chars[i] === NL;
|
|
145
|
-
if (!atLineEnd &&
|
|
195
|
+
if (!atLineEnd && widthUsed >= avail && lastSpace > 0) {
|
|
146
196
|
// Move the "tail" of the line to the next visual line.
|
|
147
197
|
const textChars = Array.from(text);
|
|
148
198
|
const tailLen = textChars.length - lastSpace;
|
|
@@ -162,7 +212,8 @@ export function layoutInput(promptStr, buf, cursor, cols) {
|
|
|
162
212
|
let cursorCol = promptW;
|
|
163
213
|
for (let r = 0; r < rows.length; r++) {
|
|
164
214
|
const row = rows[r];
|
|
165
|
-
const
|
|
215
|
+
const rowChars = Array.from(row.text);
|
|
216
|
+
const len = rowChars.length;
|
|
166
217
|
const from = row.start;
|
|
167
218
|
const to = row.start + len;
|
|
168
219
|
if (cur >= from && cur <= to) {
|
|
@@ -170,7 +221,12 @@ export function layoutInput(promptStr, buf, cursor, cols) {
|
|
|
170
221
|
if (cur === to && next && next.start === to)
|
|
171
222
|
continue;
|
|
172
223
|
cursorRow = r;
|
|
173
|
-
|
|
224
|
+
// Cursor column in COLUMNS (wide chars count as 2).
|
|
225
|
+
let w = 0;
|
|
226
|
+
for (let k = 0; k < cur - from; k++) {
|
|
227
|
+
w += charWidth(rowChars[k].codePointAt(0));
|
|
228
|
+
}
|
|
229
|
+
cursorCol = promptW + w;
|
|
174
230
|
break;
|
|
175
231
|
}
|
|
176
232
|
}
|