sourcesql 0.1.0__py3-none-any.whl
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.
- sourcesql/__init__.py +2 -0
- sourcesql/_resources/personal-cloud.zip +0 -0
- sourcesql/bridge.py +87 -0
- sourcesql/cli.py +93 -0
- sourcesql/contracts.py +109 -0
- sourcesql/engine.py +1241 -0
- sourcesql/execution/linux_sandbox.py +280 -0
- sourcesql/execution/linux_syscalls.py +216 -0
- sourcesql/execution/planner.py +429 -0
- sourcesql/execution/worker.py +150 -0
- sourcesql/execution/worker_process.py +191 -0
- sourcesql/onboarding/__init__.py +191 -0
- sourcesql/providers/__init__.py +300 -0
- sourcesql/providers/common.py +346 -0
- sourcesql/providers/fixture.py +369 -0
- sourcesql/providers/search.py +539 -0
- sourcesql/providers/semantic.py +538 -0
- sourcesql/resources.py +133 -0
- sourcesql/sql/__init__.py +5 -0
- sourcesql/sql/admission.py +1049 -0
- sourcesql/storage/archive.py +98 -0
- sourcesql/storage/motherduck.py +507 -0
- sourcesql/storage/store.py +259 -0
- sourcesql-0.1.0.dist-info/METADATA +223 -0
- sourcesql-0.1.0.dist-info/RECORD +29 -0
- sourcesql-0.1.0.dist-info/WHEEL +4 -0
- sourcesql-0.1.0.dist-info/entry_points.txt +2 -0
- sourcesql-0.1.0.dist-info/licenses/LICENSE +202 -0
- sourcesql-0.1.0.dist-info/licenses/NOTICE +10 -0
sourcesql/__init__.py
ADDED
|
Binary file
|
sourcesql/bridge.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""Bounded JSON-lines interface for the existing research service; stdout is machine-only."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import sys
|
|
8
|
+
import threading
|
|
9
|
+
from sourcesql.contracts import SourcesQLError, canonical
|
|
10
|
+
from sourcesql.contracts import digest
|
|
11
|
+
from sourcesql.engine import Engine, strict_json
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main():
|
|
15
|
+
profiles = {}
|
|
16
|
+
path = os.environ.get("SOURCESQL_PROFILES_FILE")
|
|
17
|
+
if path:
|
|
18
|
+
profiles = strict_json(Path(path).read_bytes())
|
|
19
|
+
principal = os.environ.get("SOURCESQL_PRINCIPAL", "local-owner")
|
|
20
|
+
store_root = (
|
|
21
|
+
Path(os.environ.get("SOURCESQL_DATA_DIR", "local/engine"))
|
|
22
|
+
/ "principals"
|
|
23
|
+
/ digest(principal)[:32]
|
|
24
|
+
)
|
|
25
|
+
engine = Engine(
|
|
26
|
+
store_root,
|
|
27
|
+
profiles=profiles,
|
|
28
|
+
allow_private=os.environ.get("SOURCESQL_ALLOW_PRIVATE", "1") == "1",
|
|
29
|
+
)
|
|
30
|
+
methods = {
|
|
31
|
+
"capabilities": engine.capabilities,
|
|
32
|
+
"query": engine.query,
|
|
33
|
+
"explain": engine.explain,
|
|
34
|
+
"read_result": engine.read_result,
|
|
35
|
+
"import_table": engine.import_table,
|
|
36
|
+
"export": engine.export,
|
|
37
|
+
"import": engine.import_bundle,
|
|
38
|
+
"run_status": engine.run_status,
|
|
39
|
+
"cancel": engine.cancel,
|
|
40
|
+
}
|
|
41
|
+
output_lock = threading.Lock()
|
|
42
|
+
|
|
43
|
+
def respond(line):
|
|
44
|
+
request_id = None
|
|
45
|
+
try:
|
|
46
|
+
if len(line) > 4 * 1024 * 1024:
|
|
47
|
+
raise SourcesQLError("budget_exhausted", "Bridge input exceeds byte limit")
|
|
48
|
+
request = strict_json(line)
|
|
49
|
+
request_id = request.get("id")
|
|
50
|
+
if (
|
|
51
|
+
not isinstance(request, dict)
|
|
52
|
+
or set(request) - {"id", "method", "params"}
|
|
53
|
+
or request.get("method") not in methods
|
|
54
|
+
):
|
|
55
|
+
raise SourcesQLError("invalid_request", "Invalid bridge request")
|
|
56
|
+
params = request.get("params", {})
|
|
57
|
+
if not isinstance(params, dict):
|
|
58
|
+
raise SourcesQLError("invalid_request", "Invalid method parameters")
|
|
59
|
+
result = methods[request["method"]](**params)
|
|
60
|
+
response = {"id": request_id, "result": result}
|
|
61
|
+
except SourcesQLError as error:
|
|
62
|
+
response = {
|
|
63
|
+
"id": request_id,
|
|
64
|
+
"error": {"code": error.code, "message": error.safe_message, "stage": error.stage},
|
|
65
|
+
}
|
|
66
|
+
except Exception:
|
|
67
|
+
response = {
|
|
68
|
+
"id": request_id,
|
|
69
|
+
"error": {"code": "invalid_request", "message": "Request failed safely"},
|
|
70
|
+
}
|
|
71
|
+
with output_lock:
|
|
72
|
+
sys.stdout.buffer.write(canonical(response) + b"\n")
|
|
73
|
+
sys.stdout.buffer.flush()
|
|
74
|
+
|
|
75
|
+
with ThreadPoolExecutor(max_workers=4) as executor:
|
|
76
|
+
while line := sys.stdin.buffer.readline(4 * 1024 * 1024 + 1):
|
|
77
|
+
if not line.endswith(b"\n"):
|
|
78
|
+
while chunk := sys.stdin.buffer.readline(4 * 1024 * 1024 + 1):
|
|
79
|
+
if chunk.endswith(b"\n"):
|
|
80
|
+
break
|
|
81
|
+
respond(b"{}")
|
|
82
|
+
else:
|
|
83
|
+
executor.submit(respond, line)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
main()
|
sourcesql/cli.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Headless developer entry point; fixture mode by default."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import sys
|
|
7
|
+
from sourcesql import __version__
|
|
8
|
+
from sourcesql.contracts import SourcesQLError, canonical
|
|
9
|
+
from sourcesql.engine import Engine, strict_json
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main(argv=None):
|
|
13
|
+
argv = list(sys.argv[1:] if argv is None else argv)
|
|
14
|
+
parser = argparse.ArgumentParser(prog="sourcesql")
|
|
15
|
+
parser.add_argument("--version", action="version", version=f"sourcesQL {__version__}")
|
|
16
|
+
parser.add_argument("--store", default=os.environ.get("SOURCESQL_DATA_DIR", "local/engine"))
|
|
17
|
+
commands = parser.add_subparsers(dest="command", required=True)
|
|
18
|
+
setup = commands.add_parser("setup", help="Prepare or resume an adopter-owned deployment")
|
|
19
|
+
setup.add_argument("setup_target", choices=["personal-cloud"])
|
|
20
|
+
setup.add_argument("arguments", nargs=argparse.REMAINDER)
|
|
21
|
+
commands.add_parser("capabilities").add_argument("--json", action="store_true")
|
|
22
|
+
for command in ["query", "explain"]:
|
|
23
|
+
p = commands.add_parser(command)
|
|
24
|
+
p.add_argument("--file", type=Path)
|
|
25
|
+
p.add_argument("--sql")
|
|
26
|
+
p.add_argument("--request", type=Path)
|
|
27
|
+
p.add_argument("--profile", default="fixture")
|
|
28
|
+
p.add_argument("--json", action="store_true")
|
|
29
|
+
p = commands.add_parser("read")
|
|
30
|
+
p.add_argument("result_id")
|
|
31
|
+
p.add_argument("--offset", type=int, default=0)
|
|
32
|
+
p.add_argument("--limit", type=int, default=100)
|
|
33
|
+
p = commands.add_parser("export")
|
|
34
|
+
p.add_argument("--result", required=True)
|
|
35
|
+
p.add_argument("--output", type=Path, required=True)
|
|
36
|
+
p = commands.add_parser("import")
|
|
37
|
+
p.add_argument("file", type=Path)
|
|
38
|
+
p.add_argument("--no-network", action="store_true")
|
|
39
|
+
p = commands.add_parser("demo")
|
|
40
|
+
p.add_argument("--profile", choices=["fixture"], default="fixture")
|
|
41
|
+
p.add_argument("--output", type=Path, default=Path("artifacts/demo"))
|
|
42
|
+
args = parser.parse_args(argv)
|
|
43
|
+
if args.command == "setup":
|
|
44
|
+
from sourcesql.onboarding import run_personal_cloud
|
|
45
|
+
|
|
46
|
+
return run_personal_cloud(args.arguments)
|
|
47
|
+
try:
|
|
48
|
+
profile_path = os.environ.get("SOURCESQL_PROFILES_FILE")
|
|
49
|
+
engine = Engine(
|
|
50
|
+
args.store,
|
|
51
|
+
profiles=strict_json(Path(profile_path).read_bytes()) if profile_path else None,
|
|
52
|
+
)
|
|
53
|
+
if args.command == "capabilities":
|
|
54
|
+
result = engine.capabilities()
|
|
55
|
+
elif args.command in ["query", "explain"]:
|
|
56
|
+
request = (
|
|
57
|
+
strict_json(args.request.read_bytes())
|
|
58
|
+
if args.request
|
|
59
|
+
else {
|
|
60
|
+
"query": args.file.read_text() if args.file else args.sql,
|
|
61
|
+
"profile": args.profile,
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
result = getattr(engine, args.command)(**request)
|
|
65
|
+
elif args.command == "read":
|
|
66
|
+
result = engine.read_result(args.result_id, args.offset, args.limit)
|
|
67
|
+
elif args.command == "export":
|
|
68
|
+
result = engine.export(args.result)
|
|
69
|
+
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
70
|
+
args.output.write_bytes(canonical(result))
|
|
71
|
+
elif args.command == "import":
|
|
72
|
+
result = engine.import_bundle(strict_json(args.file.read_bytes()))
|
|
73
|
+
else:
|
|
74
|
+
result = engine.query(
|
|
75
|
+
query="SELECT url, SEM_EXTRACT(content, 'project name explicitly stated') AS project, SEM_EXTRACT(content, 'planned capacity in MW, number only') AS planned_mw FROM WEB_SEARCH('fictional Aurora Birch campuses') WHERE SEM_MATCH(content, 'describes a specific data-center campus')",
|
|
76
|
+
profile="fixture",
|
|
77
|
+
)
|
|
78
|
+
args.output.mkdir(parents=True, exist_ok=True)
|
|
79
|
+
(args.output / "result.json").write_bytes(canonical(result))
|
|
80
|
+
(args.output / "bundle.json").write_bytes(canonical(engine.export(result["result_id"])))
|
|
81
|
+
print(canonical(result).decode())
|
|
82
|
+
except SourcesQLError as error:
|
|
83
|
+
print(
|
|
84
|
+
canonical(
|
|
85
|
+
{"error": {"code": error.code, "message": error.safe_message, "stage": error.stage}}
|
|
86
|
+
).decode(),
|
|
87
|
+
file=sys.stderr,
|
|
88
|
+
)
|
|
89
|
+
raise SystemExit(1)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
raise SystemExit(main())
|
sourcesql/contracts.py
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Shared engine/provider/planner contracts. Coordinator-owned."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import Any, Callable
|
|
6
|
+
import hashlib
|
|
7
|
+
import json
|
|
8
|
+
import threading
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class SourcesQLError(Exception):
|
|
12
|
+
def __init__(self, code: str, message: str, stage: str = "admission"):
|
|
13
|
+
super().__init__(message)
|
|
14
|
+
self.code, self.safe_message, self.stage = code, message, stage
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def canonical(value: Any) -> bytes:
|
|
18
|
+
return json.dumps(
|
|
19
|
+
value, ensure_ascii=False, sort_keys=True, separators=(",", ":"), allow_nan=False
|
|
20
|
+
).encode()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def digest(value: Any) -> str:
|
|
24
|
+
return hashlib.sha256(canonical(value)).hexdigest()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class Column:
|
|
29
|
+
key: str
|
|
30
|
+
logical_type: str = "VARCHAR"
|
|
31
|
+
nullable: bool = True
|
|
32
|
+
|
|
33
|
+
def to_dict(self) -> dict[str, Any]:
|
|
34
|
+
return {
|
|
35
|
+
"key": self.key,
|
|
36
|
+
"label": self.key,
|
|
37
|
+
"logical_type": self.logical_type,
|
|
38
|
+
"nullable": self.nullable,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class Table:
|
|
44
|
+
columns: list[Column]
|
|
45
|
+
rows: list[dict[str, Any]]
|
|
46
|
+
|
|
47
|
+
def to_dict(self) -> dict[str, Any]:
|
|
48
|
+
return {"columns": [c.to_dict() for c in self.columns], "rows": self.rows}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@dataclass
|
|
52
|
+
class SemanticOutcome:
|
|
53
|
+
value: Any
|
|
54
|
+
status: str
|
|
55
|
+
support: list[dict[str, Any]] = field(default_factory=list)
|
|
56
|
+
usage: dict[str, Any] = field(default_factory=dict)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
DEFAULT_LIMITS = {
|
|
60
|
+
"max_search_queries": 8,
|
|
61
|
+
"max_search_requests": 16,
|
|
62
|
+
"max_candidates": 200,
|
|
63
|
+
"max_fetches": 40,
|
|
64
|
+
"max_semantic_documents": 40,
|
|
65
|
+
"max_model_requests": 96,
|
|
66
|
+
"max_concurrency": 4,
|
|
67
|
+
"dispatch_deadline_seconds": 180,
|
|
68
|
+
"max_output_rows": 1000,
|
|
69
|
+
"max_output_bytes": 4194304,
|
|
70
|
+
"max_input_tokens": 200000,
|
|
71
|
+
"max_output_tokens": 16000,
|
|
72
|
+
"max_cost_microusd": 0,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class Budget:
|
|
77
|
+
"""One shared allowance for the whole run. Provider attempts reserve before dispatch."""
|
|
78
|
+
|
|
79
|
+
def __init__(
|
|
80
|
+
self,
|
|
81
|
+
limits: dict[str, Any] | None = None,
|
|
82
|
+
on_reserve: Callable[[str, int], None] | None = None,
|
|
83
|
+
):
|
|
84
|
+
self.limits = dict(DEFAULT_LIMITS)
|
|
85
|
+
for key, value in (limits or {}).items():
|
|
86
|
+
if key not in self.limits or type(value) is not int or value < 0:
|
|
87
|
+
raise SourcesQLError("invalid_request", "Invalid budget")
|
|
88
|
+
if key != "max_cost_microusd" and value > DEFAULT_LIMITS[key]:
|
|
89
|
+
raise SourcesQLError("invalid_request", "Requested budget exceeds v0.1 ceiling")
|
|
90
|
+
self.limits[key] = value
|
|
91
|
+
self.counts: dict[str, int] = {}
|
|
92
|
+
self.lock = threading.Lock()
|
|
93
|
+
self.cancelled = False
|
|
94
|
+
self.on_reserve = on_reserve
|
|
95
|
+
|
|
96
|
+
def reserve(self, counter: str, amount: int = 1, limit: str | None = None) -> None:
|
|
97
|
+
with self.lock:
|
|
98
|
+
if self.cancelled:
|
|
99
|
+
raise SourcesQLError("cancelled", "Run cancelled", "dispatch")
|
|
100
|
+
cap = self.limits.get(limit or "max_" + counter)
|
|
101
|
+
value = self.counts.get(counter, 0) + amount
|
|
102
|
+
if cap is not None and value > cap:
|
|
103
|
+
raise SourcesQLError("budget_exhausted", "Work allowance exhausted", "dispatch")
|
|
104
|
+
self.counts[counter] = value
|
|
105
|
+
observer = self.on_reserve
|
|
106
|
+
# Persistence/authorization observers finish before the caller can dispatch.
|
|
107
|
+
# Exceptions propagate; the reserved allowance remains conservatively consumed.
|
|
108
|
+
if observer is not None:
|
|
109
|
+
observer(counter, amount)
|