@konbakuyomu/smart-search-linux-x64 0.0.0 → 0.1.26
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/LICENSE +21 -0
- package/package.json +18 -3
- package/runtime/smart-search/_internal/base_library.zip +0 -0
- package/runtime/smart-search/_internal/certifi/cacert.pem +3959 -0
- package/runtime/smart-search/_internal/certifi/py.typed +0 -0
- package/runtime/smart-search/_internal/libpython3.13.so.1.0 +0 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/INSTALLER +1 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/METADATA +171 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/RECORD +298 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/WHEEL +5 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/licenses/AUTHORS.rst +11 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/licenses/LICENSE +27 -0
- package/runtime/smart-search/_internal/prompt_toolkit-3.0.53.dist-info/top_level.txt +1 -0
- package/runtime/smart-search/_internal/smart_search/__init__.py +1 -0
- package/runtime/smart-search/_internal/smart_search/activity.py +279 -0
- package/runtime/smart-search/_internal/smart_search/assets/i18n/messages.json +17858 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/SKILL.md +69 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/agents/openai.yaml +3 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/cli-contract.md +21 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/cli-core.md +99 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/command-patterns.md +166 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/deep-research-mode.md +204 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/provider-routing.md +178 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/regression-release.md +46 -0
- package/runtime/smart-search/_internal/smart_search/assets/skills/smart-search-cli/references/setup-config.md +133 -0
- package/runtime/smart-search/_internal/smart_search/assets/ui/index.html +955 -0
- package/runtime/smart-search/_internal/smart_search/cli.py +3651 -0
- package/runtime/smart-search/_internal/smart_search/config.py +1302 -0
- package/runtime/smart-search/_internal/smart_search/desktop_backend.py +709 -0
- package/runtime/smart-search/_internal/smart_search/desktop_catalog.py +166 -0
- package/runtime/smart-search/_internal/smart_search/desktop_cli.py +209 -0
- package/runtime/smart-search/_internal/smart_search/desktop_entry.py +19 -0
- package/runtime/smart-search/_internal/smart_search/desktop_environment.py +629 -0
- package/runtime/smart-search/_internal/smart_search/desktop_skills.py +129 -0
- package/runtime/smart-search/_internal/smart_search/desktop_updates.py +160 -0
- package/runtime/smart-search/_internal/smart_search/desktop_worker.py +117 -0
- package/runtime/smart-search/_internal/smart_search/i18n.py +135 -0
- package/runtime/smart-search/_internal/smart_search/intent_router.py +253 -0
- package/runtime/smart-search/_internal/smart_search/jev.py +473 -0
- package/runtime/smart-search/_internal/smart_search/jev_search.py +719 -0
- package/runtime/smart-search/_internal/smart_search/logger.py +43 -0
- package/runtime/smart-search/_internal/smart_search/provider_descriptions.py +140 -0
- package/runtime/smart-search/_internal/smart_search/provider_errors.py +137 -0
- package/runtime/smart-search/_internal/smart_search/provider_health.py +277 -0
- package/runtime/smart-search/_internal/smart_search/providers/__init__.py +27 -0
- package/runtime/smart-search/_internal/smart_search/providers/anysearch.py +336 -0
- package/runtime/smart-search/_internal/smart_search/providers/base.py +41 -0
- package/runtime/smart-search/_internal/smart_search/providers/context7.py +153 -0
- package/runtime/smart-search/_internal/smart_search/providers/exa.py +191 -0
- package/runtime/smart-search/_internal/smart_search/providers/jina.py +124 -0
- package/runtime/smart-search/_internal/smart_search/providers/openai_compatible.py +977 -0
- package/runtime/smart-search/_internal/smart_search/providers/sciverse.py +351 -0
- package/runtime/smart-search/_internal/smart_search/providers/tinyfish.py +213 -0
- package/runtime/smart-search/_internal/smart_search/providers/xai_responses.py +242 -0
- package/runtime/smart-search/_internal/smart_search/providers/zhipu.py +172 -0
- package/runtime/smart-search/_internal/smart_search/providers/zhipu_mcp.py +287 -0
- package/runtime/smart-search/_internal/smart_search/sciverse_schema.py +437 -0
- package/runtime/smart-search/_internal/smart_search/service.py +4302 -0
- package/runtime/smart-search/_internal/smart_search/skill_installer.py +549 -0
- package/runtime/smart-search/_internal/smart_search/skill_maintenance.py +181 -0
- package/runtime/smart-search/_internal/smart_search/sources.py +429 -0
- package/runtime/smart-search/_internal/smart_search/state_files.py +53 -0
- package/runtime/smart-search/_internal/smart_search/ui_api.py +246 -0
- package/runtime/smart-search/_internal/smart_search/ui_metadata.py +698 -0
- package/runtime/smart-search/_internal/smart_search/ui_server.py +506 -0
- package/runtime/smart-search/_internal/smart_search/utils.py +220 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/INSTALLER +1 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/METADATA +97 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/RECORD +105 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/REQUESTED +0 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/WHEEL +5 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/direct_url.json +1 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/entry_points.txt +2 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/licenses/LICENSE +21 -0
- package/runtime/smart-search/_internal/smart_search-0.1.26.dist-info/top_level.txt +1 -0
- package/runtime/smart-search/_internal/wcwidth/_wcwidth_c.abi3.so +0 -0
- package/runtime/smart-search/_internal/wcwidth/_wcwidth_c.pyi +77 -0
- package/runtime/smart-search/_internal/wcwidth/py.typed +0 -0
- package/runtime/smart-search/package.json +49 -0
- package/runtime/smart-search/smart-search +0 -0
- package/README.md +0 -3
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"""Local, bounded, metadata-only activity shared by the CLI and desktop clients."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from .i18n import source_message
|
|
4
|
+
|
|
5
|
+
from contextlib import contextmanager
|
|
6
|
+
from contextvars import ContextVar
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import sqlite3
|
|
10
|
+
import sys
|
|
11
|
+
import threading
|
|
12
|
+
import time
|
|
13
|
+
import uuid
|
|
14
|
+
|
|
15
|
+
from .config import config
|
|
16
|
+
|
|
17
|
+
SCHEMA_VERSION = 2
|
|
18
|
+
MAX_COMPLETED_RUNS = 1000
|
|
19
|
+
RETENTION_SECONDS = 7 * 86400
|
|
20
|
+
_current: ContextVar[Invocation | None] = ContextVar("smart_search_activity", default=None)
|
|
21
|
+
_SAFE_ERROR_TYPES = {"", "parameter_error", "config_error", "auth_error", "timeout", "rate_limited",
|
|
22
|
+
"network_error", "parse_error", "provider_error", "runtime_error", "cancelled",
|
|
23
|
+
"evidence_error", "interrupted"}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class ActivityStore:
|
|
27
|
+
def __init__(self, directory: str | Path | None = None):
|
|
28
|
+
self.directory = Path(directory) if directory is not None else config.config_file.parent
|
|
29
|
+
self.path = self.directory / "activity.sqlite3"
|
|
30
|
+
|
|
31
|
+
@contextmanager
|
|
32
|
+
def connection(self, timeout: float = 0.2):
|
|
33
|
+
self.directory.mkdir(parents=True, exist_ok=True)
|
|
34
|
+
db = sqlite3.connect(self.path, timeout=timeout)
|
|
35
|
+
try:
|
|
36
|
+
if os.name != "nt":
|
|
37
|
+
self.path.chmod(0o600)
|
|
38
|
+
db.row_factory = sqlite3.Row
|
|
39
|
+
db.execute("PRAGMA foreign_keys=ON")
|
|
40
|
+
version = db.execute("PRAGMA user_version").fetchone()[0]
|
|
41
|
+
if version > SCHEMA_VERSION:
|
|
42
|
+
raise ValueError(source_message('Activity database was created by a newer version.'))
|
|
43
|
+
if not version:
|
|
44
|
+
db.executescript("""
|
|
45
|
+
CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY, value TEXT NOT NULL);
|
|
46
|
+
CREATE TABLE IF NOT EXISTS runs (
|
|
47
|
+
run_id TEXT PRIMARY KEY, command TEXT NOT NULL, origin TEXT NOT NULL,
|
|
48
|
+
config_dir TEXT NOT NULL, version TEXT NOT NULL, pid INTEGER NOT NULL,
|
|
49
|
+
status TEXT NOT NULL DEFAULT 'running', phase TEXT NOT NULL DEFAULT 'starting',
|
|
50
|
+
provider TEXT NOT NULL DEFAULT '', model TEXT NOT NULL DEFAULT '',
|
|
51
|
+
started_at REAL NOT NULL, updated_at REAL NOT NULL, finished_at REAL,
|
|
52
|
+
elapsed_ms REAL NOT NULL DEFAULT 0, error_type TEXT NOT NULL DEFAULT '',
|
|
53
|
+
exit_code INTEGER, sources_count INTEGER NOT NULL DEFAULT 0,
|
|
54
|
+
sequence INTEGER NOT NULL DEFAULT 0, config_revision TEXT NOT NULL DEFAULT '');
|
|
55
|
+
CREATE TABLE IF NOT EXISTS events (
|
|
56
|
+
id INTEGER PRIMARY KEY, run_id TEXT NOT NULL REFERENCES runs(run_id) ON DELETE CASCADE,
|
|
57
|
+
sequence INTEGER NOT NULL, timestamp REAL NOT NULL, phase TEXT NOT NULL,
|
|
58
|
+
provider TEXT NOT NULL DEFAULT '', model TEXT NOT NULL DEFAULT '',
|
|
59
|
+
status TEXT NOT NULL, error_type TEXT NOT NULL DEFAULT '',
|
|
60
|
+
UNIQUE(run_id, sequence));
|
|
61
|
+
CREATE INDEX IF NOT EXISTS events_run ON events(run_id, sequence);
|
|
62
|
+
PRAGMA user_version=2;
|
|
63
|
+
""")
|
|
64
|
+
elif version == 1:
|
|
65
|
+
db.execute("BEGIN IMMEDIATE")
|
|
66
|
+
if db.execute("PRAGMA user_version").fetchone()[0] == 1:
|
|
67
|
+
db.execute("ALTER TABLE runs ADD COLUMN config_revision TEXT NOT NULL DEFAULT ''")
|
|
68
|
+
db.execute("PRAGMA user_version=2")
|
|
69
|
+
with db:
|
|
70
|
+
yield db
|
|
71
|
+
finally:
|
|
72
|
+
db.close()
|
|
73
|
+
|
|
74
|
+
def enabled(self) -> bool:
|
|
75
|
+
if os.getenv("SMART_SEARCH_ACTIVITY_ENABLED", "true").lower() in {"false", "0", "no"}:
|
|
76
|
+
return False
|
|
77
|
+
with self.connection() as db:
|
|
78
|
+
row = db.execute("SELECT value FROM settings WHERE key='enabled'").fetchone()
|
|
79
|
+
return row is None or row[0] == "true"
|
|
80
|
+
|
|
81
|
+
def set_enabled(self, enabled: bool):
|
|
82
|
+
with self.connection() as db:
|
|
83
|
+
db.execute("INSERT OR REPLACE INTO settings VALUES ('enabled', ?)", ("true" if enabled else "false",))
|
|
84
|
+
|
|
85
|
+
def start(self, run_id: str, command: str, origin: str, version: str, config_revision: str = ""):
|
|
86
|
+
now = time.time()
|
|
87
|
+
with self.connection() as db:
|
|
88
|
+
db.execute("""INSERT INTO runs(run_id,command,origin,config_dir,version,pid,started_at,updated_at,config_revision)
|
|
89
|
+
VALUES (?,?,?,?,?,?,?,?,?)""",
|
|
90
|
+
(run_id, command, origin, str(self.directory), version, os.getpid(), now, now, config_revision))
|
|
91
|
+
db.execute("INSERT INTO events(run_id,sequence,timestamp,phase,status) VALUES (?,0,?,'starting','running')",
|
|
92
|
+
(run_id, now))
|
|
93
|
+
self._prune(db, now)
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def _prune(db, now):
|
|
97
|
+
db.execute("""DELETE FROM runs WHERE finished_at IS NOT NULL AND
|
|
98
|
+
(finished_at < ? OR run_id NOT IN (SELECT run_id FROM runs WHERE finished_at IS NOT NULL
|
|
99
|
+
ORDER BY finished_at DESC LIMIT ?))""", (now - RETENTION_SECONDS, MAX_COMPLETED_RUNS))
|
|
100
|
+
|
|
101
|
+
def heartbeat(self, run_id: str):
|
|
102
|
+
with self.connection() as db:
|
|
103
|
+
db.execute("UPDATE runs SET updated_at=? WHERE run_id=? AND finished_at IS NULL", (time.time(), run_id))
|
|
104
|
+
|
|
105
|
+
def progress(self, run_id: str, *, phase: str, provider: str = "", model: str = "", error_type: str = ""):
|
|
106
|
+
now = time.time()
|
|
107
|
+
with self.connection() as db:
|
|
108
|
+
changed = db.execute("""UPDATE runs SET phase=?,provider=COALESCE(NULLIF(?,''),provider),
|
|
109
|
+
model=CASE WHEN ?='' AND (?='' OR ?=provider COLLATE NOCASE) THEN model ELSE ? END,
|
|
110
|
+
error_type=?,updated_at=?,
|
|
111
|
+
sequence=sequence+1 WHERE run_id=? AND finished_at IS NULL""",
|
|
112
|
+
(phase, provider, model, provider, provider, model, error_type, now, run_id)).rowcount
|
|
113
|
+
if changed:
|
|
114
|
+
db.execute("""INSERT INTO events(run_id,sequence,timestamp,phase,provider,model,status,error_type)
|
|
115
|
+
SELECT run_id,sequence,?,phase,provider,model,'running',error_type FROM runs WHERE run_id=?""", (now, run_id))
|
|
116
|
+
# ponytail: retain 500 phase events per run; paginate a larger journal if a real workflow needs more.
|
|
117
|
+
db.execute("DELETE FROM events WHERE run_id=? AND id NOT IN (SELECT id FROM events WHERE run_id=? ORDER BY id DESC LIMIT 500)",
|
|
118
|
+
(run_id, run_id))
|
|
119
|
+
|
|
120
|
+
def finish(self, run_id: str, exit_code: int, status: str, *, error_type: str = "", sources_count: int = 0):
|
|
121
|
+
now = time.time()
|
|
122
|
+
# SQLite's busy timeout retries the final write, still bounded to one second.
|
|
123
|
+
with self.connection(timeout=1.0) as db:
|
|
124
|
+
changed = db.execute("""UPDATE runs SET status=?,finished_at=?,updated_at=?,exit_code=?,error_type=?,
|
|
125
|
+
sources_count=?,elapsed_ms=(?-started_at)*1000,sequence=sequence+1
|
|
126
|
+
WHERE run_id=? AND finished_at IS NULL""",
|
|
127
|
+
(status, now, now, exit_code, error_type, sources_count, now, run_id)).rowcount
|
|
128
|
+
if changed:
|
|
129
|
+
db.execute("""INSERT INTO events(run_id,sequence,timestamp,phase,provider,model,status,error_type)
|
|
130
|
+
SELECT run_id,sequence,?,phase,provider,model,status,error_type FROM runs WHERE run_id=?""", (now, run_id))
|
|
131
|
+
self._prune(db, now)
|
|
132
|
+
|
|
133
|
+
@staticmethod
|
|
134
|
+
def _public_run(row):
|
|
135
|
+
value = dict(row)
|
|
136
|
+
if value["finished_at"] is None:
|
|
137
|
+
value["elapsed_ms"] = round((time.time() - value["started_at"]) * 1000, 1)
|
|
138
|
+
if time.time() - value["updated_at"] > 10:
|
|
139
|
+
value["status"] = "stale"
|
|
140
|
+
return value
|
|
141
|
+
|
|
142
|
+
def list_runs(self, limit: int = 100) -> list[dict]:
|
|
143
|
+
with self.connection() as db:
|
|
144
|
+
self._prune(db, time.time())
|
|
145
|
+
return [self._public_run(row) for row in db.execute("SELECT * FROM runs ORDER BY started_at DESC LIMIT ?",
|
|
146
|
+
(max(1, min(limit, 1000)),))]
|
|
147
|
+
|
|
148
|
+
def details(self, run_id: str) -> dict:
|
|
149
|
+
with self.connection() as db:
|
|
150
|
+
row = db.execute("SELECT * FROM runs WHERE run_id=?", (run_id,)).fetchone()
|
|
151
|
+
if row is None:
|
|
152
|
+
return {"ok": False, "error": source_message('活动记录不存在。')}
|
|
153
|
+
events = [dict(item) for item in db.execute("SELECT sequence,timestamp,phase,provider,model,status,error_type FROM events WHERE run_id=? ORDER BY sequence", (run_id,))]
|
|
154
|
+
return {"ok": True, "run": self._public_run(row), "events": events,
|
|
155
|
+
"events_truncated": bool(events and events[0]["sequence"] > 0)}
|
|
156
|
+
|
|
157
|
+
def clear(self):
|
|
158
|
+
with self.connection() as db:
|
|
159
|
+
db.execute("DELETE FROM runs WHERE finished_at IS NOT NULL")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class Invocation:
|
|
163
|
+
def __init__(self, command: str, *, origin: str = "cli", version: str = "", run_id: str = ""):
|
|
164
|
+
self.run_id = uuid.UUID(run_id).hex if run_id else uuid.uuid4().hex
|
|
165
|
+
self.command, self.origin, self.version = command[:100], origin, version
|
|
166
|
+
self._stop = threading.Event()
|
|
167
|
+
self._warned = False
|
|
168
|
+
self._enabled = False
|
|
169
|
+
self._finished = False
|
|
170
|
+
self._error_type = ""
|
|
171
|
+
self._sources_count = 0
|
|
172
|
+
self._heartbeat = None
|
|
173
|
+
self.store = self._try(ActivityStore)
|
|
174
|
+
self._secrets = self._try(config.secret_values) or ()
|
|
175
|
+
# An opaque snapshot handle identifies this invocation without retaining a
|
|
176
|
+
# credential-derived hash that could be used as an offline guessing oracle.
|
|
177
|
+
self._revision = uuid.uuid4().hex
|
|
178
|
+
|
|
179
|
+
def _try(self, fn, *args, **kwargs):
|
|
180
|
+
try:
|
|
181
|
+
return fn(*args, **kwargs)
|
|
182
|
+
except (OSError, sqlite3.Error, ValueError):
|
|
183
|
+
if not self._warned:
|
|
184
|
+
self._warned = True
|
|
185
|
+
try:
|
|
186
|
+
print("smart-search: activity recording unavailable; the command will continue.", file=sys.stderr)
|
|
187
|
+
except OSError:
|
|
188
|
+
pass
|
|
189
|
+
return None
|
|
190
|
+
|
|
191
|
+
def start(self):
|
|
192
|
+
if self.store is None:
|
|
193
|
+
return
|
|
194
|
+
self._enabled = bool(self._try(self.store.enabled))
|
|
195
|
+
if not self._enabled:
|
|
196
|
+
return
|
|
197
|
+
self._try(self.store.start, self.run_id, self.command, self.origin, self.version, self._revision)
|
|
198
|
+
self._heartbeat = threading.Thread(target=self._keep_alive, daemon=True)
|
|
199
|
+
self._heartbeat.start()
|
|
200
|
+
|
|
201
|
+
def _keep_alive(self):
|
|
202
|
+
while not self._stop.wait(2):
|
|
203
|
+
self._try(self.store.heartbeat, self.run_id)
|
|
204
|
+
|
|
205
|
+
def _label(self, value: object) -> str:
|
|
206
|
+
text = str(value or "")
|
|
207
|
+
for secret in self._secrets:
|
|
208
|
+
if secret:
|
|
209
|
+
text = text.replace(secret, "[REDACTED]")
|
|
210
|
+
return text[:100]
|
|
211
|
+
|
|
212
|
+
def progress(self, phase: str, provider: str = "", model: str = "", error_type: str = ""):
|
|
213
|
+
if self._enabled and not self._finished:
|
|
214
|
+
self._try(self.store.progress, self.run_id, phase=self._label(phase), provider=self._label(provider),
|
|
215
|
+
model=self._label(model), error_type=error_type if error_type in _SAFE_ERROR_TYPES else "runtime_error")
|
|
216
|
+
|
|
217
|
+
def result(self, data: dict):
|
|
218
|
+
if data.get("provider"):
|
|
219
|
+
# The final result names the primary provider; keep supplemental
|
|
220
|
+
# providers in phase events without attaching its model to them.
|
|
221
|
+
self.progress(self.command, str(data["provider"]), str(data.get("model") or ""))
|
|
222
|
+
self._error_type = str(data.get("error_type") or "")
|
|
223
|
+
if self._error_type not in _SAFE_ERROR_TYPES:
|
|
224
|
+
self._error_type = "runtime_error"
|
|
225
|
+
sources = data.get("sources")
|
|
226
|
+
self._sources_count = len(sources) if isinstance(sources, list) else 0
|
|
227
|
+
|
|
228
|
+
def finish(self, exit_code: int = 0, status: str = ""):
|
|
229
|
+
if self._finished:
|
|
230
|
+
return
|
|
231
|
+
self._finished = True
|
|
232
|
+
self._stop.set()
|
|
233
|
+
status = status or ("cancelled" if self._error_type == "cancelled" else "finished" if exit_code == 0 else "failed")
|
|
234
|
+
if self._enabled:
|
|
235
|
+
self._try(self.store.finish, self.run_id, exit_code, status, error_type=self._error_type,
|
|
236
|
+
sources_count=self._sources_count)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
@contextmanager
|
|
240
|
+
def observe(command: str, *, origin: str = "cli", version: str = "", run_id: str = ""):
|
|
241
|
+
previous = _current.get()
|
|
242
|
+
if previous is not None:
|
|
243
|
+
yield previous
|
|
244
|
+
return
|
|
245
|
+
run = Invocation(command, origin=origin, version=version, run_id=run_id)
|
|
246
|
+
token = _current.set(run)
|
|
247
|
+
run.start()
|
|
248
|
+
try:
|
|
249
|
+
yield run
|
|
250
|
+
except KeyboardInterrupt:
|
|
251
|
+
run.finish(5, "cancelled")
|
|
252
|
+
raise
|
|
253
|
+
except SystemExit as error:
|
|
254
|
+
run.finish(error.code if isinstance(error.code, int) else 5)
|
|
255
|
+
raise
|
|
256
|
+
except BaseException:
|
|
257
|
+
run.finish(5)
|
|
258
|
+
raise
|
|
259
|
+
finally:
|
|
260
|
+
run.finish()
|
|
261
|
+
_current.reset(token)
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def progress(phase: str, provider: str = "", model: str = "", error_type: str = ""):
|
|
265
|
+
run = _current.get()
|
|
266
|
+
if run is not None:
|
|
267
|
+
run.progress(phase, provider, model, error_type)
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def result(data: dict):
|
|
271
|
+
run = _current.get()
|
|
272
|
+
if run is not None:
|
|
273
|
+
run.result(data)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def cancelled():
|
|
277
|
+
run = _current.get()
|
|
278
|
+
if run is not None:
|
|
279
|
+
run.finish(5, "cancelled")
|