storyboard-bridge 0.9.0 → 0.9.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/tryinfer_client.py +19 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "storyboard-bridge",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "Desktop bridge that powers a hosted Storyboard AI webapp with your own local Claude Code / Gemini CLI login (no API key).",
5
5
  "type": "module",
6
6
  "bin": {
@@ -188,18 +188,23 @@ class BrowserSession:
188
188
  tid, url = self._resolve_tab()
189
189
  if not tid:
190
190
  raise RuntimeError(f"No open tab whose URL contains '{self.match}'. Open tryinfer.com and log in.")
191
- # A HOST tab left in the background gets DISCARDED/frozen by Chrome (no live renderer). Attaching still
192
- # works, but Runtime.enable then hangs waiting for a renderer → "Timed out waiting for CDP response".
193
- # Activate (foreground/wake) the tab first, and retry attach+enable a couple times so a just-woken tab
194
- # gets a moment to spin its renderer back up.
191
+ # A HOST tab left in the background CAN get discarded/frozen/throttled by Chrome (no live renderer),
192
+ # in which case attaching works but Runtime.enable hangs waiting for a renderer → CDP timeout.
193
+ # We DON'T foreground on the happy path (activateTarget steals focus, which is annoying in a browser
194
+ # the user is actively using). Instead attempt 0 attaches WITHOUT foregrounding, with a short
195
+ # Runtime.enable timeout so a genuinely stalled tab fails fast; only THEN do later attempts fall back
196
+ # to activateTarget (foreground/wake) to spin the renderer back up.
195
197
  last = None
196
198
  for attempt in range(3):
197
199
  self.cdp = CDP(self.browser_ws)
198
200
  try:
199
- try: self.cdp.call("Target.activateTarget", {"targetId": tid}, timeout=10) # wake a discarded tab
200
- except Exception: pass
201
+ if attempt > 0:
202
+ try: self.cdp.call("Target.activateTarget", {"targetId": tid}, timeout=10) # wake a stalled tab
203
+ except Exception: pass
201
204
  self.session_id = self.cdp.call("Target.attachToTarget", {"targetId": tid, "flatten": True}, timeout=15)["sessionId"]
202
- self.cdp.call("Runtime.enable", session_id=self.session_id, timeout=20)
205
+ # short timeout on the no-focus first pass → fail fast into the activate() fallback if the
206
+ # renderer is asleep; full timeout once we've foregrounded it.
207
+ self.cdp.call("Runtime.enable", session_id=self.session_id, timeout=(6 if attempt == 0 else 20))
203
208
  log(f"Routing API calls through tab: {url}")
204
209
  return
205
210
  except Exception as e:
@@ -207,7 +212,7 @@ class BrowserSession:
207
212
  try: self.cdp.close()
208
213
  except Exception: pass
209
214
  if attempt < 2:
210
- log(f" CDP attach stalled (tab may be waking) — retrying… ({e})")
215
+ log(f" CDP attach stalled (waking tab in foreground) — retrying… ({e})")
211
216
  time.sleep(2)
212
217
  raise RuntimeError(f"couldn't attach to the tryinfer tab — is it awake + logged in? ({last})")
213
218
 
@@ -295,6 +300,12 @@ def submit(session, prompt, image_urls, duration, aspect, resolution, audio,
295
300
  "group": {"groupId": str(uuid.uuid4()), "position": 0, "meta": meta}}
296
301
  r = session.request("POST", f"{API}/create/generation-tasks", body=body)
297
302
  if r.status_code not in (200, 201, 202):
303
+ # tryinfer allows ONE generation at a time per account. A 429 here means this worker's account is
304
+ # already busy — often with something started outside this app (their web UI, another tool). That is
305
+ # not a failure of the render: mark it distinctly so the backend can release the worker, cool it
306
+ # down and requeue onto another one, instead of failing the job.
307
+ if r.status_code == 429 and "create_generation_in_progress" in (r.text or ""):
308
+ raise RuntimeError(f"WORKER_BUSY: account already has a generation running ({r.text[:200]})")
298
309
  raise RuntimeError(f"submit failed ({r.status_code}): {r.text[:800]}")
299
310
  tid = r.json().get("id")
300
311
  if not tid: