feat: browser access (allowed_origins, CORS with Private Network Access), job cancel, Tomie/Unity adapters, benchmark
Includes earlier uncommitted work: Tomie and Unity adapters, benchmark, structured output, call metrics. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
13492929c6
commit
f49ee90477
32 files changed
+2799
-51
No files matched your search
@@ -36,6 +36,12 @@ class Storage:
|
||||
PRIMARY KEY (fingerprint, source)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS jobs_project ON jobs(project_id, created_at);
|
||||
CREATE TABLE IF NOT EXISTS provider_calls (
|
||||
id INTEGER PRIMARY KEY, job_id TEXT NOT NULL, item_count INTEGER NOT NULL,
|
||||
seconds REAL NOT NULL, prompt_tokens INTEGER, completion_tokens INTEGER,
|
||||
error TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS calls_job ON provider_calls(job_id);
|
||||
""")
|
||||
|
||||
@contextmanager
|
||||
@@ -75,6 +81,8 @@ class Storage:
|
||||
def connect(self):
|
||||
db = sqlite3.connect(self.path, timeout=10)
|
||||
db.row_factory = sqlite3.Row
|
||||
# Avoid system-drive temporary files during large result scans/sorts.
|
||||
db.execute("PRAGMA temp_store=MEMORY")
|
||||
try:
|
||||
with db:
|
||||
yield db
|
||||
@@ -116,6 +124,13 @@ class Storage:
|
||||
return None
|
||||
result = dict(row)
|
||||
result["items"] = [dict(item) for item in db.execute("SELECT id,source,translation,status,error,attempts,cached,position FROM items WHERE job_id=? ORDER BY position", (identity,))]
|
||||
result["metrics"] = dict(db.execute("""SELECT COUNT(*) AS provider_calls,
|
||||
COALESCE(SUM(seconds),0) AS provider_seconds,
|
||||
SUM(prompt_tokens) AS prompt_tokens, SUM(completion_tokens) AS completion_tokens,
|
||||
COUNT(prompt_tokens) AS calls_with_prompt_usage,
|
||||
COUNT(completion_tokens) AS calls_with_completion_usage,
|
||||
COALESCE(SUM(error IS NOT NULL),0) AS provider_errors
|
||||
FROM provider_calls WHERE job_id=?""", (identity,)).fetchone())
|
||||
if internal:
|
||||
result["snapshot"] = json.loads(result["snapshot"])
|
||||
result["request"] = json.loads(result["request"])
|
||||
@@ -139,7 +154,18 @@ class Storage:
|
||||
|
||||
def job_status(self, identity, status, error=None, model=None):
|
||||
with self.connect() as db:
|
||||
db.execute("UPDATE jobs SET status=?,error=?,model=COALESCE(?,model) WHERE id=?", (status, error, model, identity))
|
||||
# A cancelled job stays cancelled even if the worker finishes a batch afterwards.
|
||||
db.execute("UPDATE jobs SET status=?,error=?,model=COALESCE(?,model) WHERE id=? AND status!='cancelled'", (status, error, model, identity))
|
||||
|
||||
def job_state(self, identity):
|
||||
with self.connect() as db:
|
||||
row = db.execute("SELECT status FROM jobs WHERE id=?", (identity,)).fetchone()
|
||||
return row["status"] if row else None
|
||||
|
||||
def cancel(self, identity):
|
||||
with self.connect() as db:
|
||||
db.execute("UPDATE items SET status='failed',error='Cancelled' WHERE job_id=? AND status='pending'", (identity,))
|
||||
db.execute("UPDATE jobs SET status='cancelled',error=NULL WHERE id=? AND status IN ('queued','running')", (identity,))
|
||||
|
||||
def item_result(self, job_id, position, status, translation=None, error=None, cached=False):
|
||||
with self.connect() as db:
|
||||
@@ -158,6 +184,11 @@ class Storage:
|
||||
with self.connect() as db:
|
||||
db.execute("INSERT OR REPLACE INTO cache VALUES (?,?,?)", (fingerprint, source, translation))
|
||||
|
||||
def record_call(self, job_id, item_count, metrics, error=None):
|
||||
with self.connect() as db:
|
||||
db.execute("INSERT INTO provider_calls(job_id,item_count,seconds,prompt_tokens,completion_tokens,error) VALUES (?,?,?,?,?,?)",
|
||||
(job_id, item_count, metrics.get("seconds", 0), metrics.get("prompt_tokens"), metrics.get("completion_tokens"), error))
|
||||
|
||||
def retry(self, identity):
|
||||
with self.connect() as db:
|
||||
db.execute("UPDATE items SET status='pending',error=NULL,attempts=0 WHERE job_id=? AND status!='completed'", (identity,))
|
||||
|
||||
Reference in new issue
Block a user