@synkro-sh/cli 1.3.26 → 1.3.27
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/bootstrap.js +54 -19
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -1677,7 +1677,7 @@ Commands:
|
|
|
1677
1677
|
status - print "running"/"stopped"
|
|
1678
1678
|
"""
|
|
1679
1679
|
|
|
1680
|
-
import os, sys, json, socket, time, signal, fcntl, re
|
|
1680
|
+
import os, sys, json, socket, time, signal, fcntl, re, select
|
|
1681
1681
|
import subprocess, threading
|
|
1682
1682
|
from pathlib import Path
|
|
1683
1683
|
|
|
@@ -1707,27 +1707,49 @@ def log(msg):
|
|
|
1707
1707
|
pass
|
|
1708
1708
|
|
|
1709
1709
|
|
|
1710
|
+
STALL_TIMEOUT_SEC = int(os.environ.get("SYNKRO_DAEMON_STALL_TIMEOUT", "10"))
|
|
1711
|
+
|
|
1710
1712
|
def _read_response(proc, timeout=45):
|
|
1711
1713
|
acc = []
|
|
1712
1714
|
deadline = time.time() + timeout
|
|
1715
|
+
last_data = time.time()
|
|
1716
|
+
fd = proc.stdout.fileno()
|
|
1717
|
+
buf = ""
|
|
1713
1718
|
while True:
|
|
1714
|
-
|
|
1719
|
+
remaining = deadline - time.time()
|
|
1720
|
+
if remaining <= 0:
|
|
1715
1721
|
log("read timeout")
|
|
1716
1722
|
return ""
|
|
1717
|
-
|
|
1718
|
-
|
|
1723
|
+
if time.time() - last_data > STALL_TIMEOUT_SEC:
|
|
1724
|
+
log(f"stall timeout: no data for {STALL_TIMEOUT_SEC}s")
|
|
1719
1725
|
return ""
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1726
|
+
ready, _, _ = select.select([fd], [], [], min(remaining, 2.0))
|
|
1727
|
+
if not ready:
|
|
1728
|
+
if proc.poll() is not None:
|
|
1729
|
+
log("process exited during read")
|
|
1730
|
+
return ""
|
|
1723
1731
|
continue
|
|
1724
|
-
|
|
1725
|
-
if
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1732
|
+
chunk = os.read(fd, 65536)
|
|
1733
|
+
if not chunk:
|
|
1734
|
+
return ""
|
|
1735
|
+
last_data = time.time()
|
|
1736
|
+
buf += chunk.decode("utf-8", errors="replace")
|
|
1737
|
+
while "\\n" in buf:
|
|
1738
|
+
line, buf = buf.split("\\n", 1)
|
|
1739
|
+
line = line.strip()
|
|
1740
|
+
if not line:
|
|
1741
|
+
continue
|
|
1742
|
+
try:
|
|
1743
|
+
obj = json.loads(line)
|
|
1744
|
+
except json.JSONDecodeError:
|
|
1745
|
+
continue
|
|
1746
|
+
t = obj.get("type")
|
|
1747
|
+
if t == "assistant":
|
|
1748
|
+
for c in obj.get("message", {}).get("content", []):
|
|
1749
|
+
if c.get("type") == "text":
|
|
1750
|
+
acc.append(c["text"])
|
|
1751
|
+
elif t == "result":
|
|
1752
|
+
return "".join(acc)
|
|
1731
1753
|
|
|
1732
1754
|
|
|
1733
1755
|
def _send_msg(proc, text):
|
|
@@ -1757,6 +1779,7 @@ class WarmGrader:
|
|
|
1757
1779
|
self._warm_thread = None
|
|
1758
1780
|
self._lock = threading.Lock()
|
|
1759
1781
|
self._total_grades = 0
|
|
1782
|
+
self._prewarm_ok = True
|
|
1760
1783
|
self._start_prewarm()
|
|
1761
1784
|
|
|
1762
1785
|
def _make_proc(self):
|
|
@@ -1786,27 +1809,32 @@ class WarmGrader:
|
|
|
1786
1809
|
log("pre-warming process")
|
|
1787
1810
|
proc = self._make_proc()
|
|
1788
1811
|
_send_msg(proc, "Ready")
|
|
1789
|
-
resp = _read_response(proc, timeout=
|
|
1812
|
+
resp = _read_response(proc, timeout=15)
|
|
1790
1813
|
if resp:
|
|
1791
1814
|
with self._lock:
|
|
1792
1815
|
old = self._warm_proc
|
|
1793
1816
|
self._warm_proc = proc
|
|
1817
|
+
self._prewarm_ok = True
|
|
1794
1818
|
if old:
|
|
1795
1819
|
self._kill_proc(old)
|
|
1796
1820
|
log(f"pre-warm ready ({len(resp)} chars)")
|
|
1797
1821
|
else:
|
|
1798
1822
|
log("pre-warm response empty")
|
|
1799
1823
|
self._kill_proc(proc)
|
|
1824
|
+
self._prewarm_ok = False
|
|
1800
1825
|
except Exception as e:
|
|
1801
1826
|
log(f"pre-warm failed: {e}")
|
|
1827
|
+
self._prewarm_ok = False
|
|
1802
1828
|
|
|
1803
1829
|
def _start_prewarm(self):
|
|
1804
1830
|
self._warm_thread = threading.Thread(target=self._prewarm, daemon=True)
|
|
1805
1831
|
self._warm_thread.start()
|
|
1806
1832
|
|
|
1807
1833
|
def grade(self, prompt):
|
|
1808
|
-
if self._warm_thread:
|
|
1809
|
-
self._warm_thread.join(timeout=
|
|
1834
|
+
if self._warm_thread and self._prewarm_ok:
|
|
1835
|
+
self._warm_thread.join(timeout=8)
|
|
1836
|
+
elif self._warm_thread and not self._prewarm_ok:
|
|
1837
|
+
log("skipping prewarm join (last prewarm failed)")
|
|
1810
1838
|
|
|
1811
1839
|
with self._lock:
|
|
1812
1840
|
proc = self._warm_proc
|
|
@@ -1817,11 +1845,17 @@ class WarmGrader:
|
|
|
1817
1845
|
log("no warm process, cold fallback")
|
|
1818
1846
|
proc = self._make_proc()
|
|
1819
1847
|
warm = False
|
|
1848
|
+
elif proc.stdin.closed:
|
|
1849
|
+
log("warm process stdin closed, cold fallback")
|
|
1850
|
+
self._kill_proc(proc)
|
|
1851
|
+
proc = self._make_proc()
|
|
1852
|
+
warm = False
|
|
1820
1853
|
|
|
1854
|
+
wall_limit = int(os.environ.get("SYNKRO_DAEMON_WALL_TIMEOUT", "12"))
|
|
1821
1855
|
t0 = time.time()
|
|
1822
1856
|
try:
|
|
1823
1857
|
_send_msg(proc, prompt)
|
|
1824
|
-
resp = _read_response(proc, timeout=GRADE_TIMEOUT_SEC)
|
|
1858
|
+
resp = _read_response(proc, timeout=min(GRADE_TIMEOUT_SEC, wall_limit))
|
|
1825
1859
|
except Exception as e:
|
|
1826
1860
|
log(f"grade error: {e}")
|
|
1827
1861
|
resp = ""
|
|
@@ -2448,6 +2482,7 @@ async function callApi(method, endpoint, body) {
|
|
|
2448
2482
|
throw new Error("API URL not configured. Run `synkro install` first.");
|
|
2449
2483
|
}
|
|
2450
2484
|
const url = `${API_URL}${endpoint}`;
|
|
2485
|
+
await ensureValidToken();
|
|
2451
2486
|
const accessToken = getAccessToken();
|
|
2452
2487
|
const headers = {
|
|
2453
2488
|
"Content-Type": "application/json"
|
|
@@ -3333,7 +3368,7 @@ function writeConfigEnv(opts) {
|
|
|
3333
3368
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
3334
3369
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
3335
3370
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
3336
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.3.
|
|
3371
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.3.27")}`
|
|
3337
3372
|
];
|
|
3338
3373
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
3339
3374
|
if (safeOrgId) lines.push(`SYNKRO_ORG_ID=${shellQuoteSingle(safeOrgId)}`);
|