cortex-loop 0.1.0a1__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.
Files changed (52) hide show
  1. cortex/__init__.py +7 -0
  2. cortex/adapters.py +339 -0
  3. cortex/blocklist.py +51 -0
  4. cortex/challenges.py +210 -0
  5. cortex/cli.py +7 -0
  6. cortex/core.py +601 -0
  7. cortex/core_helpers.py +190 -0
  8. cortex/data/identity_preamble.md +5 -0
  9. cortex/data/layer1_part_a.md +65 -0
  10. cortex/data/layer1_part_b.md +17 -0
  11. cortex/executive.py +295 -0
  12. cortex/foundation.py +185 -0
  13. cortex/genome.py +348 -0
  14. cortex/graveyard.py +226 -0
  15. cortex/hooks/__init__.py +27 -0
  16. cortex/hooks/_shared.py +167 -0
  17. cortex/hooks/post_tool_use.py +13 -0
  18. cortex/hooks/pre_tool_use.py +13 -0
  19. cortex/hooks/session_start.py +13 -0
  20. cortex/hooks/stop.py +13 -0
  21. cortex/invariants.py +258 -0
  22. cortex/packs.py +118 -0
  23. cortex/repomap.py +6 -0
  24. cortex/requirements.py +497 -0
  25. cortex/retry.py +312 -0
  26. cortex/stop_contract.py +217 -0
  27. cortex/stop_payload.py +122 -0
  28. cortex/stop_policy.py +100 -0
  29. cortex/stop_runtime.py +400 -0
  30. cortex/stop_signals.py +75 -0
  31. cortex/store.py +793 -0
  32. cortex/templates/__init__.py +10 -0
  33. cortex/utils.py +58 -0
  34. cortex_loop-0.1.0a1.dist-info/METADATA +121 -0
  35. cortex_loop-0.1.0a1.dist-info/RECORD +52 -0
  36. cortex_loop-0.1.0a1.dist-info/WHEEL +5 -0
  37. cortex_loop-0.1.0a1.dist-info/entry_points.txt +3 -0
  38. cortex_loop-0.1.0a1.dist-info/licenses/LICENSE +21 -0
  39. cortex_loop-0.1.0a1.dist-info/top_level.txt +3 -0
  40. cortex_ops_cli/__init__.py +3 -0
  41. cortex_ops_cli/_adapter_validation.py +119 -0
  42. cortex_ops_cli/_check_report.py +454 -0
  43. cortex_ops_cli/_check_report_output.py +270 -0
  44. cortex_ops_cli/_openai_bridge_probe.py +241 -0
  45. cortex_ops_cli/_openai_bridge_protocol.py +469 -0
  46. cortex_ops_cli/_runtime_profile_templates.py +341 -0
  47. cortex_ops_cli/_runtime_profiles.py +445 -0
  48. cortex_ops_cli/gemini_hooks.py +301 -0
  49. cortex_ops_cli/main.py +911 -0
  50. cortex_ops_cli/openai_app_server_bridge.py +375 -0
  51. cortex_repomap/__init__.py +1 -0
  52. cortex_repomap/engine.py +1201 -0
@@ -0,0 +1,301 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import hashlib
5
+ import json
6
+ import sqlite3
7
+ import sys
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from cortex.core import CortexKernel
12
+ from cortex.executive import get_base_executive_function
13
+
14
+ KERNEL_EVENT_NAMES = {"SessionStart", "BeforeTool", "AfterTool", "AfterAgent"}
15
+ RETRY_STOP_REASON = "Cortex stop path failed after retry. Manual review required."
16
+
17
+
18
+ def main(argv: list[str] | None = None) -> int:
19
+ args = _parse_args(argv)
20
+ try:
21
+ payload = _read_payload()
22
+ payload = _ensure_session_id(payload, event=args.event)
23
+ except Exception as exc: # noqa: BLE001
24
+ print(f"[cortex] Gemini bridge error: {exc}", file=sys.stderr)
25
+ return 1
26
+
27
+ if args.event not in KERNEL_EVENT_NAMES:
28
+ if args.event == "BeforeAgent":
29
+ print(json.dumps(_before_agent_output(payload)))
30
+ return 0
31
+ print(json.dumps({}))
32
+ return 0
33
+
34
+ try:
35
+ prior_retry_pending = False
36
+ if args.event == "AfterAgent":
37
+ prior_retry_pending = _session_has_pending_after_agent_retry(
38
+ root=Path(args.root),
39
+ db_path=args.db_path,
40
+ session_id=str(payload.get("session_id") or "").strip(),
41
+ )
42
+ kernel = CortexKernel(root=args.root, config_path=args.config_path, db_path=args.db_path)
43
+ result = kernel.dispatch(args.event, payload)
44
+ print(
45
+ json.dumps(
46
+ _to_gemini_output(
47
+ event=args.event,
48
+ payload=payload,
49
+ result=result,
50
+ prior_retry_pending=prior_retry_pending,
51
+ )
52
+ )
53
+ )
54
+ return 0
55
+ except Exception as exc: # noqa: BLE001
56
+ print(f"[cortex] Gemini bridge error: {exc}", file=sys.stderr)
57
+ return 1
58
+
59
+
60
+ def _parse_args(argv: list[str] | None) -> argparse.Namespace:
61
+ parser = argparse.ArgumentParser(add_help=False)
62
+ parser.add_argument("event")
63
+ parser.add_argument("--root", default=".")
64
+ parser.add_argument("--config-path")
65
+ parser.add_argument("--db-path")
66
+ return parser.parse_args(argv)
67
+
68
+
69
+ def _read_payload() -> dict[str, Any]:
70
+ raw = sys.stdin.read().strip()
71
+ if not raw:
72
+ return {}
73
+ data = json.loads(raw)
74
+ if not isinstance(data, dict):
75
+ raise ValueError("Gemini hook payload must be a JSON object")
76
+ return data
77
+
78
+
79
+ def _to_gemini_output(
80
+ *,
81
+ event: str,
82
+ payload: dict[str, Any],
83
+ result: dict[str, Any],
84
+ prior_retry_pending: bool = False,
85
+ ) -> dict[str, Any]:
86
+ warnings = [str(item).strip() for item in (result.get("warnings") or []) if str(item).strip()]
87
+ if event == "SessionStart":
88
+ return _session_start_output(result=result, warnings=warnings)
89
+ proceed = bool(result.get("proceed", True))
90
+ if event == "AfterAgent" and _is_stuck_result(result):
91
+ reason = _stuck_reason(result, warnings=warnings)
92
+ return _attach_advisories(
93
+ {"continue": False, "stopReason": reason},
94
+ warnings=warnings,
95
+ primary=reason,
96
+ )
97
+ if event == "AfterAgent" and _needs_after_agent_retry(result, proceed=proceed):
98
+ reason = _retry_reason_from_result(result, warnings=warnings)
99
+ if _requires_session_stop(result):
100
+ return _attach_advisories(
101
+ {"continue": False, "stopReason": reason},
102
+ warnings=warnings,
103
+ primary=reason,
104
+ )
105
+ if bool(payload.get("stop_hook_active")) or prior_retry_pending:
106
+ return _attach_advisories(
107
+ {"continue": False, "stopReason": RETRY_STOP_REASON},
108
+ warnings=warnings,
109
+ primary=RETRY_STOP_REASON,
110
+ )
111
+ return _attach_advisories({"decision": "deny", "reason": reason}, warnings=warnings, primary=reason)
112
+ if not proceed:
113
+ reason = _primary_reason(event=event, warnings=warnings, result=result)
114
+ return _attach_advisories({"decision": "deny", "reason": reason}, warnings=warnings, primary=reason)
115
+ if warnings:
116
+ return {"systemMessage": _warnings_message(warnings)}
117
+ return {}
118
+
119
+
120
+ def _before_agent_output(payload: dict[str, Any]) -> dict[str, Any]:
121
+ _part_a, part_b = get_base_executive_function()
122
+ if _payload_already_contains_anchor(payload, part_b):
123
+ return {}
124
+ return {"hookSpecificOutput": {"additionalContext": part_b}}
125
+
126
+
127
+ def _payload_already_contains_anchor(payload: dict[str, Any], anchor: str) -> bool:
128
+ if not anchor:
129
+ return False
130
+ candidates = [payload.get("prompt"), payload.get("message"), payload.get("input")]
131
+ for candidate in candidates:
132
+ if isinstance(candidate, str) and anchor in candidate:
133
+ return True
134
+ return False
135
+
136
+
137
+ def _session_start_output(*, result: dict[str, Any], warnings: list[str]) -> dict[str, Any]:
138
+ response: dict[str, Any] = {}
139
+ raw_blocks = result.get("context_blocks")
140
+ context_blocks: list[str] = []
141
+ if isinstance(raw_blocks, list):
142
+ context_blocks = [str(item).strip() for item in raw_blocks if isinstance(item, str) and item.strip()]
143
+ if context_blocks:
144
+ response["hookSpecificOutput"] = {"additionalContext": "\n\n".join(context_blocks)}
145
+ if warnings:
146
+ response["systemMessage"] = _warnings_message(warnings)
147
+ return response
148
+
149
+
150
+ def _requires_session_stop(result: dict[str, Any]) -> bool:
151
+ if _is_stuck_result(result):
152
+ return True
153
+ if bool(result.get("terminate_session")):
154
+ return True
155
+ invariant_report = result.get("invariant_report")
156
+ if isinstance(invariant_report, dict) and invariant_report.get("ok") is False:
157
+ return True
158
+ return False
159
+
160
+
161
+ def _is_stuck_result(result: dict[str, Any]) -> bool:
162
+ return bool(result.get("stuck_declared")) or str(result.get("feedback_mode") or "") == "stuck"
163
+
164
+
165
+ def _needs_after_agent_retry(result: dict[str, Any], *, proceed: bool) -> bool:
166
+ if not proceed:
167
+ return True
168
+ if bool(result.get("structured_stop_violation")):
169
+ return True
170
+ if bool(result.get("challenge_coverage_missing")):
171
+ return True
172
+ if bool(result.get("requirements_gate_gap")):
173
+ return True
174
+ challenge_report = result.get("challenge_report")
175
+ if isinstance(challenge_report, dict) and challenge_report.get("ok") is False:
176
+ return True
177
+ return False
178
+
179
+
180
+ def _retry_reason_from_result(result: dict[str, Any], *, warnings: list[str]) -> str:
181
+ if bool(result.get("structured_stop_violation")):
182
+ return "Structured stop fields are required. Include STOP_FIELDS_JSON in the final response."
183
+ challenge_report = result.get("challenge_report")
184
+ if isinstance(challenge_report, dict) and isinstance(challenge_report.get("missing_categories"), list):
185
+ missing = [str(item).strip() for item in challenge_report["missing_categories"] if str(item).strip()]
186
+ if missing:
187
+ return "Missing challenge coverage for: " + ", ".join(missing)
188
+ if bool(result.get("challenge_coverage_missing")):
189
+ return "Missing challenge_coverage in stop fields. Include all active challenge categories."
190
+ if bool(result.get("requirements_gate_gap")):
191
+ requirement_report = result.get("requirement_audit_report")
192
+ if isinstance(requirement_report, dict):
193
+ req_errors = [str(item).strip() for item in (requirement_report.get("errors") or []) if str(item).strip()]
194
+ if req_errors:
195
+ return "Requirement evidence gaps: " + "; ".join(req_errors[:2])
196
+ truth_claims_report = result.get("truth_claims_report")
197
+ if isinstance(truth_claims_report, dict):
198
+ truth_errors = [str(item).strip() for item in (truth_claims_report.get("errors") or []) if str(item).strip()]
199
+ if truth_errors:
200
+ return "Truth-claim evidence gaps: " + "; ".join(truth_errors[:2])
201
+ if warnings:
202
+ return warnings[0]
203
+ if bool(result.get("requirements_gate_gap")):
204
+ return "Requirement/truth claims are incomplete or unverified. Provide explicit evidence in stop fields."
205
+ return "Cortex stop path failed."
206
+
207
+
208
+ def _stuck_reason(result: dict[str, Any], *, warnings: list[str]) -> str:
209
+ stuck = result.get("stuck_declaration")
210
+ if isinstance(stuck, dict):
211
+ check = str(stuck.get("check") or "").strip()
212
+ obstacle = str(stuck.get("obstacle") or "").strip()
213
+ if check and obstacle:
214
+ return f"Cortex reported stuck on {check}: {obstacle}"
215
+ if obstacle:
216
+ return f"Cortex reported stuck: {obstacle}"
217
+ if warnings:
218
+ return warnings[0]
219
+ return "Cortex reported stuck and could not complete the requested evidence boundary."
220
+
221
+
222
+ def _primary_reason(*, event: str, warnings: list[str], result: dict[str, Any]) -> str:
223
+ if warnings:
224
+ return warnings[0]
225
+ if event == "AfterAgent":
226
+ return "Cortex stop path failed."
227
+ if event == "BeforeTool":
228
+ return "Cortex blocked this tool invocation."
229
+ return f"Cortex denied {event}."
230
+
231
+
232
+ def _warnings_message(warnings: list[str]) -> str:
233
+ return "\n".join(f"[cortex] {warning}" for warning in warnings)
234
+
235
+
236
+ def _attach_advisories(response: dict[str, Any], *, warnings: list[str], primary: str) -> dict[str, Any]:
237
+ additional = [warning for warning in warnings if warning and warning != primary]
238
+ if additional:
239
+ response["systemMessage"] = _warnings_message(additional)
240
+ return response
241
+
242
+
243
+ def _session_has_pending_after_agent_retry(*, root: Path, db_path: str | None, session_id: str) -> bool:
244
+ if not session_id:
245
+ return False
246
+ db_file = Path(db_path) if db_path else (root / ".cortex" / "cortex.db")
247
+ if not db_file.exists():
248
+ return False
249
+ try:
250
+ with sqlite3.connect(db_file) as conn:
251
+ row = conn.execute(
252
+ "SELECT metadata_json FROM sessions WHERE session_id = ? LIMIT 1",
253
+ (session_id,),
254
+ ).fetchone()
255
+ except sqlite3.Error:
256
+ return False
257
+ if not row or not row[0]:
258
+ return False
259
+ try:
260
+ metadata = json.loads(str(row[0]))
261
+ except (json.JSONDecodeError, TypeError, ValueError):
262
+ return False
263
+ if not isinstance(metadata, dict) or str(metadata.get("hook") or "") != "Stop":
264
+ return False
265
+ if bool(metadata.get("stuck_declared")) or str(metadata.get("feedback_mode") or "") == "stuck":
266
+ return False
267
+ challenge_ok = metadata.get("challenge_ok")
268
+ return (
269
+ bool(metadata.get("structured_stop_violation"))
270
+ or bool(metadata.get("challenge_coverage_missing"))
271
+ or bool(metadata.get("requirements_gate_gap"))
272
+ or challenge_ok is False
273
+ )
274
+
275
+
276
+ def _ensure_session_id(payload: dict[str, Any], *, event: str) -> dict[str, Any]:
277
+ data = dict(payload)
278
+ session_id = str(data.get("session_id") or "").strip()
279
+ if session_id:
280
+ data["session_id"] = session_id
281
+ return data
282
+ basis = "|".join(
283
+ (
284
+ event,
285
+ str(data.get("timestamp") or ""),
286
+ str(data.get("transcript_path") or ""),
287
+ str(data.get("cwd") or ""),
288
+ str(data.get("hook_event_name") or ""),
289
+ )
290
+ )
291
+ fallback = "gemini-fallback-" + hashlib.sha1(basis.encode("utf-8")).hexdigest()[:12]
292
+ data["session_id"] = fallback
293
+ print(
294
+ f"[cortex] warning: Gemini payload missing session_id for {event}; using {fallback}.",
295
+ file=sys.stderr,
296
+ )
297
+ return data
298
+
299
+
300
+ if __name__ == "__main__":
301
+ raise SystemExit(main())