agent-tank 0.9.9 → 0.9.10
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/agents/base.js +29 -14
- package/src/agents/pty-output-parser.js +14 -2
package/package.json
CHANGED
package/src/agents/base.js
CHANGED
|
@@ -134,14 +134,6 @@ class BaseAgent {
|
|
|
134
134
|
return;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
if (/rate.?limited|rate_limit_error/i.test(cleanOutput)) {
|
|
138
|
-
logger.agent(this.name, 'Rate limited, preserving last known usage data');
|
|
139
|
-
this.error = 'Rate limited — using cached data';
|
|
140
|
-
this.lastUpdated = new Date().toISOString();
|
|
141
|
-
// Don't overwrite this.usage — keep the last known good data
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
137
|
// Check for session/auth errors — preserve cached data if available
|
|
146
138
|
const sessionErrorMatch = cleanOutput.match(/session.?expired|session.?error|invalid.?session|authentication.?error|auth.?failed|Unable to (?:load|fetch)|Error loading|could not (?:load|fetch)|Failed to load usage|not authenticated|login required|sign.?in required/i);
|
|
147
139
|
if (sessionErrorMatch) {
|
|
@@ -152,12 +144,7 @@ class BaseAgent {
|
|
|
152
144
|
return;
|
|
153
145
|
}
|
|
154
146
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
// Only update usage if we got meaningful data (not all-null)
|
|
158
|
-
const hasData = parsed && Object.values(parsed).some(v => v !== null && v !== undefined && (typeof v !== 'object' || (Array.isArray(v) ? v.length > 0 : Object.keys(v).length > 0)));
|
|
159
|
-
if (hasData) { this.usage = parsed; this.lastUpdated = new Date().toISOString(); } else if (this.usage) { logger.agent(this.name, 'Parse returned no data, preserving last known usage'); this.error = 'Failed to parse — using cached data'; } else { this.usage = parsed; this.lastUpdated = new Date().toISOString(); }
|
|
160
|
-
logger.agent(this.name, 'Parsed usage:', logger.json(this.usage));
|
|
147
|
+
this._applyParsedUsage(this.parseOutput(output), cleanOutput);
|
|
161
148
|
} catch (err) {
|
|
162
149
|
if (this.isStopping() && err.message === 'Agent stopping') {
|
|
163
150
|
logger.agent(this.name, 'Refresh cancelled during shutdown');
|
|
@@ -171,6 +158,34 @@ class BaseAgent {
|
|
|
171
158
|
}
|
|
172
159
|
}
|
|
173
160
|
|
|
161
|
+
// Decide what to do with freshly parsed usage, given the raw (cleaned) output.
|
|
162
|
+
// Prefers fresh data; treats rate-limit notices as an error only when no
|
|
163
|
+
// usable data came back (a partial rate limit — e.g. Claude's per-model /
|
|
164
|
+
// Sonnet breakdown — still yields session/weekly data, and the rate-limited
|
|
165
|
+
// section simply parses to null and is omitted by the formatter).
|
|
166
|
+
_applyParsedUsage(parsed, cleanOutput) {
|
|
167
|
+
const hasData = parsed && Object.values(parsed).some(v =>
|
|
168
|
+
v !== null && v !== undefined &&
|
|
169
|
+
(typeof v !== 'object' || (Array.isArray(v) ? v.length > 0 : Object.keys(v).length > 0)));
|
|
170
|
+
|
|
171
|
+
if (hasData) {
|
|
172
|
+
this.usage = parsed;
|
|
173
|
+
this.lastUpdated = new Date().toISOString();
|
|
174
|
+
} else if (/rate.?limited|rate_limit_error/i.test(cleanOutput)) {
|
|
175
|
+
logger.agent(this.name, 'Rate limited with no usable data, preserving last known usage');
|
|
176
|
+
this.error = this.usage ? 'Rate limited — using cached data' : 'Rate limited';
|
|
177
|
+
this.lastUpdated = new Date().toISOString();
|
|
178
|
+
return;
|
|
179
|
+
} else if (this.usage) {
|
|
180
|
+
logger.agent(this.name, 'Parse returned no data, preserving last known usage');
|
|
181
|
+
this.error = 'Failed to parse — using cached data';
|
|
182
|
+
} else {
|
|
183
|
+
this.usage = parsed;
|
|
184
|
+
this.lastUpdated = new Date().toISOString();
|
|
185
|
+
}
|
|
186
|
+
logger.agent(this.name, 'Parsed usage:', logger.json(this.usage));
|
|
187
|
+
}
|
|
188
|
+
|
|
174
189
|
async runCommand() {
|
|
175
190
|
if (this.isStopping()) {
|
|
176
191
|
throw this._createStopError();
|
|
@@ -250,8 +250,20 @@ function addPaceData(sectionData, cycleType) {
|
|
|
250
250
|
function parsePtyOutput(clean) {
|
|
251
251
|
const usage = { session: null, weeklyAll: null, weeklySonnet: null };
|
|
252
252
|
|
|
253
|
-
// Parse session
|
|
254
|
-
|
|
253
|
+
// Parse session. The "Current session" label is frequently corrupted while
|
|
254
|
+
// Claude's /usage dialog is still rendering (e.g. "Curretsession"), even
|
|
255
|
+
// though the bar, "N% used", and reset time are intact. When the labeled
|
|
256
|
+
// extraction fails, fall back to the region before the weekly section — the
|
|
257
|
+
// session block is the only "N% used" that appears there.
|
|
258
|
+
let sessionData = parseUsageSection(extractSection(clean, 'Current\\s*session', 'Current\\s*week'));
|
|
259
|
+
if (!sessionData) {
|
|
260
|
+
const beforeWeekly = clean.split(/Current\s*week/i);
|
|
261
|
+
// length > 1 confirms the weekly section exists, i.e. this is real /usage
|
|
262
|
+
// output and beforeWeekly[0] is the session region (not unrelated text).
|
|
263
|
+
if (beforeWeekly.length > 1) {
|
|
264
|
+
sessionData = parseUsageSection(beforeWeekly[0]);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
255
267
|
if (sessionData) {
|
|
256
268
|
usage.session = { label: 'Current session', ...sessionData };
|
|
257
269
|
addPaceData(usage.session, 'session');
|