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,375 @@
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ import shlex
6
+ import subprocess
7
+ import sys
8
+ import time
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ from cortex.core import CortexKernel
13
+ from cortex.stop_payload import parse_stop_fields_json
14
+
15
+ from ._openai_bridge_probe import probe_approval_blocking as _probe_approval_blocking_impl
16
+ from ._openai_bridge_probe import probe_model as _probe_model_impl
17
+ from ._openai_bridge_protocol import (
18
+ AppServerClient,
19
+ BridgeError,
20
+ COMMAND_APPROVAL_METHOD,
21
+ DEFAULT_APPROVAL_POLICY_CANDIDATES,
22
+ FILE_CHANGE_APPROVAL_METHOD,
23
+ execute_turn as _protocol_execute_turn,
24
+ initialize_app_server as _initialize_app_server,
25
+ start_thread_with_policy_fallback,
26
+ )
27
+
28
+ SCHEMA_VERSION = "openai_app_server_v1"
29
+ _start_thread_with_policy_fallback = start_thread_with_policy_fallback
30
+
31
+
32
+ _STOP_RESULT_FORWARD_KEYS = (
33
+ "session_status",
34
+ "proceed",
35
+ "recommend_revert",
36
+ "feedback_mode",
37
+ "stuck_declared",
38
+ "stuck_declaration",
39
+ "structured_stop_violation",
40
+ "challenge_coverage_missing",
41
+ "requirement_audit_gap",
42
+ "truth_claims_gap",
43
+ "requirements_gate_gap",
44
+ "contract_diagnostic",
45
+ )
46
+
47
+
48
+ def _extract_stop_fields_from_final_text(final_text: str) -> tuple[dict[str, Any] | None, str, str]:
49
+ parsed, marker_found, parse_error = parse_stop_fields_json(final_text)
50
+ if parsed is not None:
51
+ return dict(parsed), "payload.stop_fields", ""
52
+ if marker_found:
53
+ return None, "none", str(parse_error or "invalid_stop_fields_json")
54
+ return None, "none", ""
55
+
56
+
57
+ def _bridge_stop_summary(stop_result: dict[str, Any]) -> dict[str, Any]:
58
+ summary = {"enforcement_pass": bool(stop_result.get("enforcement_pass"))}
59
+ warnings = stop_result.get("warnings")
60
+ if isinstance(warnings, list):
61
+ normalized_warnings = [str(item) for item in warnings if str(item).strip()]
62
+ if normalized_warnings:
63
+ summary["warnings"] = normalized_warnings
64
+ for key in _STOP_RESULT_FORWARD_KEYS:
65
+ if key in stop_result:
66
+ summary[key] = stop_result[key]
67
+ return summary
68
+
69
+
70
+ def _kernel_pretool_decision(
71
+ *,
72
+ kernel: CortexKernel,
73
+ session_id: str,
74
+ method: str,
75
+ params: dict[str, Any],
76
+ ) -> tuple[bool, dict[str, Any]]:
77
+ if method == COMMAND_APPROVAL_METHOD:
78
+ command = str(params.get("command") or "")
79
+ tool_name = "command_execution"
80
+ elif method == FILE_CHANGE_APPROVAL_METHOD:
81
+ command = "file_change"
82
+ tool_name = "file_change"
83
+ else:
84
+ return True, {"warnings": [f"unhandled_approval_method:{method}"]}
85
+
86
+ kernel_response = kernel.dispatch(
87
+ "pre_tool_use",
88
+ {
89
+ "session_id": session_id,
90
+ "tool_name": tool_name,
91
+ "command": command,
92
+ "approval_method": method,
93
+ },
94
+ )
95
+ return bool(kernel_response.get("proceed", True)), kernel_response
96
+
97
+
98
+ def _handle_post_tool(
99
+ *,
100
+ kernel: CortexKernel,
101
+ session_id: str,
102
+ item: dict[str, Any],
103
+ ) -> None:
104
+ if str(item.get("type") or "") != "commandExecution":
105
+ return
106
+ status = str(item.get("status") or "").strip().lower()
107
+ mapped_status = "ok"
108
+ if status in {"failed"}:
109
+ mapped_status = "error"
110
+ elif status in {"declined"}:
111
+ mapped_status = "declined"
112
+ kernel.dispatch(
113
+ "post_tool_use",
114
+ {
115
+ "session_id": session_id,
116
+ "tool_name": "command_execution",
117
+ "status": mapped_status,
118
+ "tool_response": {
119
+ "stdout": str(item.get("aggregatedOutput") or ""),
120
+ "stderr": "",
121
+ "exit_code": item.get("exitCode"),
122
+ },
123
+ "command": str(item.get("command") or ""),
124
+ "cwd": str(item.get("cwd") or ""),
125
+ "raw_status": status,
126
+ },
127
+ )
128
+
129
+
130
+ def _normalize_command_for_witness(command: str) -> str:
131
+ raw = str(command or "").strip()
132
+ if not raw:
133
+ return ""
134
+ try:
135
+ tokens = shlex.split(raw)
136
+ except ValueError:
137
+ return raw
138
+ if len(tokens) >= 3 and Path(tokens[0]).name.lower() in {"bash", "sh", "zsh"} and tokens[1] == "-lc":
139
+ inner = str(tokens[2]).strip()
140
+ return inner or raw
141
+ return raw
142
+
143
+
144
+ def _execute_turn(
145
+ *,
146
+ codex_bin: str,
147
+ cwd: Path,
148
+ prompt: str,
149
+ model: str | None,
150
+ timeout_seconds: float,
151
+ approval_policy_candidates: tuple[str, ...] = DEFAULT_APPROVAL_POLICY_CANDIDATES,
152
+ approval_handler: Any,
153
+ ) -> dict[str, Any]:
154
+ return _protocol_execute_turn(
155
+ codex_bin=codex_bin,
156
+ cwd=cwd,
157
+ prompt=prompt,
158
+ model=model,
159
+ timeout_seconds=timeout_seconds,
160
+ approval_policy_candidates=approval_policy_candidates,
161
+ approval_handler=approval_handler,
162
+ client_cls=AppServerClient,
163
+ )
164
+
165
+
166
+ def _run_mode(args: argparse.Namespace) -> int:
167
+ cwd = Path(args.cwd).resolve()
168
+ kernel = CortexKernel(root=args.root, config_path=args.config_path, db_path=args.db_path)
169
+ coverage_gaps: list[str] = []
170
+ session_id_holder: dict[str, str] = {"value": ""}
171
+
172
+ def _approval_handler(method: str, params: dict[str, Any]) -> tuple[str, dict[str, Any]]:
173
+ thread_id = str(params.get("threadId") or "").strip()
174
+ if thread_id:
175
+ session_id_holder["value"] = thread_id
176
+ session_id = session_id_holder["value"] or thread_id or f"openai-session-{int(time.time())}"
177
+ proceed, kernel_response = _kernel_pretool_decision(
178
+ kernel=kernel,
179
+ session_id=session_id,
180
+ method=method,
181
+ params=params,
182
+ )
183
+ decision = "accept" if proceed else "decline"
184
+ if method not in {COMMAND_APPROVAL_METHOD, FILE_CHANGE_APPROVAL_METHOD}:
185
+ coverage_gaps.append(f"pre_tool_use_coverage_gap:{method}")
186
+ return decision, kernel_response
187
+
188
+ result = _execute_turn(
189
+ codex_bin=args.codex_bin,
190
+ cwd=cwd,
191
+ prompt=args.prompt,
192
+ model=args.model,
193
+ timeout_seconds=float(args.timeout_seconds),
194
+ approval_policy_candidates=_approval_policy_candidates_from_args(args),
195
+ approval_handler=_approval_handler,
196
+ )
197
+
198
+ command_surface = result.get("command_surface") if isinstance(result.get("command_surface"), dict) else {}
199
+ command_items_without_approval = [
200
+ str(item)
201
+ for item in command_surface.get("command_items_without_approval", [])
202
+ if str(item).strip()
203
+ ]
204
+ nonblocking_declines = [str(item) for item in command_surface.get("nonblocking_declines", []) if str(item).strip()]
205
+ if command_items_without_approval:
206
+ coverage_gaps.append("pre_tool_use_partial_surface_trusted_commands")
207
+ if nonblocking_declines:
208
+ coverage_gaps.append("pre_tool_use_nonblocking_approval")
209
+
210
+ session_id = session_id_holder["value"] or str(result.get("thread_id") or "")
211
+ approval_command_by_item_id: dict[str, dict[str, str]] = {}
212
+ for request in result.get("approval_requests") or []:
213
+ if not isinstance(request, dict):
214
+ continue
215
+ item_id = str(request.get("item_id") or "").strip()
216
+ if not item_id:
217
+ continue
218
+ approval_command_by_item_id[item_id] = {
219
+ "command": str(request.get("command") or "").strip(),
220
+ "cwd": str(request.get("cwd") or "").strip(),
221
+ }
222
+
223
+ for item in result.get("command_completion_items") or []:
224
+ if isinstance(item, dict):
225
+ item_id = str(item.get("item_id") or "").strip()
226
+ completion_command = str(item.get("command") or "").strip()
227
+ completion_cwd = str(item.get("cwd") or "").strip()
228
+ fallback_command = approval_command_by_item_id.get(item_id, {}).get("command", "")
229
+ fallback_cwd = approval_command_by_item_id.get(item_id, {}).get("cwd", "")
230
+ resolved_command = completion_command or fallback_command
231
+ resolved_cwd = completion_cwd or fallback_cwd or str(cwd)
232
+ normalized_command = _normalize_command_for_witness(resolved_command)
233
+ _handle_post_tool(
234
+ kernel=kernel,
235
+ session_id=session_id,
236
+ item={
237
+ "type": "commandExecution",
238
+ "status": item.get("status"),
239
+ "exitCode": item.get("exit_code"),
240
+ "aggregatedOutput": item.get("aggregated_output"),
241
+ "command": normalized_command,
242
+ "cwd": resolved_cwd,
243
+ },
244
+ )
245
+
246
+ final_text = str(result.get("text") or "")
247
+ stop_fields, stop_fields_source, stop_fields_parse_error = _extract_stop_fields_from_final_text(final_text)
248
+ stop_payload: dict[str, Any] = {
249
+ "session_id": session_id,
250
+ "last_assistant_message": final_text,
251
+ "final_text": final_text,
252
+ }
253
+ if stop_fields is not None:
254
+ stop_payload["stop_fields"] = stop_fields
255
+ stop_result = kernel.dispatch(
256
+ "stop",
257
+ stop_payload,
258
+ )
259
+
260
+ response = {
261
+ "ok": True,
262
+ "text": final_text,
263
+ "session_id": session_id,
264
+ "thread_id": result.get("thread_id"),
265
+ "turn_id": result.get("turn_id"),
266
+ "approval_policy_used": result.get("approval_policy_used"),
267
+ "coverage_gaps": sorted(set([*coverage_gaps, *[str(v) for v in result.get("coverage_gaps") or []]])),
268
+ "command_items_with_approval_count": len(command_surface.get("command_items_with_approval", [])),
269
+ "command_items_without_approval_count": len(command_items_without_approval),
270
+ "nonblocking_decline_count": len(nonblocking_declines),
271
+ "duplicate_turn_completed_count": int(result.get("duplicate_turn_completed_count") or 0),
272
+ "approval_request_count": len(result.get("approval_requests") or []),
273
+ "command_completion_count": len(result.get("command_completion_items") or []),
274
+ "stop_fields_present": bool(stop_fields is not None),
275
+ "stop_fields_parse_error": stop_fields_parse_error,
276
+ "stop_fields_source": stop_fields_source,
277
+ "elapsed_seconds": result.get("elapsed_seconds"),
278
+ }
279
+ response.update(_bridge_stop_summary(stop_result))
280
+ print(json.dumps(response, sort_keys=True))
281
+ return 0
282
+
283
+
284
+ def _probe_approval_blocking(args: argparse.Namespace) -> int:
285
+ return _probe_approval_blocking_impl(
286
+ args=args,
287
+ command_approval_method=COMMAND_APPROVAL_METHOD,
288
+ execute_turn=_execute_turn,
289
+ approval_policy_candidates_from_args=_approval_policy_candidates_from_args,
290
+ )
291
+
292
+
293
+ def _probe_model(args: argparse.Namespace) -> int:
294
+ return _probe_model_impl(
295
+ args=args,
296
+ app_server_client_cls=AppServerClient,
297
+ initialize_app_server=_initialize_app_server,
298
+ bridge_error_cls=BridgeError,
299
+ run_exec=subprocess.run,
300
+ )
301
+
302
+
303
+ def _parse_args(argv: list[str] | None = None) -> argparse.Namespace:
304
+ parser = argparse.ArgumentParser()
305
+ sub = parser.add_subparsers(dest="command", required=True)
306
+
307
+ run = sub.add_parser("run")
308
+ run.add_argument("--schema-version", choices=[SCHEMA_VERSION], default=SCHEMA_VERSION)
309
+ run.add_argument("--codex-bin", default="codex")
310
+ run.add_argument("--cwd", default=".")
311
+ run.add_argument("--root", default=".")
312
+ run.add_argument("--config-path")
313
+ run.add_argument("--db-path")
314
+ run.add_argument("--model")
315
+ run.add_argument("--prompt", required=True)
316
+ run.add_argument("--timeout-seconds", type=float, default=180.0)
317
+ run.add_argument(
318
+ "--approval-policy-candidates",
319
+ default=",".join(DEFAULT_APPROVAL_POLICY_CANDIDATES),
320
+ help="Comma-delimited thread/start approvalPolicy fallback order.",
321
+ )
322
+
323
+ probe = sub.add_parser("probe-approval-blocking")
324
+ probe.add_argument("--schema-version", choices=[SCHEMA_VERSION], default=SCHEMA_VERSION)
325
+ probe.add_argument("--codex-bin", default="codex")
326
+ probe.add_argument("--cwd", default=".")
327
+ probe.add_argument("--model")
328
+ probe.add_argument("--timeout-seconds", type=float, default=180.0)
329
+ probe.add_argument("--prompt", default="")
330
+ probe.add_argument(
331
+ "--approval-policy-candidates",
332
+ default=",".join(DEFAULT_APPROVAL_POLICY_CANDIDATES),
333
+ help="Comma-delimited thread/start approvalPolicy fallback order.",
334
+ )
335
+
336
+ probe_model = sub.add_parser("probe-model")
337
+ probe_model.add_argument("--schema-version", choices=[SCHEMA_VERSION], default=SCHEMA_VERSION)
338
+ probe_model.add_argument("--codex-bin", default="codex")
339
+ probe_model.add_argument("--cwd", default=".")
340
+ probe_model.add_argument("--model", required=True)
341
+ probe_model.add_argument("--timeout-seconds", type=float, default=180.0)
342
+
343
+ return parser.parse_args(argv)
344
+
345
+
346
+ def _approval_policy_candidates_from_args(args: argparse.Namespace) -> tuple[str, ...]:
347
+ raw = getattr(args, "approval_policy_candidates", None)
348
+ if raw is None:
349
+ return DEFAULT_APPROVAL_POLICY_CANDIDATES
350
+ if isinstance(raw, str):
351
+ parsed = tuple(token.strip() for token in raw.split(",") if token.strip())
352
+ return parsed or DEFAULT_APPROVAL_POLICY_CANDIDATES
353
+ if isinstance(raw, (list, tuple)):
354
+ parsed = tuple(str(token).strip() for token in raw if str(token).strip())
355
+ return parsed or DEFAULT_APPROVAL_POLICY_CANDIDATES
356
+ return DEFAULT_APPROVAL_POLICY_CANDIDATES
357
+
358
+
359
+ def main(argv: list[str] | None = None) -> int:
360
+ args = _parse_args(argv)
361
+ try:
362
+ if args.command == "run":
363
+ return _run_mode(args)
364
+ if args.command == "probe-approval-blocking":
365
+ return _probe_approval_blocking(args)
366
+ if args.command == "probe-model":
367
+ return _probe_model(args)
368
+ raise BridgeError(f"Unsupported command: {args.command}")
369
+ except BridgeError as exc:
370
+ print(json.dumps({"ok": False, "error": str(exc)}), file=sys.stderr)
371
+ return 1
372
+
373
+
374
+ if __name__ == "__main__":
375
+ raise SystemExit(main())
@@ -0,0 +1 @@
1
+ from .engine import * # noqa: F401,F403