wydcode 0.4.3
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 +100 -0
- package/NOTICE +5 -0
- package/README.md +434 -0
- package/SECURITY.md +64 -0
- package/SOCRA_SOURCE.md +36 -0
- package/TRADEMARKS.md +12 -0
- package/bin/wydcode.js +74 -0
- package/examples/behavior-preference-card.json +12 -0
- package/examples/exact-recurrence-card.json +11 -0
- package/examples/heldout-gene-evidence.json +6 -0
- package/examples/humaneval-ornith.md +29 -0
- package/examples/large_context_json_diagnostic.py +187 -0
- package/fixtures/failing-node-repo/package.json +9 -0
- package/fixtures/failing-node-repo/src/math.js +3 -0
- package/fixtures/failing-node-repo/test/math.test.js +8 -0
- package/package.json +55 -0
- package/pyproject.toml +24 -0
- package/socra_harness/__init__.py +3 -0
- package/socra_harness/attempts.py +76 -0
- package/socra_harness/central_traces.py +627 -0
- package/socra_harness/cli.py +265 -0
- package/socra_harness/eval/__init__.py +1 -0
- package/socra_harness/eval/humaneval.py +388 -0
- package/socra_harness/events.py +39 -0
- package/socra_harness/init.py +206 -0
- package/socra_harness/job/__init__.py +2 -0
- package/socra_harness/job/events.py +132 -0
- package/socra_harness/job/lock.py +90 -0
- package/socra_harness/job/manager.py +3785 -0
- package/socra_harness/job/planner.py +253 -0
- package/socra_harness/job/state.py +106 -0
- package/socra_harness/mumpix_trace_bridge.cjs +32 -0
- package/socra_harness/product.py +533 -0
- package/socra_harness/recurrence.py +263 -0
- package/socra_harness/scan/__init__.py +1 -0
- package/socra_harness/scan/repo.py +85 -0
- package/socra_harness/serve/__init__.py +1 -0
- package/socra_harness/serve/local_proxy.py +293 -0
- package/socra_harness/start.py +331 -0
- package/socra_harness/tui/__init__.py +1 -0
- package/socra_harness/tui/app.py +1114 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
import posixpath
|
|
6
|
+
import re
|
|
7
|
+
from pathlib import Path, PurePosixPath
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
IDENTIFIER_RE = re.compile(r"^[A-Za-z_$][A-Za-z0-9_$.#:\-/]*$")
|
|
12
|
+
SPACE_RE = re.compile(r"\s+")
|
|
13
|
+
LINE_COLUMN_RE = re.compile(r":\d+(?::\d+)?$")
|
|
14
|
+
FORBIDDEN_BEHAVIOR_MARKERS = ("```", "@@ ", "=>", "{", "}", ";")
|
|
15
|
+
MAX_BEHAVIOR_CHARS = 2400
|
|
16
|
+
SHA256_RE = re.compile(r"^[0-9a-f]{64}$")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def canonical_json(value: Any) -> str:
|
|
20
|
+
return json.dumps(value, ensure_ascii=True, sort_keys=True, separators=(",", ":"))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def sha256_json(value: Any) -> str:
|
|
24
|
+
return hashlib.sha256(canonical_json(value).encode("ascii")).hexdigest()
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def normalize_repository(value: object) -> str:
|
|
28
|
+
text = str(value or "").strip()
|
|
29
|
+
text = re.sub(r"^(?:https?://|ssh://git@|git@)", "", text, flags=re.I)
|
|
30
|
+
text = text.replace(":", "/", 1) if text.lower().startswith("github.com:") else text
|
|
31
|
+
text = text.rstrip("/")
|
|
32
|
+
if text.endswith(".git"):
|
|
33
|
+
text = text[:-4]
|
|
34
|
+
text = text.lower()
|
|
35
|
+
match = re.fullmatch(r"github\.com/([^/]+)/([^/]+)", text)
|
|
36
|
+
if not match:
|
|
37
|
+
raise ValueError("repository_identity must be github.com/<owner>/<repo>")
|
|
38
|
+
return f"github.com/{match.group(1)}/{match.group(2)}"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def normalize_path(value: object) -> str:
|
|
42
|
+
text = str(value or "").strip().replace("\\", "/")
|
|
43
|
+
text = LINE_COLUMN_RE.sub("", text)
|
|
44
|
+
if not text or text.startswith("/") or re.match(r"^[A-Za-z]:/", text):
|
|
45
|
+
raise ValueError("owning_path must be a non-empty repository-relative path")
|
|
46
|
+
normalized = posixpath.normpath(text)
|
|
47
|
+
if normalized in (".", "..") or normalized.startswith("../"):
|
|
48
|
+
raise ValueError("owning_path escapes repository root")
|
|
49
|
+
if any(part in ("", ".", "..") for part in PurePosixPath(normalized).parts):
|
|
50
|
+
raise ValueError("owning_path is not canonical")
|
|
51
|
+
return normalized
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def normalize_symbol(value: object) -> str:
|
|
55
|
+
text = str(value or "").strip()
|
|
56
|
+
if not text or not IDENTIFIER_RE.fullmatch(text):
|
|
57
|
+
raise ValueError("owning_symbol_or_api must be one exact identifier")
|
|
58
|
+
return text
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def normalize_invariant_part(value: object, field: str) -> str:
|
|
62
|
+
text = SPACE_RE.sub(" ", str(value or "").strip().lower())
|
|
63
|
+
if not text:
|
|
64
|
+
raise ValueError(f"invariant.{field} is required")
|
|
65
|
+
if any(char in text for char in "\r\n\t"):
|
|
66
|
+
raise ValueError(f"invariant.{field} contains control whitespace")
|
|
67
|
+
return text
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def compile_recurrence_card(card: object) -> dict[str, Any]:
|
|
71
|
+
if not isinstance(card, dict):
|
|
72
|
+
return {"status": "recurrence_key_unassignable", "reason": "card_not_object"}
|
|
73
|
+
card_id = str(card.get("card_id") or "").strip()
|
|
74
|
+
if not card_id:
|
|
75
|
+
return {"status": "recurrence_key_unassignable", "reason": "card_id_missing"}
|
|
76
|
+
try:
|
|
77
|
+
invariant = card.get("invariant")
|
|
78
|
+
if not isinstance(invariant, dict):
|
|
79
|
+
raise ValueError("invariant must be a structured object")
|
|
80
|
+
key = {
|
|
81
|
+
"canonical_repository_identity": normalize_repository(card.get("repository_identity")),
|
|
82
|
+
"repository_relative_owning_production_path": normalize_path(card.get("owning_path")),
|
|
83
|
+
"owning_production_symbol_or_exported_api": normalize_symbol(card.get("owning_symbol_or_api")),
|
|
84
|
+
"normalized_violated_invariant_signature": {
|
|
85
|
+
"error_or_assertion_class": normalize_invariant_part(
|
|
86
|
+
invariant.get("error_or_assertion_class"), "error_or_assertion_class"
|
|
87
|
+
),
|
|
88
|
+
"operation": normalize_invariant_part(invariant.get("operation"), "operation"),
|
|
89
|
+
"expected_relation": normalize_invariant_part(
|
|
90
|
+
invariant.get("expected_relation"), "expected_relation"
|
|
91
|
+
),
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
except ValueError as error:
|
|
95
|
+
return {"card_id": card_id, "status": "recurrence_key_unassignable", "reason": str(error)}
|
|
96
|
+
return {
|
|
97
|
+
"card_id": card_id,
|
|
98
|
+
"status": "assignable",
|
|
99
|
+
"recurrence_key": key,
|
|
100
|
+
"recurrence_key_sha256": sha256_json(key),
|
|
101
|
+
"compiler": "exact_recurrence_normalization_v1",
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def load_recurrence_card(path: Path) -> dict[str, Any]:
|
|
106
|
+
result = compile_recurrence_card(json.loads(path.read_text(encoding="utf-8")))
|
|
107
|
+
if result.get("status") != "assignable":
|
|
108
|
+
raise ValueError(str(result.get("reason") or "recurrence_key_unassignable"))
|
|
109
|
+
return result
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def validate_behavior_preference(value: object) -> dict[str, Any]:
|
|
113
|
+
if not isinstance(value, dict):
|
|
114
|
+
raise ValueError("behavior card must be a JSON object")
|
|
115
|
+
allowed = {"approach", "invariants_to_preserve", "checks_to_run", "known_nonmatches"}
|
|
116
|
+
if set(value) - allowed:
|
|
117
|
+
raise ValueError(f"behavior card has unknown fields: {sorted(set(value) - allowed)}")
|
|
118
|
+
approach = str(value.get("approach") or "").strip()
|
|
119
|
+
if not approach:
|
|
120
|
+
raise ValueError("behavior approach is required")
|
|
121
|
+
result: dict[str, Any] = {"approach": approach}
|
|
122
|
+
for field in ("invariants_to_preserve", "checks_to_run", "known_nonmatches"):
|
|
123
|
+
items = value.get(field)
|
|
124
|
+
if not isinstance(items, list) or not items or not all(isinstance(item, str) and item.strip() for item in items):
|
|
125
|
+
raise ValueError(f"behavior {field} must be a non-empty string list")
|
|
126
|
+
result[field] = [item.strip() for item in items]
|
|
127
|
+
strings = [approach, *result["invariants_to_preserve"], *result["checks_to_run"], *result["known_nonmatches"]]
|
|
128
|
+
for text in strings:
|
|
129
|
+
if "\n" in text or "\r" in text:
|
|
130
|
+
raise ValueError("behavior entries must be single-line prose")
|
|
131
|
+
if text.startswith(("+", "-")) or any(marker in text for marker in FORBIDDEN_BEHAVIOR_MARKERS):
|
|
132
|
+
raise ValueError("behavior card appears to contain source or patch text")
|
|
133
|
+
rendered = canonical_json(result)
|
|
134
|
+
if len(rendered) > MAX_BEHAVIOR_CHARS:
|
|
135
|
+
raise ValueError(f"behavior card exceeds {MAX_BEHAVIOR_CHARS} characters")
|
|
136
|
+
return result
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def load_behavior_preference(path: Path) -> dict[str, Any]:
|
|
140
|
+
return validate_behavior_preference(json.loads(path.read_text(encoding="utf-8")))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def behavior_overlaps_patch(preference: dict[str, Any], patch_text: str) -> bool:
|
|
144
|
+
haystack = SPACE_RE.sub(" ", patch_text).lower()
|
|
145
|
+
strings = [
|
|
146
|
+
preference["approach"],
|
|
147
|
+
*preference["invariants_to_preserve"],
|
|
148
|
+
*preference["checks_to_run"],
|
|
149
|
+
*preference["known_nonmatches"],
|
|
150
|
+
]
|
|
151
|
+
return any(len(text) >= 20 and SPACE_RE.sub(" ", text).lower() in haystack for text in strings)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def validate_gene_evidence(value: object) -> dict[str, Any]:
|
|
155
|
+
if not isinstance(value, dict):
|
|
156
|
+
raise ValueError("gene evidence must be a JSON object")
|
|
157
|
+
allowed = {"status", "probe_sha256", "hidden_feedback_used", "description"}
|
|
158
|
+
if set(value) - allowed:
|
|
159
|
+
raise ValueError(f"gene evidence has unknown fields: {sorted(set(value) - allowed)}")
|
|
160
|
+
if value.get("status") != "passed":
|
|
161
|
+
raise ValueError("gene evidence status must be passed")
|
|
162
|
+
probe_sha256 = str(value.get("probe_sha256") or "").lower()
|
|
163
|
+
if not SHA256_RE.fullmatch(probe_sha256):
|
|
164
|
+
raise ValueError("gene evidence probe_sha256 must be 64 lowercase hex characters")
|
|
165
|
+
if value.get("hidden_feedback_used") is not False:
|
|
166
|
+
raise ValueError("gene evidence hidden_feedback_used must be false")
|
|
167
|
+
description = str(value.get("description") or "").strip()
|
|
168
|
+
if len(description) > 500 or "\n" in description or "\r" in description:
|
|
169
|
+
raise ValueError("gene evidence description must be at most 500 single-line characters")
|
|
170
|
+
return {
|
|
171
|
+
"status": "passed",
|
|
172
|
+
"probe_sha256": probe_sha256,
|
|
173
|
+
"hidden_feedback_used": False,
|
|
174
|
+
"description": description,
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def load_gene_evidence(path: Path) -> dict[str, Any]:
|
|
179
|
+
raw = path.read_bytes()
|
|
180
|
+
evidence = validate_gene_evidence(json.loads(raw.decode("utf-8")))
|
|
181
|
+
return {**evidence, "artifact_sha256": hashlib.sha256(raw).hexdigest()}
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def task_instance_sha256(task: dict[str, Any]) -> str:
|
|
185
|
+
return sha256_json(
|
|
186
|
+
{
|
|
187
|
+
"description": task.get("description"),
|
|
188
|
+
"acceptance": task.get("acceptance") or [],
|
|
189
|
+
"declared_files": task.get("declared_files") or [],
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def injection_budget_decision(
|
|
195
|
+
context_budget_tokens: int,
|
|
196
|
+
reserved_output_tokens: int,
|
|
197
|
+
base_input_tokens_estimate: int,
|
|
198
|
+
injection_tokens_estimate: int,
|
|
199
|
+
safety_margin_tokens: int = 256,
|
|
200
|
+
) -> dict[str, Any]:
|
|
201
|
+
available = (
|
|
202
|
+
context_budget_tokens
|
|
203
|
+
- reserved_output_tokens
|
|
204
|
+
- base_input_tokens_estimate
|
|
205
|
+
- safety_margin_tokens
|
|
206
|
+
)
|
|
207
|
+
return {
|
|
208
|
+
"fits": available >= injection_tokens_estimate,
|
|
209
|
+
"available_injection_tokens": available,
|
|
210
|
+
"safety_margin_tokens": safety_margin_tokens,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def select_exact_behavior(
|
|
215
|
+
central_events: list[dict[str, Any]], project_scope_id: str, task: dict[str, Any]
|
|
216
|
+
) -> dict[str, Any]:
|
|
217
|
+
recurrence = task.get("recurrence") if isinstance(task.get("recurrence"), dict) else {}
|
|
218
|
+
key_sha = str(recurrence.get("recurrence_key_sha256") or "")
|
|
219
|
+
target_key = recurrence.get("recurrence_key")
|
|
220
|
+
if recurrence.get("status") != "assignable" or not key_sha:
|
|
221
|
+
return {"status": "recurrence_key_unassignable", "fired": False}
|
|
222
|
+
target_instance = task_instance_sha256(task)
|
|
223
|
+
matches: list[dict[str, Any]] = []
|
|
224
|
+
exact_replays = 0
|
|
225
|
+
for event in central_events:
|
|
226
|
+
if event.get("type") != "validated_fix_promoted":
|
|
227
|
+
continue
|
|
228
|
+
payload = event.get("payload") if isinstance(event.get("payload"), dict) else {}
|
|
229
|
+
gene = payload.get("behavior_gene") if isinstance(payload.get("behavior_gene"), dict) else None
|
|
230
|
+
if not gene:
|
|
231
|
+
continue
|
|
232
|
+
if gene.get("project_scope_id") != project_scope_id or gene.get("recurrence_key_sha256") != key_sha:
|
|
233
|
+
continue
|
|
234
|
+
if gene.get("recurrence_key") != target_key:
|
|
235
|
+
continue
|
|
236
|
+
if gene.get("privacy", {}).get("contains_patch_or_source") is not False:
|
|
237
|
+
continue
|
|
238
|
+
try:
|
|
239
|
+
preference = validate_behavior_preference(gene.get("preference"))
|
|
240
|
+
except ValueError:
|
|
241
|
+
continue
|
|
242
|
+
if gene.get("preference_sha256") != sha256_json(preference):
|
|
243
|
+
continue
|
|
244
|
+
if gene.get("source_task_instance_sha256") == target_instance:
|
|
245
|
+
exact_replays += 1
|
|
246
|
+
continue
|
|
247
|
+
matches.append({"event": event, "gene": gene})
|
|
248
|
+
if len(matches) > 1:
|
|
249
|
+
return {"status": "recurrence_key_collision_abstain", "fired": False, "match_count": len(matches)}
|
|
250
|
+
if not matches:
|
|
251
|
+
return {
|
|
252
|
+
"status": "exact_instance_replay_abstain" if exact_replays else "exact_recurrence_miss",
|
|
253
|
+
"fired": False,
|
|
254
|
+
"match_count": 0,
|
|
255
|
+
}
|
|
256
|
+
selected = matches[0]
|
|
257
|
+
return {
|
|
258
|
+
"status": "exact_recurrence_match",
|
|
259
|
+
"fired": True,
|
|
260
|
+
"match_count": 1,
|
|
261
|
+
"source_central_event_sha256": selected["event"].get("event_sha256"),
|
|
262
|
+
"gene": selected["gene"],
|
|
263
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from ..events import EventLog
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
SOURCE_EXTS = {
|
|
13
|
+
".py", ".js", ".jsx", ".ts", ".tsx", ".swift", ".go", ".rs", ".java", ".kt", ".m", ".mm",
|
|
14
|
+
".css", ".scss", ".json", ".yaml", ".yml", ".toml",
|
|
15
|
+
}
|
|
16
|
+
SKIP_PARTS = {"node_modules", ".git", "dist", "build", ".next", "DerivedData", "__pycache__", "vendor"}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def family_for(path: Path, text: str) -> str:
|
|
20
|
+
name = path.name.lower()
|
|
21
|
+
suffix = path.suffix.lower()
|
|
22
|
+
if suffix in {".tsx", ".jsx", ".swift"} and ("view" in name or "component" in text.lower() or "struct " in text):
|
|
23
|
+
return "ui_component"
|
|
24
|
+
if "route" in name or "/api/" in str(path).lower():
|
|
25
|
+
return "api_or_route_handler"
|
|
26
|
+
if suffix in {".json", ".yaml", ".yml", ".toml"}:
|
|
27
|
+
return "config"
|
|
28
|
+
if "test" in name or "spec" in name:
|
|
29
|
+
return "test"
|
|
30
|
+
return "source"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def shape_key(family: str, rel: str, text: str) -> str:
|
|
34
|
+
lines = [line.strip() for line in text.splitlines() if line.strip() and not line.strip().startswith("//")]
|
|
35
|
+
skeleton = "\n".join(lines[:80])
|
|
36
|
+
digest = hashlib.sha256((family + "\n" + skeleton).encode("utf-8", "ignore")).hexdigest()[:24]
|
|
37
|
+
return f"fsm-{digest}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def scan_main(args: Any) -> int:
|
|
41
|
+
root = args.folder.resolve()
|
|
42
|
+
events = EventLog(args.event_log)
|
|
43
|
+
groups: dict[str, list[dict[str, Any]]] = defaultdict(list)
|
|
44
|
+
source_count = 0
|
|
45
|
+
for path in root.rglob("*"):
|
|
46
|
+
if not path.is_file():
|
|
47
|
+
continue
|
|
48
|
+
if any(part in SKIP_PARTS for part in path.parts):
|
|
49
|
+
continue
|
|
50
|
+
if path.suffix.lower() not in SOURCE_EXTS:
|
|
51
|
+
continue
|
|
52
|
+
try:
|
|
53
|
+
text = path.read_text(encoding="utf-8", errors="replace")
|
|
54
|
+
except OSError:
|
|
55
|
+
continue
|
|
56
|
+
source_count += 1
|
|
57
|
+
rel = str(path.relative_to(root))
|
|
58
|
+
family = family_for(path, text)
|
|
59
|
+
key = shape_key(family, rel, text)
|
|
60
|
+
groups[family].append({"path": rel, "shape_key": key, "bytes": len(text.encode("utf-8", "ignore"))})
|
|
61
|
+
candidates = []
|
|
62
|
+
for family, files in groups.items():
|
|
63
|
+
if len(files) < 2:
|
|
64
|
+
continue
|
|
65
|
+
total_bytes = sum(item["bytes"] for item in files)
|
|
66
|
+
candidates.append({
|
|
67
|
+
"family": family,
|
|
68
|
+
"file_count": len(files),
|
|
69
|
+
"score_estimate": len(files) * 10 + min(total_bytes // 1024, 100),
|
|
70
|
+
"evidence": "static_estimate",
|
|
71
|
+
"shape_keys": sorted({item["shape_key"] for item in files})[:8],
|
|
72
|
+
"samples": files[:8],
|
|
73
|
+
})
|
|
74
|
+
candidates.sort(key=lambda item: item["score_estimate"], reverse=True)
|
|
75
|
+
payload = {
|
|
76
|
+
"folder": str(root),
|
|
77
|
+
"source_files": source_count,
|
|
78
|
+
"candidate_count": len(candidates),
|
|
79
|
+
"candidates": candidates,
|
|
80
|
+
}
|
|
81
|
+
args.out.parent.mkdir(parents=True, exist_ok=True)
|
|
82
|
+
args.out.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n")
|
|
83
|
+
events.emit("scan_complete", folder=str(root), source_files=source_count, candidate_count=len(candidates))
|
|
84
|
+
print(json.dumps({"source_files": source_count, "candidate_count": len(candidates), "out": str(args.out)}, indent=2))
|
|
85
|
+
return 0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
import signal
|
|
6
|
+
import subprocess
|
|
7
|
+
import threading
|
|
8
|
+
import time
|
|
9
|
+
import urllib.error
|
|
10
|
+
import urllib.request
|
|
11
|
+
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from ..events import EventLog
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
LOOPBACK = {"127.0.0.1", "localhost", "::1"}
|
|
19
|
+
|
|
20
|
+
HARNESS_SYSTEM_PROMPT = """You are running behind Socra Harness.
|
|
21
|
+
For coding work, prefer direct, complete, editable code.
|
|
22
|
+
Do not include hidden reasoning.
|
|
23
|
+
When asked for code, return clean code or a concise patch-oriented answer.
|
|
24
|
+
Avoid Markdown fences unless the user explicitly asks for them."""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def post_json(url: str, payload: dict[str, Any], timeout: int = 600) -> tuple[int, dict[str, str], bytes]:
|
|
28
|
+
data = json.dumps(payload).encode("utf-8")
|
|
29
|
+
req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"}, method="POST")
|
|
30
|
+
try:
|
|
31
|
+
with urllib.request.urlopen(req, timeout=timeout) as res:
|
|
32
|
+
return res.status, dict(res.headers), res.read()
|
|
33
|
+
except urllib.error.HTTPError as exc:
|
|
34
|
+
return exc.code, dict(exc.headers), exc.read()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_bytes(url: str, timeout: int = 30) -> tuple[int, dict[str, str], bytes]:
|
|
38
|
+
req = urllib.request.Request(url, method="GET")
|
|
39
|
+
try:
|
|
40
|
+
with urllib.request.urlopen(req, timeout=timeout) as res:
|
|
41
|
+
return res.status, dict(res.headers), res.read()
|
|
42
|
+
except urllib.error.HTTPError as exc:
|
|
43
|
+
return exc.code, dict(exc.headers), exc.read()
|
|
44
|
+
except urllib.error.URLError as exc:
|
|
45
|
+
payload = {"error": {"code": 503, "message": str(exc), "type": "backend_unavailable"}}
|
|
46
|
+
return 503, {"Content-Type": "application/json"}, json.dumps(payload).encode("utf-8")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def split_reasoning_text(text: str) -> tuple[str, str]:
|
|
50
|
+
parts: list[str] = []
|
|
51
|
+
|
|
52
|
+
def collect(match: re.Match[str]) -> str:
|
|
53
|
+
parts.append(match.group(1).strip())
|
|
54
|
+
return ""
|
|
55
|
+
|
|
56
|
+
text = re.sub(r"(?is)<think>(.*?)</think>", collect, text)
|
|
57
|
+
text = re.sub(r"(?is)<reasoning>(.*?)</reasoning>", collect, text)
|
|
58
|
+
return text.strip(), "\n\n".join(part for part in parts if part)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def strip_reasoning_text(text: str) -> str:
|
|
62
|
+
cleaned, _reasoning = split_reasoning_text(text)
|
|
63
|
+
return cleaned
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def clean_code_wrappers(text: str) -> tuple[str, str]:
|
|
67
|
+
stripped, reasoning = split_reasoning_text(text)
|
|
68
|
+
fence = re.fullmatch(r"\s*```(?:\w+)?\s*([\s\S]*?)```\s*", stripped)
|
|
69
|
+
if fence:
|
|
70
|
+
return fence.group(1).strip("\n"), reasoning
|
|
71
|
+
return stripped, reasoning
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def apply_socra_response_harness(body: dict[str, Any]) -> tuple[dict[str, Any], bool]:
|
|
75
|
+
changed = False
|
|
76
|
+
for choice in body.get("choices", []):
|
|
77
|
+
message = choice.get("message")
|
|
78
|
+
if not isinstance(message, dict):
|
|
79
|
+
continue
|
|
80
|
+
content = message.get("content")
|
|
81
|
+
if isinstance(content, str):
|
|
82
|
+
cleaned, extracted_reasoning = clean_code_wrappers(content)
|
|
83
|
+
if cleaned != content:
|
|
84
|
+
message["content"] = cleaned
|
|
85
|
+
changed = True
|
|
86
|
+
if extracted_reasoning and not isinstance(message.get("reasoning_content"), str):
|
|
87
|
+
message["reasoning_content"] = extracted_reasoning
|
|
88
|
+
changed = True
|
|
89
|
+
reasoning = message.get("reasoning_content")
|
|
90
|
+
if isinstance(reasoning, str) and not reasoning.strip():
|
|
91
|
+
message.pop("reasoning_content", None)
|
|
92
|
+
changed = True
|
|
93
|
+
return body, changed
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def apply_socra_request_harness(body: dict[str, Any], model_alias: str) -> tuple[dict[str, Any], bool]:
|
|
97
|
+
patched = dict(body)
|
|
98
|
+
patched["model"] = model_alias
|
|
99
|
+
messages = list(patched.get("messages") or [])
|
|
100
|
+
has_system = any(message.get("role") == "system" for message in messages if isinstance(message, dict))
|
|
101
|
+
if not has_system:
|
|
102
|
+
messages.insert(0, {"role": "system", "content": HARNESS_SYSTEM_PROMPT})
|
|
103
|
+
patched["messages"] = messages
|
|
104
|
+
return patched, patched != body
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class SocraProxyHandler(BaseHTTPRequestHandler):
|
|
108
|
+
server: "SocraProxyServer"
|
|
109
|
+
|
|
110
|
+
def log_message(self, fmt: str, *args: Any) -> None:
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
def write_json(self, status: int, payload: dict[str, Any]) -> None:
|
|
114
|
+
data = json.dumps(payload).encode("utf-8")
|
|
115
|
+
self.send_response(status)
|
|
116
|
+
self.send_header("Content-Type", "application/json; charset=utf-8")
|
|
117
|
+
self.send_header("Content-Length", str(len(data)))
|
|
118
|
+
self.send_header("X-Socra-Harness", "active")
|
|
119
|
+
self.end_headers()
|
|
120
|
+
self.wfile.write(data)
|
|
121
|
+
|
|
122
|
+
def read_json(self) -> dict[str, Any]:
|
|
123
|
+
length = int(self.headers.get("Content-Length", "0"))
|
|
124
|
+
raw = self.rfile.read(length) if length else b"{}"
|
|
125
|
+
return json.loads(raw.decode("utf-8") or "{}")
|
|
126
|
+
|
|
127
|
+
def do_GET(self) -> None:
|
|
128
|
+
if self.path == "/health":
|
|
129
|
+
self.write_json(200, {"status": "ready", "backend": self.server.backend_url, "model": self.server.model_alias})
|
|
130
|
+
return
|
|
131
|
+
if self.path == "/runtime/stats":
|
|
132
|
+
self.write_json(200, self.server.metrics)
|
|
133
|
+
return
|
|
134
|
+
if self.path == "/v1/models":
|
|
135
|
+
status, _headers, data = get_bytes(f"{self.server.backend_url}/v1/models")
|
|
136
|
+
self.send_response(status)
|
|
137
|
+
self.send_header("Content-Type", "application/json; charset=utf-8")
|
|
138
|
+
self.send_header("X-Socra-Harness", "active")
|
|
139
|
+
self.end_headers()
|
|
140
|
+
self.wfile.write(data)
|
|
141
|
+
return
|
|
142
|
+
self.write_json(404, {"error": "not found"})
|
|
143
|
+
|
|
144
|
+
def do_POST(self) -> None:
|
|
145
|
+
if self.path != "/v1/chat/completions":
|
|
146
|
+
self.write_json(404, {"error": "not found"})
|
|
147
|
+
return
|
|
148
|
+
body = self.read_json()
|
|
149
|
+
stream = bool(body.get("stream"))
|
|
150
|
+
patched, request_changed = apply_socra_request_harness(body, self.server.model_alias)
|
|
151
|
+
self.server.metrics["chat_requests_total"] += 1
|
|
152
|
+
if request_changed:
|
|
153
|
+
self.server.metrics["request_harness_applied_total"] += 1
|
|
154
|
+
self.server.events.emit("chat_request", stream=stream, request_harness=request_changed)
|
|
155
|
+
|
|
156
|
+
if stream:
|
|
157
|
+
status, headers, data = post_json(f"{self.server.backend_url}/v1/chat/completions", patched)
|
|
158
|
+
self.send_response(status)
|
|
159
|
+
self.send_header("Content-Type", headers.get("Content-Type", "text/event-stream"))
|
|
160
|
+
self.send_header("X-Socra-Harness", "active")
|
|
161
|
+
self.send_header("X-Socra-Mode", "stream_passthrough")
|
|
162
|
+
self.end_headers()
|
|
163
|
+
self.wfile.write(data)
|
|
164
|
+
self.server.metrics["stream_passthrough_total"] += 1
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
status, _headers, data = post_json(f"{self.server.backend_url}/v1/chat/completions", patched)
|
|
168
|
+
try:
|
|
169
|
+
payload = json.loads(data.decode("utf-8"))
|
|
170
|
+
except json.JSONDecodeError:
|
|
171
|
+
self.send_response(status)
|
|
172
|
+
self.send_header("Content-Type", "text/plain; charset=utf-8")
|
|
173
|
+
self.send_header("X-Socra-Harness", "active")
|
|
174
|
+
self.end_headers()
|
|
175
|
+
self.wfile.write(data)
|
|
176
|
+
return
|
|
177
|
+
payload, response_changed = apply_socra_response_harness(payload)
|
|
178
|
+
if response_changed:
|
|
179
|
+
self.server.metrics["response_harness_applied_total"] += 1
|
|
180
|
+
self.server.events.emit("chat_response", status=status, response_harness=response_changed)
|
|
181
|
+
self.write_json(status, payload)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
class SocraProxyServer(ThreadingHTTPServer):
|
|
185
|
+
def __init__(self, addr: tuple[str, int], backend_url: str, model_alias: str, events: EventLog):
|
|
186
|
+
super().__init__(addr, SocraProxyHandler)
|
|
187
|
+
self.backend_url = backend_url.rstrip("/")
|
|
188
|
+
self.model_alias = model_alias
|
|
189
|
+
self.events = events
|
|
190
|
+
self.metrics = {
|
|
191
|
+
"local_first_enforced": True,
|
|
192
|
+
"hosted_fallback_total": 0,
|
|
193
|
+
"external_code_requests_total": 0,
|
|
194
|
+
"chat_requests_total": 0,
|
|
195
|
+
"request_harness_applied_total": 0,
|
|
196
|
+
"response_harness_applied_total": 0,
|
|
197
|
+
"stream_passthrough_total": 0,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def wait_for_backend(url: str, timeout_seconds: int = 120) -> bool:
|
|
202
|
+
deadline = time.time() + timeout_seconds
|
|
203
|
+
while time.time() < deadline:
|
|
204
|
+
try:
|
|
205
|
+
status, _headers, _data = get_bytes(f"{url}/v1/models", timeout=5)
|
|
206
|
+
if status < 500:
|
|
207
|
+
return True
|
|
208
|
+
except Exception:
|
|
209
|
+
pass
|
|
210
|
+
time.sleep(1)
|
|
211
|
+
return False
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def serve_main(args: Any) -> int:
|
|
215
|
+
if args.host not in LOOPBACK:
|
|
216
|
+
raise SystemExit("Socra Harness is local-first: --host must be loopback")
|
|
217
|
+
if args.backend_host not in LOOPBACK:
|
|
218
|
+
raise SystemExit("Socra Harness is local-first: --backend-host must be loopback")
|
|
219
|
+
|
|
220
|
+
events = EventLog(args.event_log)
|
|
221
|
+
state_dir = args.event_log.parent
|
|
222
|
+
state_dir.mkdir(parents=True, exist_ok=True)
|
|
223
|
+
model_alias = args.alias or Path(args.model).stem
|
|
224
|
+
backend_url = f"http://{args.backend_host}:{args.backend_port}"
|
|
225
|
+
frontend_url = f"http://{args.host}:{args.port}"
|
|
226
|
+
|
|
227
|
+
state = {
|
|
228
|
+
"model": str(args.model),
|
|
229
|
+
"model_alias": model_alias,
|
|
230
|
+
"llama_server": str(args.llama_server),
|
|
231
|
+
"host": args.host,
|
|
232
|
+
"port": args.port,
|
|
233
|
+
"endpoint": f"{frontend_url}/v1",
|
|
234
|
+
"backend_endpoint": f"{backend_url}/v1",
|
|
235
|
+
"local_first": True,
|
|
236
|
+
"hosted_fallback": False,
|
|
237
|
+
"harness": "socra_request_response",
|
|
238
|
+
}
|
|
239
|
+
(state_dir / "server-state.json").write_text(json.dumps(state, indent=2) + "\n")
|
|
240
|
+
events.emit("server_start", **state)
|
|
241
|
+
|
|
242
|
+
backend = None
|
|
243
|
+
if not getattr(args, "reuse_backend", False):
|
|
244
|
+
cmd = [
|
|
245
|
+
str(args.llama_server),
|
|
246
|
+
"-m",
|
|
247
|
+
str(args.model),
|
|
248
|
+
"--host",
|
|
249
|
+
args.backend_host,
|
|
250
|
+
"--port",
|
|
251
|
+
str(args.backend_port),
|
|
252
|
+
"--ctx-size",
|
|
253
|
+
str(args.ctx_size),
|
|
254
|
+
"--gpu-layers",
|
|
255
|
+
str(args.gpu_layers),
|
|
256
|
+
]
|
|
257
|
+
print("Starting backend llama-server:")
|
|
258
|
+
print(" ".join(cmd))
|
|
259
|
+
backend = subprocess.Popen(cmd)
|
|
260
|
+
else:
|
|
261
|
+
print(f"Reusing existing backend llama-server at {backend_url}")
|
|
262
|
+
|
|
263
|
+
def stop_backend(*_: Any) -> None:
|
|
264
|
+
if backend is not None and backend.poll() is None:
|
|
265
|
+
backend.terminate()
|
|
266
|
+
|
|
267
|
+
signal.signal(signal.SIGINT, stop_backend)
|
|
268
|
+
signal.signal(signal.SIGTERM, stop_backend)
|
|
269
|
+
|
|
270
|
+
if not wait_for_backend(backend_url):
|
|
271
|
+
stop_backend()
|
|
272
|
+
raise SystemExit(f"backend did not become ready: {backend_url}")
|
|
273
|
+
|
|
274
|
+
print(f"Socra Harness endpoint: {frontend_url}/v1")
|
|
275
|
+
print("Use this endpoint for Codex/vibe coding tools. Press Ctrl+C to stop.")
|
|
276
|
+
server = SocraProxyServer((args.host, args.port), backend_url, model_alias, events)
|
|
277
|
+
try:
|
|
278
|
+
thread = threading.Thread(target=server.serve_forever, daemon=True)
|
|
279
|
+
thread.start()
|
|
280
|
+
if backend is None:
|
|
281
|
+
while True:
|
|
282
|
+
time.sleep(0.5)
|
|
283
|
+
while backend.poll() is None:
|
|
284
|
+
time.sleep(0.5)
|
|
285
|
+
except KeyboardInterrupt:
|
|
286
|
+
pass
|
|
287
|
+
finally:
|
|
288
|
+
server.shutdown()
|
|
289
|
+
stop_backend()
|
|
290
|
+
if backend is not None:
|
|
291
|
+
backend.wait(timeout=10)
|
|
292
|
+
events.emit("server_stop", model=model_alias)
|
|
293
|
+
return 0
|