fable-engine 1.3.1__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 (104) hide show
  1. fable_compressor.py +356 -0
  2. fable_engine/__init__.py +1 -0
  3. fable_engine/actions/__init__.py +291 -0
  4. fable_engine/actions/cas.py +182 -0
  5. fable_engine/actions/deliberation.py +523 -0
  6. fable_engine/actions/fleet.py +807 -0
  7. fable_engine/actions/lifecycle.py +298 -0
  8. fable_engine/actions/scrapers.py +116 -0
  9. fable_engine/actions/system3.py +815 -0
  10. fable_engine/browser.py +824 -0
  11. fable_engine/cas.py +974 -0
  12. fable_engine/fable_session.json +510 -0
  13. fable_engine/guards.py +283 -0
  14. fable_engine/schema.py +714 -0
  15. fable_engine/scrapers/__init__.py +32 -0
  16. fable_engine/scrapers/arxiv.py +115 -0
  17. fable_engine/scrapers/base.py +386 -0
  18. fable_engine/scrapers/github.py +129 -0
  19. fable_engine/scrapers/reddit.py +154 -0
  20. fable_engine/scrapers/web.py +120 -0
  21. fable_engine/scrapers/x.py +125 -0
  22. fable_engine/scrapers/youtube.py +132 -0
  23. fable_engine/server.py +414 -0
  24. fable_engine/session.py +1819 -0
  25. fable_engine/test_server.py +1362 -0
  26. fable_engine/updater.py +541 -0
  27. fable_engine-1.3.1.dist-info/LICENSE +22 -0
  28. fable_engine-1.3.1.dist-info/METADATA +173 -0
  29. fable_engine-1.3.1.dist-info/RECORD +104 -0
  30. fable_engine-1.3.1.dist-info/WHEEL +5 -0
  31. fable_engine-1.3.1.dist-info/entry_points.txt +5 -0
  32. fable_engine-1.3.1.dist-info/top_level.txt +6 -0
  33. fable_mode/__init__.py +3 -0
  34. fable_mode/__main__.py +4 -0
  35. fable_mode/adapters.py +1014 -0
  36. fable_mode/installer.py +553 -0
  37. fable_mode/launcher.py +437 -0
  38. fable_mode/manifest.py +142 -0
  39. fable_mode/resources.json +114 -0
  40. fable_mode/safety.py +103 -0
  41. fable_mode_entry.py +10 -0
  42. fable_v2/__init__.py +146 -0
  43. fable_v2/adapters.py +151 -0
  44. fable_v2/coder_fleet/__init__.py +100 -0
  45. fable_v2/coder_fleet/ast_tools.py +158 -0
  46. fable_v2/coder_fleet/compute.py +199 -0
  47. fable_v2/coder_fleet/design_engine.py +1316 -0
  48. fable_v2/coder_fleet/diagnostics.py +293 -0
  49. fable_v2/coder_fleet/fleet_dispatcher.py +214 -0
  50. fable_v2/coder_fleet/mock_auditor.py +306 -0
  51. fable_v2/coder_fleet/mutation.py +216 -0
  52. fable_v2/coder_fleet/property_oracle.py +260 -0
  53. fable_v2/coder_fleet/receipt_attestor.py +122 -0
  54. fable_v2/coder_fleet/red_team_swarm.py +908 -0
  55. fable_v2/coder_fleet/test_harness.py +198 -0
  56. fable_v2/coder_fleet/vector_engine.py +1287 -0
  57. fable_v2/coder_fleet/visual.py +357 -0
  58. fable_v2/coder_fleet/workspace.py +153 -0
  59. fable_v2/cortical/__init__.py +20 -0
  60. fable_v2/cortical/plasticity_engine.py +992 -0
  61. fable_v2/execution_broker.py +811 -0
  62. fable_v2/proof_engine.py +1141 -0
  63. fable_v2/protocol.py +485 -0
  64. fable_v2/runtime.py +1010 -0
  65. fable_v2/system3/__init__.py +204 -0
  66. fable_v2/system3/causal.py +558 -0
  67. fable_v2/system3/dialectical.py +577 -0
  68. fable_v2/system3/evolution.py +503 -0
  69. fable_v2/system3/executive.py +338 -0
  70. fable_v2/system3/free_energy.py +479 -0
  71. fable_v2/system3/hyperbolic.py +555 -0
  72. fable_v2/system3/induction.py +336 -0
  73. fable_v2/system3/kripke.py +548 -0
  74. fable_v2/system3/oracle.py +745 -0
  75. fable_v2/verifiers.py +72 -0
  76. tests/__init__.py +1 -0
  77. tests/test_anti_loop_circuit_breaker.py +64 -0
  78. tests/test_auto_updater.py +407 -0
  79. tests/test_coder_fleet.py +535 -0
  80. tests/test_delegation_compiler.py +54 -0
  81. tests/test_descriptor_boundaries.py +126 -0
  82. tests/test_design_engine.py +603 -0
  83. tests/test_epistemic_evidence_validator.py +66 -0
  84. tests/test_execution_broker.py +233 -0
  85. tests/test_fable_v2.py +406 -0
  86. tests/test_fleet_transitions.py +116 -0
  87. tests/test_fsm_redteam_evolution.py +406 -0
  88. tests/test_goal_rubric_and_pipeline.py +367 -0
  89. tests/test_hebbian_plasticity.py +585 -0
  90. tests/test_packaging_runtime.py +194 -0
  91. tests/test_proof_engine.py +259 -0
  92. tests/test_red_team_swarm.py +645 -0
  93. tests/test_redteam_remediation.py +169 -0
  94. tests/test_registration_transaction.py +375 -0
  95. tests/test_requested_regressions.py +467 -0
  96. tests/test_scrapers.py +370 -0
  97. tests/test_server_actions.py +93 -0
  98. tests/test_server_frontier_actions.py +269 -0
  99. tests/test_server_protocol.py +88 -0
  100. tests/test_stealth_browser.py +970 -0
  101. tests/test_system3.py +381 -0
  102. tests/test_system3_deep_integration.py +385 -0
  103. tests/test_system3_frontier.py +436 -0
  104. tests/test_vector_engine.py +608 -0
@@ -0,0 +1,269 @@
1
+ import unittest
2
+ import json
3
+ import time
4
+ import tempfile
5
+ from pathlib import Path
6
+ import sys
7
+
8
+ BASE_DIR = Path(__file__).resolve().parent.parent
9
+ for p in [str(BASE_DIR), str(BASE_DIR / "fable_engine"), str(Path(__file__).resolve().parent)]:
10
+ if p not in sys.path:
11
+ sys.path.insert(0, p)
12
+
13
+ from server import (
14
+ handle_fable_session,
15
+ ACTIVE_SESSIONS,
16
+ SESSIONS_DIR,
17
+ FableSession,
18
+ MIN_TIME_BUDGET_MINUTES,
19
+ GLOBAL_VELOCITY_PROFILER,
20
+ ModelVelocityProfiler,
21
+ )
22
+ from fable_v2.proof_engine import DeterministicProofValidator, ProofType
23
+
24
+
25
+ class TestServerFrontierActions(unittest.TestCase):
26
+ def setUp(self):
27
+ self.session_name = f"test_frontier_{int(time.time() * 1000)}"
28
+
29
+ def tearDown(self):
30
+ if self.session_name in ACTIVE_SESSIONS:
31
+ del ACTIVE_SESSIONS[self.session_name]
32
+ session_file = SESSIONS_DIR / f"{self.session_name}.json"
33
+ if session_file.exists():
34
+ try:
35
+ session_file.unlink()
36
+ except Exception:
37
+ pass
38
+
39
+ def test_min_time_budget_enforcement(self):
40
+ # 1. Reject time budget < 2.0
41
+ res = handle_fable_session({
42
+ "action": "create_session",
43
+ "session_name": self.session_name,
44
+ "objective": "Test budget rejection",
45
+ "time_budget_minutes": 1.5
46
+ })
47
+ self.assertIn("Error:", res)
48
+ self.assertIn("minimum allowed time budget is 2.0 minutes", res)
49
+
50
+ # 2. Accept valid time budget >= 2.0
51
+ res_ok = handle_fable_session({
52
+ "action": "create_session",
53
+ "session_name": self.session_name,
54
+ "objective": "Test valid budget",
55
+ "time_budget_minutes": 5.0
56
+ })
57
+ self.assertIn("Fable Cognitive Session Initialized", res_ok)
58
+
59
+ # 3. Reject set_timer < 2.0
60
+ res_timer_fail = handle_fable_session({
61
+ "action": "set_timer",
62
+ "session_name": self.session_name,
63
+ "time_budget_minutes": 0.5
64
+ })
65
+ self.assertIn("Error:", res_timer_fail)
66
+ self.assertIn("minimum allowed time budget is 2.0 minutes", res_timer_fail)
67
+
68
+ def test_model_velocity_profiler(self):
69
+ profiler = ModelVelocityProfiler(window_size=10)
70
+ # Record rapid high-throughput requests
71
+ t0 = time.time()
72
+ for i in range(5):
73
+ profiler.record_request("test_action", "x" * 2000, timestamp=t0 + i * 0.1)
74
+
75
+ prof = profiler.get_velocity_profile()
76
+ self.assertEqual(prof["model_tier"], "flash")
77
+ self.assertEqual(prof["tier_multiplier"], 2.5)
78
+ self.assertGreater(prof["tokens_per_sec"], 80.0)
79
+
80
+ def test_track_file_change_action(self):
81
+ handle_fable_session({
82
+ "action": "create_session",
83
+ "session_name": self.session_name,
84
+ "objective": "Test file tracking",
85
+ "time_budget_minutes": 10.0
86
+ })
87
+
88
+ with tempfile.NamedTemporaryFile("w", delete=False, suffix=".py") as tf:
89
+ tf.write("print('hello')\n")
90
+ tf_path = tf.name
91
+
92
+ try:
93
+ res = handle_fable_session({
94
+ "action": "track_file_change",
95
+ "session_name": self.session_name,
96
+ "file_path": tf_path,
97
+ "change_type": "modified",
98
+ "diff_summary": "Added hello print statement",
99
+ "rationale": "Bootstrap entrypoint",
100
+ "affected_invariants": ["INV-01"]
101
+ })
102
+ self.assertIn("File Change Tracked", res)
103
+ self.assertIn("MODIFIED", res)
104
+ self.assertIn("File SHA256", res)
105
+
106
+ session = ACTIVE_SESSIONS[self.session_name]
107
+ self.assertEqual(len(session.file_changes), 1)
108
+ self.assertEqual(session.file_changes[0]["change_type"], "modified")
109
+ self.assertIsNotNone(session.file_changes[0]["sha256"])
110
+ finally:
111
+ Path(tf_path).unlink(missing_ok=True)
112
+
113
+ def test_record_visual_mockups_action(self):
114
+ handle_fable_session({
115
+ "action": "create_session",
116
+ "session_name": self.session_name,
117
+ "objective": "Test visual mockups",
118
+ "time_budget_minutes": 10.0
119
+ })
120
+
121
+ mockups = [
122
+ {
123
+ "concept_name": "Kinetic Glassmorphism",
124
+ "aesthetic_archetype": "glassmorphic_modern",
125
+ "prompt": "Futuristic UI with frosted glass cards",
126
+ "palette": "oklch(0.95 0.02 240) / oklch(0.2 0.05 260)",
127
+ "typography": "Geist, Geist Mono",
128
+ "coordinates_data": {"grid": "12-col", "gap": "16px"}
129
+ },
130
+ {
131
+ "concept_name": "Monochrome Minimal",
132
+ "aesthetic_archetype": "swiss_high_contrast",
133
+ "prompt": "Clean monochrome Swiss typography",
134
+ "palette": "#000000 / #FFFFFF",
135
+ "typography": "Inter, JetBrains Mono",
136
+ "coordinates_data": {"grid": "bento-3x3"}
137
+ }
138
+ ]
139
+
140
+ res = handle_fable_session({
141
+ "action": "record_visual_mockups",
142
+ "session_name": self.session_name,
143
+ "mockups": mockups,
144
+ "selected_concept": "Kinetic Glassmorphism"
145
+ })
146
+ self.assertIn("Visual Architectural Mockups Recorded", res)
147
+ self.assertIn("Kinetic Glassmorphism", res)
148
+
149
+ session = ACTIVE_SESSIONS[self.session_name]
150
+ self.assertEqual(len(session.visual_mockups["mockups"]), 2)
151
+ self.assertEqual(session.visual_mockups["selected_concept"], "Kinetic Glassmorphism")
152
+
153
+ def test_verify_proof_action(self):
154
+ handle_fable_session({
155
+ "action": "create_session",
156
+ "session_name": self.session_name,
157
+ "objective": "Test proof verification",
158
+ "time_budget_minutes": 10.0
159
+ })
160
+
161
+ res = handle_fable_session({
162
+ "action": "verify_proof",
163
+ "session_name": self.session_name,
164
+ "claim": "Cargo test passes cleanly with 0 failures",
165
+ "proof_type": "receipt",
166
+ "evidence": "cargo test --all: exit code 0, 42 passed"
167
+ })
168
+ self.assertIn("Deterministic Proof Verification", res)
169
+ self.assertIn("VERIFIED", res)
170
+ self.assertIn("rcpt_", res)
171
+
172
+ def test_get_session_lineage_and_inspect_plan(self):
173
+ handle_fable_session({
174
+ "action": "create_session",
175
+ "session_name": self.session_name,
176
+ "objective": "Full lineage and blueprint inspection",
177
+ "time_budget_minutes": 10.0
178
+ })
179
+
180
+ handle_fable_session({
181
+ "action": "track_file_change",
182
+ "session_name": self.session_name,
183
+ "file_path": "src/core/router.py",
184
+ "change_type": "slated",
185
+ "diff_summary": "Implement atomic lock-free queue"
186
+ })
187
+
188
+ plan_res = handle_fable_session({
189
+ "action": "inspect_plan",
190
+ "session_name": self.session_name
191
+ })
192
+ self.assertIn("Fable Execution Plan & Cognitive Blueprint", plan_res)
193
+ self.assertIn("Cognitive Gate Status", plan_res)
194
+ self.assertIn("src/core/router.py", plan_res)
195
+
196
+ lineage_res = handle_fable_session({
197
+ "action": "get_session_lineage",
198
+ "session_name": self.session_name
199
+ })
200
+ self.assertIn("Omniscient Session Lineage", lineage_res)
201
+ self.assertIn("Slated File Modifications", lineage_res)
202
+ self.assertIn("Model Velocity & Capability Telemetry", lineage_res)
203
+
204
+ def test_tautology_rejection_in_proven_claim(self):
205
+ handle_fable_session({
206
+ "action": "create_session",
207
+ "session_name": self.session_name,
208
+ "objective": "Test tautology rejection",
209
+ "time_budget_minutes": 10.0
210
+ })
211
+
212
+ # Tautological claim should be rejected
213
+ res = handle_fable_session({
214
+ "action": "log_epistemic_item",
215
+ "session_name": self.session_name,
216
+ "tag": "PROVEN",
217
+ "claim": "it works tested verified",
218
+ "evidence": "stdout: ok"
219
+ })
220
+ self.assertIn("Error:", res)
221
+ self.assertIn("must not be tautological or generic", res)
222
+
223
+ def test_validate_event_history_action(self):
224
+ handle_fable_session({
225
+ "action": "create_session",
226
+ "session_name": self.session_name,
227
+ "objective": "Test event history audit",
228
+ "time_budget_minutes": 10.0
229
+ })
230
+
231
+ handle_fable_session({
232
+ "action": "track_file_change",
233
+ "session_name": self.session_name,
234
+ "file_path": "src/unified.py",
235
+ "change_type": "modified",
236
+ "diff_summary": "+ unified event tracking",
237
+ })
238
+
239
+ audit_res = handle_fable_session({
240
+ "action": "validate_event_history",
241
+ "session_name": self.session_name,
242
+ })
243
+ self.assertIn("Cryptographic Event Chain Audit", audit_res)
244
+ self.assertIn("VALID & INTACT", audit_res)
245
+
246
+ def test_cross_process_session_mtime_synchronization(self):
247
+ from fable_engine.server import get_or_load_session, SESSIONS_DIR
248
+ handle_fable_session({
249
+ "action": "create_session",
250
+ "session_name": self.session_name,
251
+ "objective": "Concurrency test",
252
+ "time_budget_minutes": 10.0
253
+ })
254
+ session1 = get_or_load_session(self.session_name)
255
+ file_path = SESSIONS_DIR / f"{self.session_name}.json"
256
+
257
+ # Simulate external process update by loading, modifying, and saving to disk
258
+ data = json.loads(file_path.read_text(encoding="utf-8"))
259
+ data["objective"] = "Updated by external worker process"
260
+ time.sleep(0.02)
261
+ file_path.write_text(json.dumps(data), encoding="utf-8")
262
+
263
+ # get_or_load_session should detect disk mtime delta and refresh in-memory session
264
+ session2 = get_or_load_session(self.session_name)
265
+ self.assertEqual(session2.objective, "Updated by external worker process")
266
+
267
+
268
+ if __name__ == "__main__":
269
+ unittest.main()
@@ -0,0 +1,88 @@
1
+ import io
2
+ import json
3
+ import os
4
+ import subprocess
5
+ import sys
6
+ import tempfile
7
+ import threading
8
+ import unittest
9
+ from pathlib import Path
10
+ from unittest.mock import patch
11
+
12
+ from fable_engine.server import FableCASStore, IntegrityError, MAX_RPC_LINE_BYTES, main
13
+
14
+
15
+ class ServerProtocolRegressionTests(unittest.TestCase):
16
+ def test_cached_verified_cas_reads_detect_disk_tampering(self):
17
+ with tempfile.TemporaryDirectory() as tmp:
18
+ store = FableCASStore(Path(tmp))
19
+ ref = store.put("trusted")
20
+ path = store.get_file_path(ref)
21
+ path.write_text("tampered", encoding="utf-8")
22
+ with self.assertRaises(IntegrityError):
23
+ store.get_bytes(ref, verify=True)
24
+ self.assertFalse(store.verify_integrity(ref))
25
+
26
+ def test_verify_false_is_explicit_low_level_cache_opt_out(self):
27
+ """Only the opt-out can return cached bytes after disk tampering."""
28
+ with tempfile.TemporaryDirectory() as tmp:
29
+ store = FableCASStore(Path(tmp))
30
+ ref = store.put("trusted")
31
+ store.get_file_path(ref).write_text("tampered", encoding="utf-8")
32
+ self.assertEqual(store.get_bytes(ref, verify=False), b"trusted")
33
+ with self.assertRaises(IntegrityError):
34
+ store.get_text(ref, verify=True)
35
+
36
+ def test_malformed_jsonrpc_requests_are_controlled_errors(self):
37
+ requests = "not-json\n[]\n" + json.dumps({"jsonrpc": "2.0", "id": 3, "method": "ping", "params": []}) + "\n"
38
+ output = io.StringIO()
39
+ with patch("sys.stdin", io.StringIO(requests)), patch("sys.stdout", output):
40
+ main()
41
+ responses = [json.loads(line) for line in output.getvalue().splitlines() if line]
42
+ self.assertEqual([item["error"]["code"] for item in responses], [-32700, -32600, -32600])
43
+
44
+ def test_rpc_line_limit_counts_untrimmed_frame(self):
45
+ output = io.StringIO()
46
+ with patch("sys.stdin", io.StringIO(" " * (MAX_RPC_LINE_BYTES + 1) + "\n")), patch("sys.stdout", output):
47
+ main()
48
+ response = json.loads(output.getvalue())
49
+ self.assertEqual(response["error"]["code"], -32600)
50
+
51
+ def test_interactive_initialize_does_not_wait_for_eof(self):
52
+ """A short frame must be answered while stdin remains open."""
53
+ root = Path(tempfile.mkdtemp(prefix="fable-interactive-"))
54
+ proc = subprocess.Popen(
55
+ [sys.executable, "-u", os.fspath(Path(__file__).resolve().parents[1] / "fable_engine" / "server.py")],
56
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
57
+ text=True, encoding="utf-8", cwd=os.fspath(root),
58
+ )
59
+ line = []
60
+ reader = threading.Thread(target=lambda: line.append(proc.stdout.readline()), daemon=True)
61
+ try:
62
+ proc.stdin.write(json.dumps({"jsonrpc": "2.0", "id": 1,
63
+ "method": "initialize", "params": {}}) + "\n")
64
+ proc.stdin.flush()
65
+ reader.start()
66
+ reader.join(timeout=10)
67
+ self.assertFalse(reader.is_alive(), "interactive response waited for EOF")
68
+ self.assertTrue(line and line[0])
69
+ self.assertEqual(json.loads(line[0])["id"], 1)
70
+ finally:
71
+ if proc.stdin:
72
+ proc.stdin.close()
73
+ if proc.poll() is None:
74
+ proc.terminate()
75
+ try:
76
+ proc.wait(timeout=2)
77
+ except subprocess.TimeoutExpired:
78
+ proc.kill(); proc.wait(timeout=2)
79
+ if proc.stdout:
80
+ proc.stdout.close()
81
+ if proc.stderr:
82
+ proc.stderr.close()
83
+ import shutil
84
+ shutil.rmtree(root, ignore_errors=True)
85
+
86
+
87
+ if __name__ == "__main__":
88
+ unittest.main()