storyboard-bridge 0.9.49 → 0.9.51
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/index.mjs +29 -2
- package/newface_client.py +6 -1
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -149,14 +149,41 @@ function runCli(bin, args, stdinInput, cwd) {
|
|
|
149
149
|
// Surface the STDOUT content, not just its length: claude-code prints its real failure there (usage/rate
|
|
150
150
|
// limit, model overload after retries, a refusal, an error JSON) — often with stderr EMPTY. Without this,
|
|
151
151
|
// "produced 1107b stdout" hid the actual reason. Show both so the failure is diagnosable from the app.
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
//
|
|
153
|
+
// When that stdout IS the CLI's json envelope, read the diagnosis out of it instead of printing the
|
|
154
|
+
// first 700 raw bytes. Those bytes are mostly token counters — an observed failure spent its whole
|
|
155
|
+
// budget on `duration_api_ms`, `usage`, `cache_creation` and friends and cut off before `result`,
|
|
156
|
+
// the one field carrying the human sentence. terminal_reason:"api_error" with zero tokens and zero
|
|
157
|
+
// cost means the API refused the request before any inference: an expired login or a usage limit,
|
|
158
|
+
// not anything this bridge or the prompt did.
|
|
159
|
+
reject(new Error(`${bin} ${how} after ${secs}s — ${describeCliOutput(out)}; stderr: ${err.slice(0, 300).trim() || '(empty)'}`));
|
|
154
160
|
});
|
|
155
161
|
// Feed the prompt via STDIN (not argv) — see runJob for why this matters on Windows.
|
|
156
162
|
if (stdinInput != null) child.stdin.write(stdinInput);
|
|
157
163
|
child.stdin.end();
|
|
158
164
|
});
|
|
159
165
|
}
|
|
166
|
+
/** The diagnosis inside a CLI json envelope, or the raw head when it is not one. */
|
|
167
|
+
export function describeCliOutput(out) {
|
|
168
|
+
const raw = String(out ?? '');
|
|
169
|
+
let o;
|
|
170
|
+
try { o = JSON.parse(raw); } catch { o = null; }
|
|
171
|
+
if (!o || typeof o !== 'object') return `stdout(${raw.length}b): ${raw.slice(0, 700).trim() || '(empty)'}`;
|
|
172
|
+
const parts = [];
|
|
173
|
+
// the human sentence first — it is the only field that ever says WHY
|
|
174
|
+
for (const k of ['result', 'error', 'message']) {
|
|
175
|
+
const v = o[k];
|
|
176
|
+
if (typeof v === 'string' && v.trim()) { parts.push(v.trim().slice(0, 400)); break; }
|
|
177
|
+
if (v && typeof v === 'object') { parts.push(JSON.stringify(v).slice(0, 400)); break; }
|
|
178
|
+
}
|
|
179
|
+
for (const k of ['subtype', 'terminal_reason', 'stop_reason']) {
|
|
180
|
+
if (typeof o[k] === 'string' && o[k]) parts.push(`${k}=${o[k]}`);
|
|
181
|
+
}
|
|
182
|
+
const inTok = o.usage?.input_tokens ?? null, outTok = o.usage?.output_tokens ?? null;
|
|
183
|
+
if (inTok === 0 && outTok === 0) parts.push('0 tokens billed — the API refused the request before inference (expired login or usage limit)');
|
|
184
|
+
return parts.length ? parts.join(' · ') : `stdout(${raw.length}b): ${raw.slice(0, 700).trim()}`;
|
|
185
|
+
}
|
|
186
|
+
|
|
160
187
|
// claude wraps the answer as { result }, gemini as { response }; read either, else raw stdout.
|
|
161
188
|
function extractText(stdout) {
|
|
162
189
|
try {
|
package/newface_client.py
CHANGED
|
@@ -311,7 +311,12 @@ def poll(session, mids, timeout=1800, interval=5, prefix=()):
|
|
|
311
311
|
else:
|
|
312
312
|
pend += 1
|
|
313
313
|
pct = int(sum(int((content.get(m) or {}).get("progress") or 0) for m in mids) / max(1, len(mids)))
|
|
314
|
-
key
|
|
314
|
+
# The dedupe key MUST include elapsed time. The hub gives a render 30 minutes and refreshes that
|
|
315
|
+
# window on every progress event, so a key of only "done:pct" stops emitting the moment a batch
|
|
316
|
+
# plateaus — and a slow batch sitting at 0/15 · 0% therefore starved the heartbeat and was killed as
|
|
317
|
+
# "newface render timed out" while it was still legitimately rendering. creaa_client already carries
|
|
318
|
+
# a per-minute component for exactly this reason; this is the same bug, one provider later.
|
|
319
|
+
key = f"{len(done)}:{pct}:{int(time.time() - (end - timeout)) // 60}"
|
|
315
320
|
if key != last_key:
|
|
316
321
|
last_key = key
|
|
317
322
|
# Ship the urls of everything finished SO FAR, not just a count. A batch finishes at wildly
|
package/package.json
CHANGED