Route live research through llm-connect and record pilot findings
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0cffe-206f-7323-89d3-b20ca4cf4bf9
This commit is contained in:
parent
1f95f6389a
commit
2ec23bb22c
39 changed files with 2259 additions and 22 deletions
|
|
@ -5,6 +5,8 @@ import argparse
|
|||
import hashlib
|
||||
import json
|
||||
import re
|
||||
from urllib import error, request
|
||||
from urllib.parse import urlsplit
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
|
|
@ -12,7 +14,8 @@ import yaml
|
|||
from infospace_bench import create_infospace, load_infospace, register_artifact
|
||||
from infospace_bench.errors import InfospaceError
|
||||
from infospace_bench.workflow import FixtureAssistedGenerationAdapter, run_workflow
|
||||
from infospace_bench.openrouter import OpenRouterAssistedGenerationAdapter
|
||||
from infospace_bench.workflow import AssistedGenerationResult
|
||||
from llm_connect.models import RunConfig
|
||||
|
||||
REPO = Path(__file__).resolve().parents[1]
|
||||
PROFILE = REPO / "research/bench/profile"
|
||||
|
|
@ -83,6 +86,50 @@ def plan(root):
|
|||
"review_status": "unreviewed"}
|
||||
|
||||
|
||||
class LLMConnectAdapter:
|
||||
"""Client of llm-connect's /execute contract; credentials stay at the service."""
|
||||
|
||||
def __init__(self, endpoint, model, max_tokens=4000):
|
||||
parsed = urlsplit(endpoint)
|
||||
if (parsed.scheme not in ("http", "https") or not parsed.hostname
|
||||
or parsed.username or parsed.password or parsed.query or parsed.fragment):
|
||||
raise ValueError("Use an HTTP(S) llm-connect URL without credentials or query")
|
||||
if max_tokens <= 0:
|
||||
raise ValueError("--max-tokens must be positive")
|
||||
self.endpoint, self.model = endpoint.rstrip("/"), model
|
||||
self.config = RunConfig(model_name=model, temperature=0.2, max_tokens=max_tokens)
|
||||
self.responses = []
|
||||
|
||||
def generate(self, generation):
|
||||
payload = {"prompt": generation.prompt, "config": self.config.to_dict()}
|
||||
req = request.Request(self.endpoint + "/execute",
|
||||
data=json.dumps(payload).encode(),
|
||||
headers={"Content-Type": "application/json"})
|
||||
try:
|
||||
with request.urlopen(req, timeout=self.config.timeout_seconds + 15) as response:
|
||||
data = json.load(response)
|
||||
except error.HTTPError as exc:
|
||||
raise InfospaceError("llm_connect_http", "llm-connect request failed",
|
||||
{"error": f"HTTP Error {exc.code}"}) from None
|
||||
except (error.URLError, TimeoutError):
|
||||
raise InfospaceError("llm_connect_transport", "llm-connect unavailable", {}) from None
|
||||
except ValueError:
|
||||
raise InfospaceError("llm_connect_response", "Invalid llm-connect JSON", {}) from None
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError("Invalid llm-connect response object")
|
||||
metadata = {key: data.get(key) for key in ("model", "usage", "finish_reason")}
|
||||
extra = data.get("metadata") or {}
|
||||
metadata.update({key: extra[key] for key in (
|
||||
"provider", "response_id", "latency_seconds", "profile", "profile_model",
|
||||
"profile_provider") if key in extra})
|
||||
self.responses.append({"stage": generation.stage_id, **metadata})
|
||||
if (not isinstance(data.get("content"), str) or not data["content"].strip()
|
||||
or data.get("finish_reason") != "stop"):
|
||||
raise ValueError("llm-connect returned empty or incomplete generation; see receipt")
|
||||
return AssistedGenerationResult(markdown=data["content"], provider="llm-connect",
|
||||
metadata=metadata)
|
||||
|
||||
|
||||
class LimitedAdapter:
|
||||
def __init__(self, adapter, limit):
|
||||
self.adapter, self.limit, self.calls = adapter, limit, 0
|
||||
|
|
@ -111,6 +158,10 @@ def execute(root, adapter, max_calls=4):
|
|||
manifest["status"] = "started"
|
||||
manifest["adapter"] = type(adapter).__name__
|
||||
manifest["model"] = getattr(adapter, "model", "")
|
||||
if isinstance(adapter, LLMConnectAdapter):
|
||||
manifest["execution"] = {"endpoint": adapter.endpoint,
|
||||
"config": adapter.config.to_dict(),
|
||||
"call_limit_scope": "service requests; server retries unknown"}
|
||||
receipt.write_text(json.dumps(manifest, indent=2) + "\n")
|
||||
limited = LimitedAdapter(adapter, max_calls)
|
||||
try:
|
||||
|
|
@ -127,6 +178,9 @@ def execute(root, adapter, max_calls=4):
|
|||
raise
|
||||
finally:
|
||||
manifest["provider_calls_attempted"] = limited.calls
|
||||
if isinstance(adapter, LLMConnectAdapter):
|
||||
manifest["service_requests_attempted"] = limited.calls
|
||||
manifest["responses"] = adapter.responses
|
||||
receipt.write_text(json.dumps(manifest, indent=2) + "\n")
|
||||
return manifest
|
||||
|
||||
|
|
@ -144,8 +198,9 @@ def main():
|
|||
run.add_argument("root", type=Path)
|
||||
providers = run.add_mutually_exclusive_group(required=True)
|
||||
providers.add_argument("--fixture-responses", type=Path)
|
||||
providers.add_argument("--provider", choices=["openrouter"])
|
||||
run.add_argument("--model")
|
||||
providers.add_argument("--llm-connect-url", help="llm-connect service base URL")
|
||||
run.add_argument("--model", help="Model or runtime profile requested from llm-connect")
|
||||
run.add_argument("--max-tokens", type=int, default=4000)
|
||||
run.add_argument("--max-calls", type=int, default=4)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
|
|
@ -161,7 +216,7 @@ def main():
|
|||
else:
|
||||
if not args.model:
|
||||
raise ValueError("Live generation requires --model")
|
||||
adapter = OpenRouterAssistedGenerationAdapter(model=args.model, retry_limit=0)
|
||||
adapter = LLMConnectAdapter(args.llm_connect_url, args.model, args.max_tokens)
|
||||
result = execute(args.root, adapter, args.max_calls)
|
||||
print(json.dumps(result, indent=2, default=str))
|
||||
except (ValueError, OSError, InfospaceError) as exc:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue