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.
- fable_compressor.py +356 -0
- fable_engine/__init__.py +1 -0
- fable_engine/actions/__init__.py +291 -0
- fable_engine/actions/cas.py +182 -0
- fable_engine/actions/deliberation.py +523 -0
- fable_engine/actions/fleet.py +807 -0
- fable_engine/actions/lifecycle.py +298 -0
- fable_engine/actions/scrapers.py +116 -0
- fable_engine/actions/system3.py +815 -0
- fable_engine/browser.py +824 -0
- fable_engine/cas.py +974 -0
- fable_engine/fable_session.json +510 -0
- fable_engine/guards.py +283 -0
- fable_engine/schema.py +714 -0
- fable_engine/scrapers/__init__.py +32 -0
- fable_engine/scrapers/arxiv.py +115 -0
- fable_engine/scrapers/base.py +386 -0
- fable_engine/scrapers/github.py +129 -0
- fable_engine/scrapers/reddit.py +154 -0
- fable_engine/scrapers/web.py +120 -0
- fable_engine/scrapers/x.py +125 -0
- fable_engine/scrapers/youtube.py +132 -0
- fable_engine/server.py +414 -0
- fable_engine/session.py +1819 -0
- fable_engine/test_server.py +1362 -0
- fable_engine/updater.py +541 -0
- fable_engine-1.3.1.dist-info/LICENSE +22 -0
- fable_engine-1.3.1.dist-info/METADATA +173 -0
- fable_engine-1.3.1.dist-info/RECORD +104 -0
- fable_engine-1.3.1.dist-info/WHEEL +5 -0
- fable_engine-1.3.1.dist-info/entry_points.txt +5 -0
- fable_engine-1.3.1.dist-info/top_level.txt +6 -0
- fable_mode/__init__.py +3 -0
- fable_mode/__main__.py +4 -0
- fable_mode/adapters.py +1014 -0
- fable_mode/installer.py +553 -0
- fable_mode/launcher.py +437 -0
- fable_mode/manifest.py +142 -0
- fable_mode/resources.json +114 -0
- fable_mode/safety.py +103 -0
- fable_mode_entry.py +10 -0
- fable_v2/__init__.py +146 -0
- fable_v2/adapters.py +151 -0
- fable_v2/coder_fleet/__init__.py +100 -0
- fable_v2/coder_fleet/ast_tools.py +158 -0
- fable_v2/coder_fleet/compute.py +199 -0
- fable_v2/coder_fleet/design_engine.py +1316 -0
- fable_v2/coder_fleet/diagnostics.py +293 -0
- fable_v2/coder_fleet/fleet_dispatcher.py +214 -0
- fable_v2/coder_fleet/mock_auditor.py +306 -0
- fable_v2/coder_fleet/mutation.py +216 -0
- fable_v2/coder_fleet/property_oracle.py +260 -0
- fable_v2/coder_fleet/receipt_attestor.py +122 -0
- fable_v2/coder_fleet/red_team_swarm.py +908 -0
- fable_v2/coder_fleet/test_harness.py +198 -0
- fable_v2/coder_fleet/vector_engine.py +1287 -0
- fable_v2/coder_fleet/visual.py +357 -0
- fable_v2/coder_fleet/workspace.py +153 -0
- fable_v2/cortical/__init__.py +20 -0
- fable_v2/cortical/plasticity_engine.py +992 -0
- fable_v2/execution_broker.py +811 -0
- fable_v2/proof_engine.py +1141 -0
- fable_v2/protocol.py +485 -0
- fable_v2/runtime.py +1010 -0
- fable_v2/system3/__init__.py +204 -0
- fable_v2/system3/causal.py +558 -0
- fable_v2/system3/dialectical.py +577 -0
- fable_v2/system3/evolution.py +503 -0
- fable_v2/system3/executive.py +338 -0
- fable_v2/system3/free_energy.py +479 -0
- fable_v2/system3/hyperbolic.py +555 -0
- fable_v2/system3/induction.py +336 -0
- fable_v2/system3/kripke.py +548 -0
- fable_v2/system3/oracle.py +745 -0
- fable_v2/verifiers.py +72 -0
- tests/__init__.py +1 -0
- tests/test_anti_loop_circuit_breaker.py +64 -0
- tests/test_auto_updater.py +407 -0
- tests/test_coder_fleet.py +535 -0
- tests/test_delegation_compiler.py +54 -0
- tests/test_descriptor_boundaries.py +126 -0
- tests/test_design_engine.py +603 -0
- tests/test_epistemic_evidence_validator.py +66 -0
- tests/test_execution_broker.py +233 -0
- tests/test_fable_v2.py +406 -0
- tests/test_fleet_transitions.py +116 -0
- tests/test_fsm_redteam_evolution.py +406 -0
- tests/test_goal_rubric_and_pipeline.py +367 -0
- tests/test_hebbian_plasticity.py +585 -0
- tests/test_packaging_runtime.py +194 -0
- tests/test_proof_engine.py +259 -0
- tests/test_red_team_swarm.py +645 -0
- tests/test_redteam_remediation.py +169 -0
- tests/test_registration_transaction.py +375 -0
- tests/test_requested_regressions.py +467 -0
- tests/test_scrapers.py +370 -0
- tests/test_server_actions.py +93 -0
- tests/test_server_frontier_actions.py +269 -0
- tests/test_server_protocol.py +88 -0
- tests/test_stealth_browser.py +970 -0
- tests/test_system3.py +381 -0
- tests/test_system3_deep_integration.py +385 -0
- tests/test_system3_frontier.py +436 -0
- tests/test_vector_engine.py +608 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
"""Deliberation, epistemic ledger, invariants, refinement, and proof action handlers."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import collections
|
|
5
|
+
import hashlib
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
import math
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
11
|
+
import sys
|
|
12
|
+
import time
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
15
|
+
|
|
16
|
+
logger = logging.getLogger("fable-engine.actions.deliberation")
|
|
17
|
+
|
|
18
|
+
from fable_engine.guards import (
|
|
19
|
+
GLOBAL_VELOCITY_PROFILER,
|
|
20
|
+
DelegationContractCompiler,
|
|
21
|
+
)
|
|
22
|
+
from fable_engine.session import (
|
|
23
|
+
ACTIVE_SESSIONS,
|
|
24
|
+
PHASES,
|
|
25
|
+
SESSIONS_DIR,
|
|
26
|
+
SILENT_DELIBERATION_REMINDER,
|
|
27
|
+
FableSession,
|
|
28
|
+
SessionState,
|
|
29
|
+
_validate_session_name,
|
|
30
|
+
_validate_time_budget,
|
|
31
|
+
get_or_load_session,
|
|
32
|
+
)
|
|
33
|
+
# DeterministicProofValidator imported lazily
|
|
34
|
+
|
|
35
|
+
def _handle_log_epistemic_item(arguments: Dict[str, Any]) -> str:
|
|
36
|
+
action = arguments.get("action", "").strip().lower()
|
|
37
|
+
session_name = arguments.get("session_name", "").strip()
|
|
38
|
+
session: Optional[FableSession] = None
|
|
39
|
+
if not session_name:
|
|
40
|
+
return "Error: 'session_name' is required for action 'log_epistemic_item'."
|
|
41
|
+
tag = arguments.get("tag", "").strip()
|
|
42
|
+
if not tag:
|
|
43
|
+
return "Error: 'tag' (PROVEN, HYPOTHESIS, UNKNOWN) is required for 'log_epistemic_item'."
|
|
44
|
+
claim = arguments.get("claim", "").strip()
|
|
45
|
+
if not claim:
|
|
46
|
+
return "Error: 'claim' is required for 'log_epistemic_item'."
|
|
47
|
+
evidence = arguments.get("evidence")
|
|
48
|
+
|
|
49
|
+
session = get_or_load_session(session_name)
|
|
50
|
+
item = session.log_epistemic_item(tag, claim, evidence)
|
|
51
|
+
session.save()
|
|
52
|
+
|
|
53
|
+
tel = session.get_telemetry()
|
|
54
|
+
counts = tel["epistemic_counts"]
|
|
55
|
+
|
|
56
|
+
ev_display = f"\n- **Evidence**: `{item['evidence']}`" if item.get("evidence") else ""
|
|
57
|
+
return (
|
|
58
|
+
f"### 📝 Epistemic Item Logged (`{item['id']}`)\n\n"
|
|
59
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
60
|
+
f"- **Classification**: `[{item['tag']}]`\n"
|
|
61
|
+
f"- **Claim**: {item['claim']}{ev_display}\n"
|
|
62
|
+
f"- **Logged in**: `{item['phase']}`\n"
|
|
63
|
+
f"- **Ledger Total**: `{counts['proven']} PROVEN`, `{counts['hypothesis']} HYPOTHESIS`, `{counts['unknown']} UNKNOWN`"
|
|
64
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _handle_record_invariant(arguments: Dict[str, Any]) -> str:
|
|
69
|
+
action = arguments.get("action", "").strip().lower()
|
|
70
|
+
session_name = arguments.get("session_name", "").strip()
|
|
71
|
+
session: Optional[FableSession] = None
|
|
72
|
+
if not session_name:
|
|
73
|
+
return "Error: 'session_name' is required for action 'record_invariant'."
|
|
74
|
+
invariant_name = arguments.get("invariant_name", "").strip()
|
|
75
|
+
if not invariant_name:
|
|
76
|
+
return "Error: 'invariant_name' is required for 'record_invariant'."
|
|
77
|
+
formal_statement = arguments.get("formal_statement", "").strip()
|
|
78
|
+
if not formal_statement:
|
|
79
|
+
return "Error: 'formal_statement' is required for 'record_invariant'."
|
|
80
|
+
proof_or_rationale = arguments.get("proof_or_rationale", "").strip()
|
|
81
|
+
domain = arguments.get("domain", "architecture").strip()
|
|
82
|
+
|
|
83
|
+
session = get_or_load_session(session_name)
|
|
84
|
+
inv = session.record_invariant(invariant_name, formal_statement, proof_or_rationale, domain)
|
|
85
|
+
session.save()
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
f"### 📐 Formal Invariant Recorded (`{inv['id']}`)\n\n"
|
|
89
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
90
|
+
f"- **Invariant Name**: **{inv['name']}**\n"
|
|
91
|
+
f"- **Domain**: `{inv['domain'].upper()}`\n"
|
|
92
|
+
f"- **Formal Statement**: `{inv['formal_statement']}`\n"
|
|
93
|
+
f"- **Proof / Rationale**: {inv['proof_or_rationale']}\n"
|
|
94
|
+
f"- **Total Invariants**: `{len(session.invariants)}`"
|
|
95
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _handle_log_refinement_cycle(arguments: Dict[str, Any]) -> str:
|
|
100
|
+
action = arguments.get("action", "").strip().lower()
|
|
101
|
+
session_name = arguments.get("session_name", "").strip()
|
|
102
|
+
session: Optional[FableSession] = None
|
|
103
|
+
if not session_name:
|
|
104
|
+
return "Error: 'session_name' is required for action 'log_refinement_cycle'."
|
|
105
|
+
refinement_type = arguments.get("refinement_type", "").strip()
|
|
106
|
+
if not refinement_type:
|
|
107
|
+
return "Error: 'refinement_type' is required for 'log_refinement_cycle'."
|
|
108
|
+
focus_area = arguments.get("focus_area", "").strip()
|
|
109
|
+
if not focus_area:
|
|
110
|
+
return "Error: 'focus_area' is required for 'log_refinement_cycle'."
|
|
111
|
+
critique_or_bottleneck = arguments.get("critique_or_bottleneck", "").strip()
|
|
112
|
+
if not critique_or_bottleneck:
|
|
113
|
+
return "Error: 'critique_or_bottleneck' is required for 'log_refinement_cycle'."
|
|
114
|
+
architectural_refinement = arguments.get("architectural_refinement", "").strip()
|
|
115
|
+
if not architectural_refinement:
|
|
116
|
+
return "Error: 'architectural_refinement' is required for 'log_refinement_cycle'."
|
|
117
|
+
|
|
118
|
+
terminal_probe_results = arguments.get("terminal_probe_results")
|
|
119
|
+
artifact_path = arguments.get("artifact_path")
|
|
120
|
+
|
|
121
|
+
session = get_or_load_session(session_name)
|
|
122
|
+
cycle = session.log_refinement_cycle(
|
|
123
|
+
refinement_type=refinement_type,
|
|
124
|
+
focus_area=focus_area,
|
|
125
|
+
critique_or_bottleneck=critique_or_bottleneck,
|
|
126
|
+
architectural_refinement=architectural_refinement,
|
|
127
|
+
terminal_probe_results=terminal_probe_results,
|
|
128
|
+
artifact_path=artifact_path
|
|
129
|
+
)
|
|
130
|
+
session.save()
|
|
131
|
+
|
|
132
|
+
tel = session.get_telemetry()
|
|
133
|
+
probe_display = f"\n- **Terminal Probes / Benchmarks**: `{cycle['terminal_probe_results']}`" if cycle.get("terminal_probe_results") else ""
|
|
134
|
+
artifact_display = f"\n- **Artifact Blueprint**: `{cycle['artifact_path']}`" if cycle.get("artifact_path") else ""
|
|
135
|
+
|
|
136
|
+
return (
|
|
137
|
+
f"### 🔄 Rethink-Refine Cycle #{cycle['cycle_number']} Logged\n\n"
|
|
138
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
139
|
+
f"- **Refinement Type**: `{cycle['refinement_type'].upper()}`\n"
|
|
140
|
+
f"- **Focus Area**: {cycle['focus_area']}\n"
|
|
141
|
+
f"- **Critique / Bottleneck**: {cycle['critique_or_bottleneck']}\n"
|
|
142
|
+
f"- **Architectural Refinement**: {cycle['architectural_refinement']}{probe_display}{artifact_display}\n"
|
|
143
|
+
f"- **Phase**: `{cycle['phase']}`\n"
|
|
144
|
+
f"- **Pacing Remaining**: `{tel['remaining_formatted']}` ({tel['pacing_percentage']} budget used)\n"
|
|
145
|
+
f"- **Total Refinement Cycles**: `{len(session.refinement_cycles)}`\n\n"
|
|
146
|
+
f"> [!TIP]\n"
|
|
147
|
+
f"> Rethink-Refine Cognitive Loop active. Continue exploring alternative archetypes, falsifications, and terminal benchmarks until the time budget is fulfilled."
|
|
148
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _handle_compile_delegation_contract(arguments: Dict[str, Any]) -> str:
|
|
153
|
+
action = arguments.get("action", "").strip().lower()
|
|
154
|
+
session_name = arguments.get("session_name", "").strip()
|
|
155
|
+
session: Optional[FableSession] = None
|
|
156
|
+
prompt = arguments.get("subagent_prompt") or arguments.get("prompt") or arguments.get("contract") or ""
|
|
157
|
+
if not str(prompt).strip():
|
|
158
|
+
return "Error: 'subagent_prompt' (or 'prompt') is required for action 'compile_delegation_contract'."
|
|
159
|
+
|
|
160
|
+
compiler = DelegationContractCompiler()
|
|
161
|
+
is_valid, errors, parsed = compiler.compile_and_validate(prompt)
|
|
162
|
+
|
|
163
|
+
if not is_valid:
|
|
164
|
+
err_list = "\n".join([f"- ❌ {e}" for e in errors])
|
|
165
|
+
return (
|
|
166
|
+
f"### 🛑 Subagent Delegation Contract Compilation Failed\n\n"
|
|
167
|
+
f"The subagent prompt does not satisfy the strict Fable-Mode delegation boundaries:\n\n"
|
|
168
|
+
f"{err_list}\n\n"
|
|
169
|
+
f"> [!WARNING]\n"
|
|
170
|
+
f"> Worker subagents must receive 100% bounded, unambiguous contracts before dispatch.\n"
|
|
171
|
+
f"> Ensure your prompt contains:\n"
|
|
172
|
+
f"> 1. `TargetFile: <file path>`\n"
|
|
173
|
+
f"> 2. `InterfaceContract: <type/function signature>`\n"
|
|
174
|
+
f"> 3. `StrictConstraints: <invariants / bounds>`\n"
|
|
175
|
+
f"> 4. `VerificationCommand: <exact CLI test command>`"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
compiled_scaffold = parsed.get("compiled_prompt", prompt)
|
|
179
|
+
return (
|
|
180
|
+
f"### ✅ Subagent Delegation Contract Compiled Successfully (with System 3 Micro-Scaffolds)\n\n"
|
|
181
|
+
f"- **Target File**: `{parsed.get('TargetFile', 'Declared')}`\n"
|
|
182
|
+
f"- **Verification Command**: `{parsed.get('VerificationCommand', 'Declared')}`\n"
|
|
183
|
+
f"- **Contract Status**: `100% BOUNDED & VALIDATED`\n"
|
|
184
|
+
f"- **System 3 Micro-Scaffolds**: `INJECTED (Kripke AG(safe), Causal do(·) bounds, TRIZ Transcendence, Regex Constraints)`\n"
|
|
185
|
+
f"- **Dispatch Readiness**: `READY_FOR_SUBAGENT_DISPATCH` 🚀\n\n"
|
|
186
|
+
f"```markdown\n{compiled_scaffold}\n```\n\n"
|
|
187
|
+
f"> [!TIP]\n"
|
|
188
|
+
f"> You may now dispatch a worker subagent (`type: self`) with this validated contract once execution is unlocked."
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _handle_track_file_change(arguments: Dict[str, Any]) -> str:
|
|
193
|
+
action = arguments.get("action", "").strip().lower()
|
|
194
|
+
session_name = arguments.get("session_name", "").strip()
|
|
195
|
+
session: Optional[FableSession] = None
|
|
196
|
+
if not session_name:
|
|
197
|
+
return "Error: 'session_name' is required for action 'track_file_change'."
|
|
198
|
+
file_path = arguments.get("file_path", "").strip()
|
|
199
|
+
if not file_path:
|
|
200
|
+
return "Error: 'file_path' is required for action 'track_file_change'."
|
|
201
|
+
change_type = arguments.get("change_type", "").strip().lower()
|
|
202
|
+
if not change_type:
|
|
203
|
+
return "Error: 'change_type' ('modified', 'created', 'deleted', 'slated') is required for action 'track_file_change'."
|
|
204
|
+
diff_summary = arguments.get("diff_summary", "").strip()
|
|
205
|
+
if not diff_summary:
|
|
206
|
+
return "Error: 'diff_summary' is required for action 'track_file_change'."
|
|
207
|
+
rationale = arguments.get("rationale", "").strip()
|
|
208
|
+
affected_invariants = arguments.get("affected_invariants")
|
|
209
|
+
|
|
210
|
+
session = get_or_load_session(session_name)
|
|
211
|
+
entry = session.track_file_change(file_path, change_type, diff_summary, rationale, affected_invariants)
|
|
212
|
+
if getattr(session, "fable_run", None):
|
|
213
|
+
try:
|
|
214
|
+
from fable_v2.protocol import FileChangeRecord
|
|
215
|
+
session.fable_run.record_file_change(
|
|
216
|
+
FileChangeRecord(
|
|
217
|
+
file_path=file_path,
|
|
218
|
+
change_type=change_type,
|
|
219
|
+
before_hash=entry.get("before_hash"),
|
|
220
|
+
after_hash=entry.get("after_hash", ""),
|
|
221
|
+
diff_summary=diff_summary,
|
|
222
|
+
rationale=rationale or "",
|
|
223
|
+
affected_invariants=tuple(affected_invariants or []),
|
|
224
|
+
)
|
|
225
|
+
)
|
|
226
|
+
except Exception:
|
|
227
|
+
pass
|
|
228
|
+
session.save()
|
|
229
|
+
|
|
230
|
+
inv_str = f"\n- **Affected Invariants**: `{', '.join(entry['affected_invariants'])}`" if entry.get("affected_invariants") else ""
|
|
231
|
+
sha_str = f"\n- **File SHA256**: `{entry['sha256']}`" if entry.get("sha256") else ""
|
|
232
|
+
return (
|
|
233
|
+
f"### 📂 File Change Tracked\n\n"
|
|
234
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
235
|
+
f"- **Target File**: `{entry['file_path']}`\n"
|
|
236
|
+
f"- **Change Type**: `{entry['change_type'].upper()}`\n"
|
|
237
|
+
f"- **Diff Summary**: {entry['diff_summary']}\n"
|
|
238
|
+
f"- **Rationale**: {entry['rationale'] or 'N/A'}"
|
|
239
|
+
f"{sha_str}"
|
|
240
|
+
f"{inv_str}\n"
|
|
241
|
+
f"- **Total Tracked Changes**: `{len(session.file_changes)}`"
|
|
242
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _handle_get_session_lineage(arguments: Dict[str, Any]) -> str:
|
|
247
|
+
action = arguments.get("action", "").strip().lower()
|
|
248
|
+
session_name = arguments.get("session_name", "").strip()
|
|
249
|
+
session: Optional[FableSession] = None
|
|
250
|
+
if not session_name:
|
|
251
|
+
return "Error: 'session_name' is required for action 'get_session_lineage'."
|
|
252
|
+
session = get_or_load_session(session_name)
|
|
253
|
+
tel = session.get_telemetry()
|
|
254
|
+
v_prof = tel.get("velocity_profile", {})
|
|
255
|
+
|
|
256
|
+
# 1. Past files modified/created/deleted
|
|
257
|
+
past_files = [fc for fc in session.file_changes if fc.get("change_type") != "slated"]
|
|
258
|
+
past_lines = []
|
|
259
|
+
for pf in past_files:
|
|
260
|
+
sha = f" (`{pf['sha256'][:8]}`)" if pf.get("sha256") else ""
|
|
261
|
+
past_lines.append(f"- `[{pf['change_type'].upper()}]` `{pf['file_path']}`{sha}: {pf['diff_summary']}")
|
|
262
|
+
past_str = "\n".join(past_lines) if past_lines else "- No files modified or created yet."
|
|
263
|
+
|
|
264
|
+
# 2. Slated files
|
|
265
|
+
slated_files = [fc for fc in session.file_changes if fc.get("change_type") == "slated"]
|
|
266
|
+
slated_lines = []
|
|
267
|
+
for sf in slated_files:
|
|
268
|
+
slated_lines.append(f"- `[SLATED]` `{sf['file_path']}`: {sf['diff_summary']} (Rationale: {sf.get('rationale', 'N/A')})")
|
|
269
|
+
slated_str = "\n".join(slated_lines) if slated_lines else "- No upcoming files slated."
|
|
270
|
+
|
|
271
|
+
# 3. Roadmap & Phase History
|
|
272
|
+
phase_lines = []
|
|
273
|
+
for ph in session.phase_history:
|
|
274
|
+
phase_lines.append(f"- **{ph['phase']}**: {ph.get('summary', 'Entered')}")
|
|
275
|
+
roadmap_str = "\n".join(phase_lines)
|
|
276
|
+
|
|
277
|
+
# 4. Epistemic ledger
|
|
278
|
+
epi_lines = []
|
|
279
|
+
for item in session.epistemic_ledger:
|
|
280
|
+
rcpt = f" (Receipt: `{item['proof_receipt']['receipt_id']}`)" if item.get("proof_receipt") else ""
|
|
281
|
+
epi_lines.append(f"- `[{item['tag']}]` **{item['id']}**: {item['claim']}{rcpt}")
|
|
282
|
+
epi_str = "\n".join(epi_lines) if epi_lines else "- No epistemic items logged."
|
|
283
|
+
|
|
284
|
+
# 5. Invariants
|
|
285
|
+
inv_lines = []
|
|
286
|
+
for inv in session.invariants:
|
|
287
|
+
rcpt = f" (Receipt: `{inv['proof_receipt']['receipt_id']}`)" if inv.get("proof_receipt") else ""
|
|
288
|
+
inv_lines.append(f"- **{inv['name']}** `[{inv['domain']}]`: `{inv['formal_statement']}`{rcpt}")
|
|
289
|
+
inv_str = "\n".join(inv_lines) if inv_lines else "- No formal invariants recorded."
|
|
290
|
+
|
|
291
|
+
# 6. Visual mockups
|
|
292
|
+
vm = session.visual_mockups if isinstance(session.visual_mockups, dict) else {}
|
|
293
|
+
mockups_list = vm.get("mockups", [])
|
|
294
|
+
vm_lines = []
|
|
295
|
+
for m in mockups_list:
|
|
296
|
+
sel = " 🌟 *(SELECTED)*" if m.get("concept_name") == vm.get("selected_concept") else ""
|
|
297
|
+
vm_lines.append(f"- **{m.get('concept_name', 'Concept')}** `[{m.get('aesthetic_archetype', 'N/A')}]`{sel}: Palette: {m.get('palette', 'N/A')}, Typography: {m.get('typography', 'N/A')}")
|
|
298
|
+
vm_str = "\n".join(vm_lines) if vm_lines else "- No visual mockups recorded."
|
|
299
|
+
|
|
300
|
+
return (
|
|
301
|
+
f"### 🌐 Omniscient Session Lineage (`{session.session_name}`)\n\n"
|
|
302
|
+
f"#### 🎯 Mission Objective & Roadmap:\n"
|
|
303
|
+
f"- **Goal**: {session.objective}\n"
|
|
304
|
+
f"- **Active Phase**: `{session.active_phase}` (Phase {tel['phase_index']}/{tel['total_phases']})\n"
|
|
305
|
+
f"- **Pacing Remaining**: `{tel['pacing_remaining_formatted']}` / Authority: `{tel['authority_remaining_formatted']}`\n\n"
|
|
306
|
+
f"#### 🛣️ Phase Progression History:\n{roadmap_str}\n\n"
|
|
307
|
+
f"#### 📝 Completed File Mutations ({len(past_files)}):\n{past_str}\n\n"
|
|
308
|
+
f"#### 📋 Slated File Modifications ({len(slated_files)}):\n{slated_str}\n\n"
|
|
309
|
+
f"#### 🔬 Epistemic Grounding Ledger ({len(session.epistemic_ledger)} items):\n{epi_str}\n\n"
|
|
310
|
+
f"#### 📐 Formal Invariants & Contract Verification ({len(session.invariants)} items):\n{inv_str}\n\n"
|
|
311
|
+
f"#### 🎨 Visual Mockup Concepts & Spatial Spec:\n{vm_str}\n\n"
|
|
312
|
+
f"#### ⚡ Model Velocity & Capability Telemetry:\n"
|
|
313
|
+
f"- **Tier**: `{v_prof.get('model_tier', 'pro').upper()}` (Multiplier: `{v_prof.get('tier_multiplier', 1.0)}x`)\n"
|
|
314
|
+
f"- **Velocity**: `{v_prof.get('tokens_per_sec', 0.0)} est. tokens/sec` (`{v_prof.get('chars_per_sec', 0.0)} chars/sec`)\n"
|
|
315
|
+
f"- **Call Frequency**: `{v_prof.get('tool_call_frequency_cpm', 0.0)} calls/min` (Avg Interval: `{v_prof.get('avg_interval_seconds', 0.0)}s`)\n"
|
|
316
|
+
f"- **Total Ingested**: `{v_prof.get('total_requests', 0)} calls` / `{v_prof.get('total_estimated_tokens', 0)} est. tokens`"
|
|
317
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
318
|
+
)
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def _handle_inspect_plan(arguments: Dict[str, Any]) -> str:
|
|
322
|
+
action = arguments.get("action", "").strip().lower()
|
|
323
|
+
session_name = arguments.get("session_name", "").strip()
|
|
324
|
+
session: Optional[FableSession] = None
|
|
325
|
+
if not session_name:
|
|
326
|
+
return "Error: 'session_name' is required for action 'inspect_plan'."
|
|
327
|
+
session = get_or_load_session(session_name)
|
|
328
|
+
tel = session.get_telemetry()
|
|
329
|
+
gate_report = session._gate_report()
|
|
330
|
+
|
|
331
|
+
min_refinements = max(2, math.ceil(session.time_budget_minutes / 5.0))
|
|
332
|
+
current_refinements = len(session.refinement_cycles)
|
|
333
|
+
refinement_ok = current_refinements >= min_refinements
|
|
334
|
+
|
|
335
|
+
# Refinement history
|
|
336
|
+
ref_lines = []
|
|
337
|
+
for ref in session.refinement_cycles:
|
|
338
|
+
ref_lines.append(f"- **Cycle #{ref['cycle_number']}** `[{ref['refinement_type'].upper()}]` ({ref['focus_area']}): {ref['architectural_refinement']}")
|
|
339
|
+
ref_str = "\n".join(ref_lines) if ref_lines else "- No rethink-refine cycles logged yet."
|
|
340
|
+
|
|
341
|
+
# Slated files
|
|
342
|
+
slated_files = [fc for fc in session.file_changes if fc.get("change_type") == "slated"]
|
|
343
|
+
slated_lines = []
|
|
344
|
+
for sf in slated_files:
|
|
345
|
+
slated_lines.append(f"- `{sf['file_path']}`: {sf['diff_summary']}")
|
|
346
|
+
slated_str = "\n".join(slated_lines) if slated_lines else "- None declared yet."
|
|
347
|
+
|
|
348
|
+
# Gate checklist
|
|
349
|
+
c = gate_report["checks"]
|
|
350
|
+
gate_checklist = (
|
|
351
|
+
f"- [{'x' if c['two_proven_evidence_items'] else ' '}] At least 2 [PROVEN] facts with evidence ({gate_report['proven_with_evidence']}/2)\n"
|
|
352
|
+
f"- [{'x' if c['one_proved_invariant'] else ' '}] At least 1 formal Invariant with proof/rationale ({gate_report['invariants_with_proof']}/1)\n"
|
|
353
|
+
f"- [{'x' if c['adversarial_phase_reached'] else ' '}] Active Phase >= Phase 3 (Current: Phase {tel['phase_index']})\n"
|
|
354
|
+
f"- [{'x' if refinement_ok else ' '}] Anti-Idle Refinement Cycles ({current_refinements}/{min_refinements} required)\n"
|
|
355
|
+
f"- [{'x' if not session.execution_locked else ' '}] Immutable Authority Deadline Elapsed ({tel['authority_remaining_formatted']} remaining)"
|
|
356
|
+
)
|
|
357
|
+
|
|
358
|
+
delegation_guidelines = (
|
|
359
|
+
"1. Verify execution is unlocked (`can_execute_code: True`).\n"
|
|
360
|
+
"2. Compile Subagent Delegation Contracts with explicit `TargetFile`, `InterfaceContract`, `StrictConstraints`, and `VerificationCommand`.\n"
|
|
361
|
+
"3. Dispatch subagents to perform atomic codebase changes.\n"
|
|
362
|
+
"4. Enforce DoD validation via automated test suite execution."
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
return (
|
|
366
|
+
f"### 📋 Fable Execution Plan & Cognitive Blueprint (`{session.session_name}`)\n\n"
|
|
367
|
+
f"- **Objective**: {session.objective}\n"
|
|
368
|
+
f"- **Active Phase**: `{session.active_phase}`\n"
|
|
369
|
+
f"- **Execution Lock**: `{'🔴 LOCKED' if session.execution_locked else '🟢 UNLOCKED'}`\n\n"
|
|
370
|
+
f"#### 🚦 Cognitive Gate Status:\n{gate_checklist}\n\n"
|
|
371
|
+
f"#### 🔄 Rethink-Refine History ({current_refinements} cycles):\n{ref_str}\n\n"
|
|
372
|
+
f"#### 🛠️ Slated File Implementations:\n{slated_str}\n\n"
|
|
373
|
+
f"#### 🤖 Subagent Delegation & Implementer Instructions:\n{delegation_guidelines}"
|
|
374
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def _handle_verify_proof(arguments: Dict[str, Any]) -> str:
|
|
379
|
+
action = arguments.get("action", "").strip().lower()
|
|
380
|
+
session_name = arguments.get("session_name", "").strip()
|
|
381
|
+
session: Optional[FableSession] = None
|
|
382
|
+
claim = arguments.get("claim", "").strip()
|
|
383
|
+
if not claim:
|
|
384
|
+
return "Error: 'claim' is required for action 'verify_proof'."
|
|
385
|
+
proof_type = arguments.get("proof_type", "").strip().lower()
|
|
386
|
+
if not proof_type:
|
|
387
|
+
return "Error: 'proof_type' ('ast', 'receipt', 'file_sha256', 'formal_logic', 'vector_coordinates') is required for 'verify_proof'."
|
|
388
|
+
evidence = arguments.get("evidence", "")
|
|
389
|
+
target_resource = arguments.get("target_resource")
|
|
390
|
+
|
|
391
|
+
from fable_v2.proof_engine import DeterministicProofValidator
|
|
392
|
+
validator = DeterministicProofValidator()
|
|
393
|
+
result = validator.verify_proof(claim=claim, proof_type=proof_type, evidence=str(evidence), target_resource=target_resource)
|
|
394
|
+
|
|
395
|
+
if session_name:
|
|
396
|
+
try:
|
|
397
|
+
session = get_or_load_session(session_name)
|
|
398
|
+
session.proof_receipts.append(result)
|
|
399
|
+
if getattr(session, "fable_run", None):
|
|
400
|
+
try:
|
|
401
|
+
from fable_v2.protocol import ToolReceipt
|
|
402
|
+
session.fable_run.record_receipt(
|
|
403
|
+
ToolReceipt(
|
|
404
|
+
tool_name=f"proof_{proof_type}",
|
|
405
|
+
args={"claim": claim, "target_resource": target_resource},
|
|
406
|
+
output=result,
|
|
407
|
+
success=bool(result.get("verified")),
|
|
408
|
+
session_id=session.session_id,
|
|
409
|
+
)
|
|
410
|
+
)
|
|
411
|
+
except Exception:
|
|
412
|
+
pass
|
|
413
|
+
session.save()
|
|
414
|
+
except Exception:
|
|
415
|
+
pass
|
|
416
|
+
|
|
417
|
+
status_badge = "✅ VERIFIED" if result.get("verified") else "❌ FAILED"
|
|
418
|
+
err_msg = f"\n- **Error**: {result['error']}" if result.get("error") else ""
|
|
419
|
+
details_msg = f"\n- **Details**: {result['details']}" if result.get("details") else ""
|
|
420
|
+
return (
|
|
421
|
+
f"### ⚖️ Deterministic Proof Verification\n\n"
|
|
422
|
+
f"- **Status**: `{status_badge}`\n"
|
|
423
|
+
f"- **Receipt ID**: `{result.get('receipt_id')}`\n"
|
|
424
|
+
f"- **Proof Type**: `{result.get('proof_type')}`\n"
|
|
425
|
+
f"- **Claim**: {result.get('claim')}\n"
|
|
426
|
+
f"- **Timestamp**: `{time.ctime(result.get('timestamp', time.time()))}`"
|
|
427
|
+
f"{err_msg}"
|
|
428
|
+
f"{details_msg}"
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def _handle_record_visual_mockups(arguments: Dict[str, Any]) -> str:
|
|
433
|
+
action = arguments.get("action", "").strip().lower()
|
|
434
|
+
session_name = arguments.get("session_name", "").strip()
|
|
435
|
+
session: Optional[FableSession] = None
|
|
436
|
+
if not session_name:
|
|
437
|
+
return "Error: 'session_name' is required for action 'record_visual_mockups'."
|
|
438
|
+
mockups = arguments.get("mockups")
|
|
439
|
+
if not mockups:
|
|
440
|
+
return "Error: 'mockups' is required for action 'record_visual_mockups'."
|
|
441
|
+
selected_concept = arguments.get("selected_concept")
|
|
442
|
+
|
|
443
|
+
session = get_or_load_session(session_name)
|
|
444
|
+
vm = session.record_visual_mockups(mockups, selected_concept)
|
|
445
|
+
if getattr(session, "fable_run", None):
|
|
446
|
+
try:
|
|
447
|
+
from fable_v2.protocol import VisualMockupSpec
|
|
448
|
+
mockups_list = mockups if isinstance(mockups, list) else [mockups]
|
|
449
|
+
for idx, m in enumerate(mockups_list):
|
|
450
|
+
if isinstance(m, dict):
|
|
451
|
+
spec = VisualMockupSpec(
|
|
452
|
+
mockup_id=m.get("mockup_id", f"mockup_{len(session.fable_run.visual_mockups)+1}"),
|
|
453
|
+
concept_name=m.get("concept_name", f"Concept {idx+1}"),
|
|
454
|
+
aesthetic_archetype=m.get("aesthetic_archetype", "editorial"),
|
|
455
|
+
prompt=m.get("prompt", ""),
|
|
456
|
+
image_url=m.get("image_url"),
|
|
457
|
+
coordinates_data=m.get("coordinates_data"),
|
|
458
|
+
palette=tuple(m.get("palette", [])) if isinstance(m.get("palette"), (list, tuple)) else (),
|
|
459
|
+
typography=m.get("typography", {}) if isinstance(m.get("typography"), dict) else {},
|
|
460
|
+
status=m.get("status", "draft"),
|
|
461
|
+
selected_by_user=bool(selected_concept and m.get("concept_name") == selected_concept),
|
|
462
|
+
)
|
|
463
|
+
session.fable_run.record_visual_mockup(spec)
|
|
464
|
+
except Exception:
|
|
465
|
+
pass
|
|
466
|
+
session.save()
|
|
467
|
+
|
|
468
|
+
concept_lines = []
|
|
469
|
+
for m in vm.get("mockups", []):
|
|
470
|
+
sel = " 🌟 *(SELECTED)*" if m.get("concept_name") == vm.get("selected_concept") else ""
|
|
471
|
+
palette = m.get("palette", "N/A")
|
|
472
|
+
typo = m.get("typography", "N/A")
|
|
473
|
+
concept_lines.append(
|
|
474
|
+
f"- **{m.get('concept_name', 'Concept')}** `[{m.get('aesthetic_archetype', 'N/A')}]`{sel}\n"
|
|
475
|
+
f" * Prompt: {m.get('prompt', 'N/A')}\n"
|
|
476
|
+
f" * Palette: `{palette}` | Typography: `{typo}`\n"
|
|
477
|
+
f" * Coordinates: `{m.get('coordinates_data', 'N/A')}`"
|
|
478
|
+
)
|
|
479
|
+
concept_str = "\n".join(concept_lines)
|
|
480
|
+
|
|
481
|
+
return (
|
|
482
|
+
f"### 🎨 Visual Architectural Mockups Recorded\n\n"
|
|
483
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
484
|
+
f"- **Total Concepts**: `{len(vm.get('mockups', []))}`\n"
|
|
485
|
+
f"- **Selected Archetype**: `{vm.get('selected_concept')}`\n\n"
|
|
486
|
+
f"#### 🖼️ Concept Specifications:\n"
|
|
487
|
+
f"{concept_str}"
|
|
488
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
def _handle_validate_event_history(arguments: Dict[str, Any]) -> str:
|
|
493
|
+
action = arguments.get("action", "").strip().lower()
|
|
494
|
+
session_name = arguments.get("session_name", "").strip()
|
|
495
|
+
session: Optional[FableSession] = None
|
|
496
|
+
if not session_name:
|
|
497
|
+
return "Error: 'session_name' is required for action 'validate_event_history'."
|
|
498
|
+
session = get_or_load_session(session_name)
|
|
499
|
+
if not getattr(session, "fable_run", None):
|
|
500
|
+
return f"### ⚠️ Fable V2 Event History\n\nSession `{session.session_name}` does not have an active FableRun instance."
|
|
501
|
+
try:
|
|
502
|
+
session.fable_run.validate_event_history()
|
|
503
|
+
valid = True
|
|
504
|
+
details = "Cryptographic event chain is intact and verified against genesis root."
|
|
505
|
+
except Exception as ex:
|
|
506
|
+
valid = False
|
|
507
|
+
details = str(ex)
|
|
508
|
+
|
|
509
|
+
status_badge = "✅ VALID & INTACT" if valid else "❌ COMPROMISED / INVALID"
|
|
510
|
+
events = getattr(session.fable_run, "events", [])
|
|
511
|
+
genesis_hash = events[0].get("event_hash", "0"*64) if events else "None"
|
|
512
|
+
terminal_hash = events[-1].get("event_hash", "0"*64) if events else "None"
|
|
513
|
+
return (
|
|
514
|
+
f"### 🔗 Fable V2 Cryptographic Event Chain Audit\n\n"
|
|
515
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
516
|
+
f"- **Chain Status**: `{status_badge}`\n"
|
|
517
|
+
f"- **Total Events**: `{len(events)}`\n"
|
|
518
|
+
f"- **Genesis Hash**: `{str(genesis_hash)[:16]}...`\n"
|
|
519
|
+
f"- **Terminal Chain Hash**: `{str(terminal_hash)[:16]}...`\n"
|
|
520
|
+
f"- **Audit Summary**: {details}"
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
|