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,807 @@
|
|
|
1
|
+
"""Fleet quality rubrics, red team swarm review, cortical plasticity, and auto-update handlers."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import collections
|
|
5
|
+
from dataclasses import asdict
|
|
6
|
+
import json
|
|
7
|
+
import logging
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
import time
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger("fable-engine.actions.fleet")
|
|
15
|
+
|
|
16
|
+
from fable_engine.session import (
|
|
17
|
+
ACTIVE_SESSIONS,
|
|
18
|
+
PHASES,
|
|
19
|
+
SESSIONS_DIR,
|
|
20
|
+
SILENT_DELIBERATION_REMINDER,
|
|
21
|
+
FableSession,
|
|
22
|
+
SessionState,
|
|
23
|
+
_validate_session_name,
|
|
24
|
+
_validate_time_budget,
|
|
25
|
+
get_or_load_session,
|
|
26
|
+
get_plasticity_engine,
|
|
27
|
+
get_red_team_swarm,
|
|
28
|
+
)
|
|
29
|
+
from fable_engine.updater import AutoUpdater
|
|
30
|
+
|
|
31
|
+
def _get_swarm():
|
|
32
|
+
return get_red_team_swarm()
|
|
33
|
+
|
|
34
|
+
def _get_cortex():
|
|
35
|
+
return get_plasticity_engine()
|
|
36
|
+
|
|
37
|
+
def _handle_set_goal_rubric(arguments: Dict[str, Any]) -> str:
|
|
38
|
+
action = arguments.get("action", "").strip().lower()
|
|
39
|
+
session_name = arguments.get("session_name", "").strip()
|
|
40
|
+
session: Optional[FableSession] = None
|
|
41
|
+
if not session_name:
|
|
42
|
+
return "Error: 'session_name' is required for action 'set_goal_rubric'."
|
|
43
|
+
task_objective = arguments.get("task_objective") or arguments.get("objective") or ""
|
|
44
|
+
criteria = arguments.get("criteria") or arguments.get("items") or arguments.get("rubric_items")
|
|
45
|
+
if not criteria:
|
|
46
|
+
return "Error: 'criteria' (list of rubric criteria items/pointers) is required for 'set_goal_rubric'."
|
|
47
|
+
target_score = arguments.get("target_score", 0.95)
|
|
48
|
+
rubric_id = arguments.get("rubric_id")
|
|
49
|
+
meta = arguments.get("metadata")
|
|
50
|
+
|
|
51
|
+
session = get_or_load_session(session_name)
|
|
52
|
+
rubric = session.set_goal_rubric(
|
|
53
|
+
task_objective=task_objective,
|
|
54
|
+
criteria=criteria,
|
|
55
|
+
target_score=target_score,
|
|
56
|
+
rubric_id=rubric_id,
|
|
57
|
+
metadata=meta
|
|
58
|
+
)
|
|
59
|
+
session.save()
|
|
60
|
+
|
|
61
|
+
items_preview = "\n".join([
|
|
62
|
+
f"- `[{it['pointer_id']}]` (wt: {it['weight']:.1f}, score: {it['score']:.2f}, satisfied: {'✅' if it['satisfied'] else '⏳'}): {it['description']}"
|
|
63
|
+
for it in rubric["items"]
|
|
64
|
+
])
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
f"### 🎯 Goal Rubric Initialized (`{rubric['rubric_id']}`)\n\n"
|
|
68
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
69
|
+
f"- **Objective**: {rubric['task_objective']}\n"
|
|
70
|
+
f"- **Target Goal Score**: `{rubric['target_score'] * 100:.1f}%` (Strict Threshold: >= 95%)\n"
|
|
71
|
+
f"- **Current Composite Score**: `{rubric['current_score'] * 100:.1f}%`\n"
|
|
72
|
+
f"- **Status**: `{rubric['status'].upper()}`\n"
|
|
73
|
+
f"- **Criteria Pointers Count**: `{len(rubric['items'])}`\n\n"
|
|
74
|
+
f"#### 📋 Criteria Pointers Breakdown:\n"
|
|
75
|
+
f"{items_preview}"
|
|
76
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _handle_evaluate_goal_rubric(arguments: Dict[str, Any]) -> str:
|
|
81
|
+
action = arguments.get("action", "").strip().lower()
|
|
82
|
+
session_name = arguments.get("session_name", "").strip()
|
|
83
|
+
session: Optional[FableSession] = None
|
|
84
|
+
if not session_name:
|
|
85
|
+
return "Error: 'session_name' is required for action 'evaluate_goal_rubric'."
|
|
86
|
+
rubric_id = arguments.get("rubric_id")
|
|
87
|
+
item_evaluations = arguments.get("item_evaluations") or arguments.get("evaluations") or arguments.get("items")
|
|
88
|
+
|
|
89
|
+
session = get_or_load_session(session_name)
|
|
90
|
+
rubric = session.evaluate_goal_rubric(
|
|
91
|
+
rubric_id=rubric_id,
|
|
92
|
+
item_evaluations=item_evaluations
|
|
93
|
+
)
|
|
94
|
+
session.save()
|
|
95
|
+
|
|
96
|
+
status_badge = "🟢 ACHIEVED (>= 95%)" if rubric["status"] == "achieved" else "🟡 IN_PROGRESS (< 95%)"
|
|
97
|
+
items_preview = "\n".join([
|
|
98
|
+
f"- `[{it['pointer_id']}]` ({it['score']*100:.0f}%, {'✅ SATISFIED' if it['satisfied'] else '⏳ PENDING'}): {it['description']}" +
|
|
99
|
+
(f" [Receipt: `{it['evidence_receipt_id']}`]" if it.get('evidence_receipt_id') else "")
|
|
100
|
+
for it in rubric["items"]
|
|
101
|
+
])
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
f"### 📈 Goal Rubric Evaluation (`{rubric['rubric_id']}`)\n\n"
|
|
105
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
106
|
+
f"- **Composite Goal Score**: `{rubric['current_score'] * 100:.2f}%`\n"
|
|
107
|
+
f"- **Target Score**: `{rubric['target_score'] * 100:.1f}%`\n"
|
|
108
|
+
f"- **Status**: `{status_badge}`\n\n"
|
|
109
|
+
f"#### 📊 Criteria Pointers Status:\n"
|
|
110
|
+
f"{items_preview}"
|
|
111
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _handle_get_goal_rubric(arguments: Dict[str, Any]) -> str:
|
|
116
|
+
action = arguments.get("action", "").strip().lower()
|
|
117
|
+
session_name = arguments.get("session_name", "").strip()
|
|
118
|
+
session: Optional[FableSession] = None
|
|
119
|
+
if not session_name:
|
|
120
|
+
return "Error: 'session_name' is required for action 'get_goal_rubric'."
|
|
121
|
+
rubric_id = arguments.get("rubric_id")
|
|
122
|
+
|
|
123
|
+
session = get_or_load_session(session_name)
|
|
124
|
+
rubric = session.get_goal_rubric(rubric_id=rubric_id)
|
|
125
|
+
if not rubric:
|
|
126
|
+
return f"### ⚠️ No Goal Rubric Found\n\nSession `{session.session_name}` has no registered goal rubrics."
|
|
127
|
+
|
|
128
|
+
status_badge = "🟢 ACHIEVED" if rubric["status"] == "achieved" else "🟡 IN_PROGRESS"
|
|
129
|
+
items_preview = "\n".join([
|
|
130
|
+
f"- `[{it['pointer_id']}]` (wt: {it['weight']:.1f}, score: {it['score']*100:.0f}%, {'✅' if it['satisfied'] else '⏳'}): {it['description']}" +
|
|
131
|
+
(f" (Verifier: `{it['verifier_command']}`)" if it.get('verifier_command') else "")
|
|
132
|
+
for it in rubric["items"]
|
|
133
|
+
])
|
|
134
|
+
|
|
135
|
+
return (
|
|
136
|
+
f"### 📋 Goal Rubric Details (`{rubric['rubric_id']}`)\n\n"
|
|
137
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
138
|
+
f"- **Task Objective**: {rubric['task_objective']}\n"
|
|
139
|
+
f"- **Target Score**: `{rubric['target_score'] * 100:.1f}%`\n"
|
|
140
|
+
f"- **Current Score**: `{rubric['current_score'] * 100:.2f}%`\n"
|
|
141
|
+
f"- **Status**: `{status_badge}`\n\n"
|
|
142
|
+
f"#### 📑 Criteria Breakdown:\n"
|
|
143
|
+
f"{items_preview}"
|
|
144
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def _handle_register_automation_pipeline(arguments: Dict[str, Any]) -> str:
|
|
149
|
+
action = arguments.get("action", "").strip().lower()
|
|
150
|
+
session_name = arguments.get("session_name", "").strip()
|
|
151
|
+
session: Optional[FableSession] = None
|
|
152
|
+
if not session_name:
|
|
153
|
+
return "Error: 'session_name' is required for action 'register_automation_pipeline'."
|
|
154
|
+
name = arguments.get("name") or arguments.get("pipeline_name") or ""
|
|
155
|
+
if not name:
|
|
156
|
+
return "Error: 'name' is required for 'register_automation_pipeline'."
|
|
157
|
+
pipeline_type = arguments.get("pipeline_type", "closed_loop")
|
|
158
|
+
generator_command = arguments.get("generator_command") or arguments.get("generator_cmd") or ""
|
|
159
|
+
evaluator_command = arguments.get("evaluator_command") or arguments.get("evaluator_cmd") or ""
|
|
160
|
+
target_threshold = arguments.get("target_threshold") if arguments.get("target_threshold") is not None else arguments.get("target_score", 0.95)
|
|
161
|
+
max_iterations = arguments.get("max_iterations", 10)
|
|
162
|
+
meta = arguments.get("metadata")
|
|
163
|
+
|
|
164
|
+
session = get_or_load_session(session_name)
|
|
165
|
+
pipe = session.register_automation_pipeline(
|
|
166
|
+
name=name,
|
|
167
|
+
pipeline_type=pipeline_type,
|
|
168
|
+
generator_command=generator_command,
|
|
169
|
+
evaluator_command=evaluator_command,
|
|
170
|
+
target_threshold=target_threshold,
|
|
171
|
+
max_iterations=max_iterations,
|
|
172
|
+
metadata=meta
|
|
173
|
+
)
|
|
174
|
+
session.save()
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
f"### ⚙️ Autonomous Pipeline Registered (`{pipe['pipeline_id']}`)\n\n"
|
|
178
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
179
|
+
f"- **Pipeline Name**: `{pipe['name']}`\n"
|
|
180
|
+
f"- **Pipeline Type**: `{pipe['pipeline_type']}`\n"
|
|
181
|
+
f"- **Generator Command**: `{pipe['generator_command'] or 'N/A'}`\n"
|
|
182
|
+
f"- **Evaluator Command**: `{pipe['evaluator_command'] or 'N/A'}`\n"
|
|
183
|
+
f"- **Target Threshold**: `{pipe['target_threshold'] * 100:.1f}%`\n"
|
|
184
|
+
f"- **Max Iterations**: `{pipe['max_iterations']}`\n"
|
|
185
|
+
f"- **Status**: `ACTIVE 🚀`"
|
|
186
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _handle_red_team_code_review(arguments: Dict[str, Any]) -> str:
|
|
191
|
+
action = arguments.get("action", "").strip().lower()
|
|
192
|
+
session_name = arguments.get("session_name", "").strip()
|
|
193
|
+
if not session_name:
|
|
194
|
+
return "Error: 'session_name' is required for action 'red_team_code_review'."
|
|
195
|
+
|
|
196
|
+
target_name = arguments.get("target_name", "system")
|
|
197
|
+
code_snippet = None
|
|
198
|
+
for k in ("target_code", "code_snippet", "code", "target_callable"):
|
|
199
|
+
if k in arguments and arguments[k] is not None:
|
|
200
|
+
code_snippet = arguments[k]
|
|
201
|
+
break
|
|
202
|
+
|
|
203
|
+
if code_snippet is not None and not callable(code_snippet):
|
|
204
|
+
return (
|
|
205
|
+
"Error: Source-code strings cannot be evaluated in-process for security reasons. "
|
|
206
|
+
"Dynamic source-code execution is disabled for public actions until an isolated sandbox executor is configured."
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
custom_hypotheses = arguments.get("custom_hypotheses") or arguments.get("hypotheses")
|
|
210
|
+
output_path = arguments.get("output_path")
|
|
211
|
+
|
|
212
|
+
session = get_or_load_session(session_name)
|
|
213
|
+
try:
|
|
214
|
+
report = _get_swarm().run_full_review_cycle(
|
|
215
|
+
target_callable=code_snippet,
|
|
216
|
+
target_name=target_name,
|
|
217
|
+
custom_hypotheses=custom_hypotheses,
|
|
218
|
+
)
|
|
219
|
+
report_dict = report.to_dict()
|
|
220
|
+
if int(report_dict.get("broken_count", 0)) == 0:
|
|
221
|
+
if not session._fresh_stage_records()[2]:
|
|
222
|
+
return "Error: A current immutable reviewed_change_id is required before accepting a clean review."
|
|
223
|
+
change_id = str(arguments.get("reviewed_change_id") or session.derive_reviewed_change_id()).strip()
|
|
224
|
+
report_dict["report_origin"] = "red_team_swarm"
|
|
225
|
+
report_dict["reviewed_change_id"] = change_id
|
|
226
|
+
report_dict["attack_vector_results"] = session._attack_vector_results(report_dict)
|
|
227
|
+
report_dict["red_team_receipt"] = session.issue_red_team_receipt(report_dict, change_id)
|
|
228
|
+
session.record_breakage_report(report_dict)
|
|
229
|
+
except (TypeError, ValueError) as exc:
|
|
230
|
+
return f"Error: Cannot record red-team report: {exc}"
|
|
231
|
+
session.save()
|
|
232
|
+
|
|
233
|
+
md_report = _get_swarm().document_breakage(report, output_path=output_path)
|
|
234
|
+
return (
|
|
235
|
+
f"{md_report}\n\n"
|
|
236
|
+
f"- **Session Recorded**: `{session.session_name}`\n"
|
|
237
|
+
f"- **Total Breakage Reports in Session**: `{len(session.breakage_reports)}`"
|
|
238
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def _handle_record_breakage_report(arguments: Dict[str, Any]) -> str:
|
|
243
|
+
action = arguments.get("action", "").strip().lower()
|
|
244
|
+
session_name = arguments.get("session_name", "").strip()
|
|
245
|
+
session: Optional[FableSession] = None
|
|
246
|
+
if not session_name:
|
|
247
|
+
return "Error: 'session_name' is required for action 'record_breakage_report'."
|
|
248
|
+
report_data = arguments.get("report") or arguments.get("report_data") or {}
|
|
249
|
+
if not report_data and (arguments.get("findings") is not None or arguments.get("broken_scenarios") is not None):
|
|
250
|
+
raw_findings = arguments.get("findings") if arguments.get("findings") is not None else arguments.get("broken_scenarios", [])
|
|
251
|
+
broken_cnt = arguments.get("broken_count")
|
|
252
|
+
if broken_cnt is None:
|
|
253
|
+
broken_cnt = sum(1 for f in raw_findings if (f.get("broken", True) if isinstance(f, dict) else getattr(f, "broken", True)))
|
|
254
|
+
report_data = {
|
|
255
|
+
"report_id": arguments.get("report_id", f"report_{int(time.time())}"),
|
|
256
|
+
"target_name": arguments.get("target_name", "system"),
|
|
257
|
+
"total_probes": arguments.get("total_probes", len(raw_findings)),
|
|
258
|
+
"broken_count": int(broken_cnt),
|
|
259
|
+
"passed": arguments.get("passed", int(broken_cnt) == 0),
|
|
260
|
+
"findings": raw_findings,
|
|
261
|
+
"created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
|
262
|
+
"remediation_directives": arguments.get("remediation_directives", [])
|
|
263
|
+
}
|
|
264
|
+
if not report_data:
|
|
265
|
+
return "Error: 'report', 'report_data', 'findings', or 'broken_scenarios' is required for 'record_breakage_report'."
|
|
266
|
+
|
|
267
|
+
session = get_or_load_session(session_name)
|
|
268
|
+
try:
|
|
269
|
+
session.record_breakage_report(dict(report_data))
|
|
270
|
+
broken_count = int(report_data.get("broken_count", 0))
|
|
271
|
+
except (TypeError, ValueError) as exc:
|
|
272
|
+
return f"Error: Cannot record breakage report: {exc}"
|
|
273
|
+
session.save()
|
|
274
|
+
|
|
275
|
+
if broken_count > 0:
|
|
276
|
+
directives = report_data.get("remediation_directives") or [
|
|
277
|
+
f"Remediate {item.get('hypothesis', item.get('scenario_id', 'breakage'))}"
|
|
278
|
+
for item in session.active_breakages
|
|
279
|
+
]
|
|
280
|
+
directives_list = "\n".join(f"- {directive}" for directive in directives)
|
|
281
|
+
order_msg = f"TASK REJECTED: {broken_count} breakages detected. Deploy subagent to fix findings."
|
|
282
|
+
escalation = session.current_state == SessionState.ESCALATION_UNRESOLVED_BREAKAGES
|
|
283
|
+
arbitration_message = (
|
|
284
|
+
"> **Human architecture arbitration required: remediation bounds exceeded.**\n"
|
|
285
|
+
if escalation else ""
|
|
286
|
+
)
|
|
287
|
+
return (
|
|
288
|
+
f"### 🚨 {order_msg}\n\n"
|
|
289
|
+
f"> [!CAUTION]\n> **{order_msg}**\n\n"
|
|
290
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
291
|
+
f"- **Current State**: `{session.current_state.value}` 🔴\n"
|
|
292
|
+
f"- **Broken Count**: `{broken_count}`\n"
|
|
293
|
+
f"- **Active Breakages Tracked**: `{len(session.active_breakages)}`\n"
|
|
294
|
+
f"- **Remediation Attempts**: `{session.remediation_attempt_count}`\n"
|
|
295
|
+
f"{arbitration_message}"
|
|
296
|
+
f"\n#### 🛠️ Structured Remediation Directives:\n{directives_list}\n"
|
|
297
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
return (
|
|
301
|
+
"### 🛡️ TASK COMPLETED: 0 breakages remain. Code sealed.\n\n"
|
|
302
|
+
"🟢 **TASK COMPLETED: 0 breakages remain. Code sealed.**\n\n"
|
|
303
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
304
|
+
f"- **Current State**: `{session.current_state.value}` 🟢\n"
|
|
305
|
+
"- **Broken Count**: `0`\n"
|
|
306
|
+
"- **Status**: Verified resilient. Ready for `evolve_cortex`."
|
|
307
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
308
|
+
)
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
def _handle_verify_red_team_remediation(arguments: Dict[str, Any]) -> str:
|
|
312
|
+
action = arguments.get("action", "").strip().lower()
|
|
313
|
+
session_name = arguments.get("session_name", "").strip()
|
|
314
|
+
if not session_name:
|
|
315
|
+
return "Error: 'session_name' is required for action 'verify_red_team_remediation'."
|
|
316
|
+
|
|
317
|
+
remediated_code = None
|
|
318
|
+
for k in ("remediated_code", "target_code", "code_snippet", "code", "target_callable"):
|
|
319
|
+
if k in arguments and arguments[k] is not None:
|
|
320
|
+
remediated_code = arguments[k]
|
|
321
|
+
break
|
|
322
|
+
|
|
323
|
+
if remediated_code is not None and not callable(remediated_code):
|
|
324
|
+
return (
|
|
325
|
+
"Error: Source-code strings cannot be evaluated in-process for security reasons. "
|
|
326
|
+
"Dynamic source-code execution is disabled for public actions until an isolated sandbox executor is configured."
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
session = get_or_load_session(session_name)
|
|
330
|
+
|
|
331
|
+
report_id = arguments.get("report_id")
|
|
332
|
+
prior_report = arguments.get("prior_report")
|
|
333
|
+
|
|
334
|
+
if not prior_report:
|
|
335
|
+
if report_id:
|
|
336
|
+
prior_report = next((r for r in session.breakage_reports if r.get("report_id") == str(report_id).strip()), None)
|
|
337
|
+
elif session.breakage_reports:
|
|
338
|
+
prior_report = session.breakage_reports[-1]
|
|
339
|
+
|
|
340
|
+
if not prior_report:
|
|
341
|
+
return "Error: No prior breakage report found to verify. Provide 'report_id' or 'prior_report'."
|
|
342
|
+
try:
|
|
343
|
+
timeout_sec = float(arguments.get("timeout_seconds", 3.0))
|
|
344
|
+
all_fixed, verification = _get_swarm().verify_remediation(
|
|
345
|
+
target_callable=remediated_code,
|
|
346
|
+
prior_report=prior_report,
|
|
347
|
+
timeout_seconds=timeout_sec,
|
|
348
|
+
)
|
|
349
|
+
report = verification.to_dict()
|
|
350
|
+
# A seal requires a fresh review across all five vectors, not only the
|
|
351
|
+
# scenarios that failed in the prior report.
|
|
352
|
+
if all_fixed and verification.broken_count == 0:
|
|
353
|
+
report = _get_swarm().run_full_review_cycle(
|
|
354
|
+
target_callable=remediated_code,
|
|
355
|
+
target_name=verification.target_name,
|
|
356
|
+
auto_consolidate=False,
|
|
357
|
+
).to_dict()
|
|
358
|
+
if int(report.get("broken_count", 0)) == 0:
|
|
359
|
+
if not session._fresh_stage_records()[2]:
|
|
360
|
+
return "Error: A current immutable reviewed_change_id is required before accepting a clean remediation."
|
|
361
|
+
change_id = str(
|
|
362
|
+
arguments.get("reviewed_change_id")
|
|
363
|
+
or report.get("reviewed_change_id")
|
|
364
|
+
or session.derive_reviewed_change_id()
|
|
365
|
+
).strip()
|
|
366
|
+
report["report_origin"] = "red_team_swarm"
|
|
367
|
+
report["reviewed_change_id"] = change_id
|
|
368
|
+
report["attack_vector_results"] = session._attack_vector_results(report)
|
|
369
|
+
report["red_team_receipt"] = session.issue_red_team_receipt(report, change_id)
|
|
370
|
+
session.record_breakage_report(report)
|
|
371
|
+
except (TypeError, ValueError) as exc:
|
|
372
|
+
return f"Error: Cannot record remediation verification: {exc}"
|
|
373
|
+
|
|
374
|
+
session.save()
|
|
375
|
+
broken_count = int(report.get("broken_count", 0))
|
|
376
|
+
if broken_count > 0:
|
|
377
|
+
directives = report.get("remediation_directives", [])
|
|
378
|
+
directives_list = "\n".join(f"- {directive}" for directive in directives)
|
|
379
|
+
order_msg = f"TASK REJECTED: {broken_count} breakages detected. Deploy subagent to fix findings."
|
|
380
|
+
escalation = session.current_state == SessionState.ESCALATION_UNRESOLVED_BREAKAGES
|
|
381
|
+
arbitration_message = (
|
|
382
|
+
"> **Human architecture arbitration required: remediation bounds exceeded.**\n"
|
|
383
|
+
if escalation else ""
|
|
384
|
+
)
|
|
385
|
+
return (
|
|
386
|
+
f"### 🚨 {order_msg}\n\n> [!CAUTION]\n> **{order_msg}**\n\n"
|
|
387
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
388
|
+
f"- **Current State**: `{session.current_state.value}` 🔴 "
|
|
389
|
+
f"(Attempt {session.remediation_attempt_count})\n"
|
|
390
|
+
f"- **Remaining Breakages**: `{broken_count}`\n"
|
|
391
|
+
f"{arbitration_message}\n"
|
|
392
|
+
f"#### 🛠️ Directives for Next Remediation Cycle:\n{directives_list}\n"
|
|
393
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
completed_msg = "TASK COMPLETED: 0 breakages remain. Code sealed."
|
|
397
|
+
return (
|
|
398
|
+
f"### 🛡️ {completed_msg}\n\n🟢 **{completed_msg}**\n\n"
|
|
399
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
400
|
+
f"- **Current State**: `{session.current_state.value}` 🟢\n"
|
|
401
|
+
"- **Broken Count**: `0`\n"
|
|
402
|
+
f"- **Remediation Iterations**: `{session.iteration_count}`\n\n"
|
|
403
|
+
"> [!NOTE]\n> All prior adversarial breakages resolved with zero regressions. Session is in `SEALED` state. Automatically proceed or advance to `EVOLVED` state via `evolve_cortex`."
|
|
404
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def _handle_evolve_cortex(arguments: Dict[str, Any]) -> str:
|
|
409
|
+
action = arguments.get("action", "").strip().lower()
|
|
410
|
+
session_name = arguments.get("session_name", "").strip()
|
|
411
|
+
session: Optional[FableSession] = None
|
|
412
|
+
if not session_name:
|
|
413
|
+
return "Error: 'session_name' is required for action 'evolve_cortex'."
|
|
414
|
+
session = get_or_load_session(session_name)
|
|
415
|
+
|
|
416
|
+
if session.current_state not in (SessionState.SEALED, SessionState.EVOLVED):
|
|
417
|
+
return f"Error: evolve_cortex rejected: Session must be in SEALED or EVOLVED state (current state: {session.current_state.value})."
|
|
418
|
+
|
|
419
|
+
domain = arguments.get("domain") or "python"
|
|
420
|
+
task_id = arguments.get("task_id") or session.session_id
|
|
421
|
+
|
|
422
|
+
neutralized_scenarios = arguments.get("broken_scenarios") or []
|
|
423
|
+
if not neutralized_scenarios:
|
|
424
|
+
for rep in session.breakage_reports:
|
|
425
|
+
for f in rep.get("findings", []):
|
|
426
|
+
if isinstance(f, dict) and f.get("broken"):
|
|
427
|
+
neutralized_scenarios.append(f)
|
|
428
|
+
elif hasattr(f, "broken") and f.broken:
|
|
429
|
+
neutralized_scenarios.append(f.to_dict() if hasattr(f, "to_dict") else asdict(f))
|
|
430
|
+
for hist in session.remediation_history:
|
|
431
|
+
for b in hist.get("breakages", []):
|
|
432
|
+
if b not in neutralized_scenarios:
|
|
433
|
+
neutralized_scenarios.append(b)
|
|
434
|
+
|
|
435
|
+
co_activated_nodes = arguments.get("co_activated_nodes") or ["mutation", "test_harness", "red_team_swarm", "property_oracle"]
|
|
436
|
+
|
|
437
|
+
cortex = _get_cortex()
|
|
438
|
+
evo_receipt = cortex.consolidate_task(
|
|
439
|
+
task_id=task_id,
|
|
440
|
+
success=True,
|
|
441
|
+
domain=domain,
|
|
442
|
+
broken_scenarios=neutralized_scenarios,
|
|
443
|
+
co_activated_nodes=co_activated_nodes,
|
|
444
|
+
)
|
|
445
|
+
lobe_path = cortex._get_lobe_path(domain).resolve()
|
|
446
|
+
|
|
447
|
+
session.transition_to(SessionState.EVOLVED, "Cortical evolution consolidation completed")
|
|
448
|
+
session.save()
|
|
449
|
+
|
|
450
|
+
antibodies_list = "\n".join([f"- `ab_{domain}_{s.get('scenario_id', 'unknown')}`: {s.get('hypothesis', 'Neutralized breakage')}" for s in neutralized_scenarios]) if neutralized_scenarios else "- Antibodies consolidated into cortical lobe."
|
|
451
|
+
weights_table = "\n".join([f"| `{k}` | `{v:.4f}` | `+0.10 * A_domain * A_node (LTP)` |" for k, v in evo_receipt.get("synaptic_weights", {}).items()])
|
|
452
|
+
|
|
453
|
+
return (
|
|
454
|
+
f"### 🧬 Cortical Evolution Receipt: EVOLVED\n\n"
|
|
455
|
+
f"- **Session**: `{session.session_name}`\n"
|
|
456
|
+
f"- **Current State**: `EVOLVED` 🌟\n"
|
|
457
|
+
f"- **Domain Lobe**: `{domain}` (`{lobe_path}`)\n"
|
|
458
|
+
f"- **Task ID**: `{task_id}`\n"
|
|
459
|
+
f"- **Plasticity Mode**: `LTP (Long-Term Potentiation)` (Score: +1.0)\n"
|
|
460
|
+
f"- **Antibodies Added**: `{evo_receipt.get('antibodies_added', 0)}`\n"
|
|
461
|
+
f"- **Total Lobe Antibodies**: `{evo_receipt.get('total_antibodies', 0)}`\n"
|
|
462
|
+
f"- **A_domain**: `{evo_receipt.get('A_domain', 0.80)}`\n\n"
|
|
463
|
+
f"#### 🛡️ Synthesized Heuristic Antibodies:\n{antibodies_list}\n\n"
|
|
464
|
+
f"#### ⚡ Potentiated Synaptic Weights:\n"
|
|
465
|
+
f"| Node | Potentiated Weight | Hebbian Rule |\n"
|
|
466
|
+
f"| :--- | :---: | :--- |\n"
|
|
467
|
+
f"{weights_table}\n\n"
|
|
468
|
+
f"> [!TIP]\n"
|
|
469
|
+
f"> Cortical lobe `{lobe_path}` successfully evolved and persisted to disk."
|
|
470
|
+
f"{SILENT_DELIBERATION_REMINDER if session.execution_locked else ''}"
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def _handle_cortical_define_lobe(arguments: Dict[str, Any]) -> str:
|
|
475
|
+
action = arguments.get("action", "").strip().lower()
|
|
476
|
+
session_name = arguments.get("session_name", "").strip()
|
|
477
|
+
session: Optional[FableSession] = None
|
|
478
|
+
name = arguments.get("name") or arguments.get("lobe_name") or ""
|
|
479
|
+
if not name:
|
|
480
|
+
return "Error: 'name' or 'lobe_name' is required for action 'cortical_define_lobe'."
|
|
481
|
+
description = arguments.get("description") or arguments.get("desc") or ""
|
|
482
|
+
initial_heuristics = arguments.get("initial_heuristics") or arguments.get("heuristics") or []
|
|
483
|
+
initial_synaptic_weights = arguments.get("initial_synaptic_weights") or arguments.get("synaptic_weights") or {}
|
|
484
|
+
|
|
485
|
+
lobe = _get_cortex().define_cortical_lobe(
|
|
486
|
+
name=str(name),
|
|
487
|
+
description=str(description),
|
|
488
|
+
initial_heuristics=initial_heuristics if isinstance(initial_heuristics, list) else [str(initial_heuristics)],
|
|
489
|
+
initial_synaptic_weights=initial_synaptic_weights if isinstance(initial_synaptic_weights, dict) else {},
|
|
490
|
+
)
|
|
491
|
+
session = get_or_load_session(session_name) if session_name else None
|
|
492
|
+
|
|
493
|
+
md_output = (
|
|
494
|
+
f"### 🧠 Cortical Lobe Sprouted: `{lobe.name}`\n\n"
|
|
495
|
+
f"- **Name**: `{lobe.name}`\n"
|
|
496
|
+
f"- **Description**: {lobe.description}\n"
|
|
497
|
+
f"- **Domain**: `{lobe.domain}`\n"
|
|
498
|
+
f"- **Heuristics Initialized**: `{len(lobe.specialized_heuristics)}`\n"
|
|
499
|
+
f"- **Synaptic Nodes**: `{len(lobe.synaptic_weights)}`\n"
|
|
500
|
+
f"- **File Path**: `skills/fable-mode/cortex/{lobe.name}.md`\n"
|
|
501
|
+
)
|
|
502
|
+
if session and session.execution_locked:
|
|
503
|
+
md_output += SILENT_DELIBERATION_REMINDER
|
|
504
|
+
return md_output
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
def _handle_cortical_list_lobes(arguments: Dict[str, Any]) -> str:
|
|
508
|
+
action = arguments.get("action", "").strip().lower()
|
|
509
|
+
session_name = arguments.get("session_name", "").strip()
|
|
510
|
+
session: Optional[FableSession] = None
|
|
511
|
+
lobes = _get_cortex().list_cortical_lobes()
|
|
512
|
+
session = get_or_load_session(session_name) if session_name else None
|
|
513
|
+
|
|
514
|
+
lines = [
|
|
515
|
+
"### 🧠 Available Cortical Lobes",
|
|
516
|
+
"",
|
|
517
|
+
f"Total Lobes: `{len(lobes)}`",
|
|
518
|
+
"",
|
|
519
|
+
"| Lobe Name | Description | Activations | Antibodies | Heuristics |",
|
|
520
|
+
"| :--- | :--- | :--- | :--- | :--- |",
|
|
521
|
+
]
|
|
522
|
+
for l in lobes:
|
|
523
|
+
desc = l['description'][:60] + "..." if len(l['description']) > 60 else (l['description'] or "—")
|
|
524
|
+
lines.append(f"| `{l['name']}` | {desc} | `{l['activation_count']}` | `{l['antibody_count']}` | `{l['heuristic_count']}` |")
|
|
525
|
+
|
|
526
|
+
md_output = "\n".join(lines)
|
|
527
|
+
if session and session.execution_locked:
|
|
528
|
+
md_output += SILENT_DELIBERATION_REMINDER
|
|
529
|
+
return md_output
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def _handle_check_auto_update(arguments: Dict[str, Any]) -> str:
|
|
533
|
+
action = arguments.get("action", "").strip().lower()
|
|
534
|
+
session_name = arguments.get("session_name", "").strip()
|
|
535
|
+
session: Optional[FableSession] = None
|
|
536
|
+
if AutoUpdater is None:
|
|
537
|
+
return "Error: AutoUpdater module is unavailable."
|
|
538
|
+
updater = AutoUpdater()
|
|
539
|
+
res = updater.check_for_updates()
|
|
540
|
+
session = get_or_load_session(session_name) if session_name else None
|
|
541
|
+
lines = [
|
|
542
|
+
"### 🔄 Fable Autonomous Auto-Updater Status",
|
|
543
|
+
"",
|
|
544
|
+
f"- **Update Available**: `{res.get('update_available', False)}`",
|
|
545
|
+
f"- **Local Commit**: `{res.get('local_commit', 'unknown')}`",
|
|
546
|
+
f"- **Remote Commit**: `{res.get('remote_commit', 'unknown')}`",
|
|
547
|
+
f"- **Offline / Standalone**: `{res.get('offline', False)}`",
|
|
548
|
+
f"- **Status**: {res.get('message', '')}",
|
|
549
|
+
]
|
|
550
|
+
md_output = "\n".join(lines)
|
|
551
|
+
if session and session.execution_locked:
|
|
552
|
+
md_output += SILENT_DELIBERATION_REMINDER
|
|
553
|
+
return md_output
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
def _handle_apply_auto_update(arguments: Dict[str, Any]) -> str:
|
|
557
|
+
action = arguments.get("action", "").strip().lower()
|
|
558
|
+
session_name = arguments.get("session_name", "").strip()
|
|
559
|
+
session: Optional[FableSession] = None
|
|
560
|
+
if AutoUpdater is None:
|
|
561
|
+
return "Error: AutoUpdater module is unavailable."
|
|
562
|
+
preserve_cortex = arguments.get("preserve_cortex", True)
|
|
563
|
+
if isinstance(preserve_cortex, str):
|
|
564
|
+
preserve_cortex = preserve_cortex.lower() not in ("false", "0", "no")
|
|
565
|
+
updater = AutoUpdater()
|
|
566
|
+
res = updater.apply_update(preserve_cortex=preserve_cortex)
|
|
567
|
+
session = get_or_load_session(session_name) if session_name else None
|
|
568
|
+
status_emoji = "✅" if res.get("success") else "⚠️"
|
|
569
|
+
targets = res.get("synced_targets", [])
|
|
570
|
+
synced_str = ", ".join(f"`{t}`" for t in targets) if targets else "None"
|
|
571
|
+
preserved = res.get("preserved_lobes", [])
|
|
572
|
+
pres_str = ", ".join(f"`{p}`" for p in preserved) if preserved else "None"
|
|
573
|
+
lines = [
|
|
574
|
+
f"### {status_emoji} Fable Autonomous Auto-Updater Applied",
|
|
575
|
+
"",
|
|
576
|
+
f"- **Success**: `{res.get('success', False)}`",
|
|
577
|
+
f"- **Updated**: `{res.get('updated', False)}`",
|
|
578
|
+
f"- **Message**: {res.get('message', '')}",
|
|
579
|
+
f"- **Preserved Cortical Lobes**: {pres_str}",
|
|
580
|
+
f"- **Host Targets Synced**: {synced_str}",
|
|
581
|
+
]
|
|
582
|
+
md_output = "\n".join(lines)
|
|
583
|
+
if session and session.execution_locked:
|
|
584
|
+
md_output += SILENT_DELIBERATION_REMINDER
|
|
585
|
+
return md_output
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
try:
|
|
589
|
+
from fable_v2.coder_fleet.design_engine import (
|
|
590
|
+
AestheticArchetype,
|
|
591
|
+
DesignDials,
|
|
592
|
+
DesignEngine,
|
|
593
|
+
HAUTE_THEMES,
|
|
594
|
+
)
|
|
595
|
+
except ImportError:
|
|
596
|
+
DesignEngine = None
|
|
597
|
+
HAUTE_THEMES = {}
|
|
598
|
+
|
|
599
|
+
_GLOBAL_DESIGN_ENGINE = None
|
|
600
|
+
|
|
601
|
+
def _get_design_engine():
|
|
602
|
+
global _GLOBAL_DESIGN_ENGINE
|
|
603
|
+
if _GLOBAL_DESIGN_ENGINE is None and DesignEngine is not None:
|
|
604
|
+
_GLOBAL_DESIGN_ENGINE = DesignEngine()
|
|
605
|
+
return _GLOBAL_DESIGN_ENGINE
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
def _handle_audit_anti_slop(arguments: Dict[str, Any]) -> str:
|
|
609
|
+
code = arguments.get("code") or arguments.get("content") or arguments.get("html") or arguments.get("source") or ""
|
|
610
|
+
file_path = arguments.get("file_path", "")
|
|
611
|
+
session_name = arguments.get("session_name", "").strip()
|
|
612
|
+
session = get_or_load_session(session_name) if session_name else None
|
|
613
|
+
engine = _get_design_engine()
|
|
614
|
+
if engine is None:
|
|
615
|
+
return "Error: DesignEngine module is unavailable."
|
|
616
|
+
|
|
617
|
+
res = engine.audit_anti_slop(code, file_path=file_path)
|
|
618
|
+
status_badge = "🟢 CLEAN (ZERO AI SLOP)" if res["clean"] else f"🔴 FAILED ({res['total_violations']} VIOLATIONS)"
|
|
619
|
+
lines = [
|
|
620
|
+
f"### 🛡️ Anti-Slop Design Audit: {status_badge}",
|
|
621
|
+
"",
|
|
622
|
+
f"- **Anti-Slop Score**: `{res['score'] * 100:.1f}%`",
|
|
623
|
+
f"- **Clean**: `{res['clean']}`",
|
|
624
|
+
f"- **Fatal Violations**: `{res['fatal_count']}`",
|
|
625
|
+
f"- **High Violations**: `{res['high_count']}`",
|
|
626
|
+
f"- **Medium Violations**: `{res['medium_count']}`",
|
|
627
|
+
"",
|
|
628
|
+
]
|
|
629
|
+
if res["violations"]:
|
|
630
|
+
lines.append("#### ⚠️ Violations Breakdown:")
|
|
631
|
+
for v in res["violations"]:
|
|
632
|
+
lines.append(f"- **[{v['severity']}] `{v['rule_id']}`** (Line {v['line_number'] or 'N/A'}): {v['message']}")
|
|
633
|
+
lines.append(f" - *Snippet*: `{v['snippet']}`")
|
|
634
|
+
lines.append(f" - *Remedy*: {v['remedy']}")
|
|
635
|
+
else:
|
|
636
|
+
lines.append("✅ **All Anti-Slop Gates Passed**: Zero purple blobs, zero centered 3-card boilerplates, zero LLM marketing fluff, zero fake div dots, zero viewport instability.")
|
|
637
|
+
|
|
638
|
+
md_output = "\n".join(lines)
|
|
639
|
+
if session and session.execution_locked:
|
|
640
|
+
md_output += SILENT_DELIBERATION_REMINDER
|
|
641
|
+
return md_output
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
def _handle_infer_design_brief(arguments: Dict[str, Any]) -> str:
|
|
645
|
+
prompt = arguments.get("prompt") or arguments.get("user_prompt") or arguments.get("brief") or ""
|
|
646
|
+
dials_override = arguments.get("dials_override") or arguments.get("dials")
|
|
647
|
+
archetype_override = arguments.get("archetype_override") or arguments.get("archetype")
|
|
648
|
+
session_name = arguments.get("session_name", "").strip()
|
|
649
|
+
session = get_or_load_session(session_name) if session_name else None
|
|
650
|
+
engine = _get_design_engine()
|
|
651
|
+
if engine is None:
|
|
652
|
+
return "Error: DesignEngine module is unavailable."
|
|
653
|
+
|
|
654
|
+
res = engine.infer_design_brief(prompt, dials_override=dials_override, archetype_override=archetype_override)
|
|
655
|
+
dials = res["dials"]
|
|
656
|
+
palette = res["palette"]
|
|
657
|
+
typo = res["typography"]
|
|
658
|
+
layout = res["layout_blueprint"]
|
|
659
|
+
lines = [
|
|
660
|
+
"### 🎨 Fable Brief Inference & Design Read",
|
|
661
|
+
"",
|
|
662
|
+
f"> **{res['design_read']}**",
|
|
663
|
+
"",
|
|
664
|
+
f"- **Page Kind**: `{res['page_kind']}`",
|
|
665
|
+
f"- **Target Audience**: {res['target_audience']}",
|
|
666
|
+
f"- **Optimal Archetype**: `{res['archetype_title']}` (`{res['archetype']}`)",
|
|
667
|
+
f"- **Aesthetic Vector**: Variance `{dials['variance']}` / Motion `{dials['motion']}` / Density `{dials['density']}`",
|
|
668
|
+
"",
|
|
669
|
+
"#### 🎨 Curated OKLCH Palette:",
|
|
670
|
+
f"- Background Void: `{palette['bg_void']}`",
|
|
671
|
+
f"- Surface Card: `{palette['surface_card']}`",
|
|
672
|
+
f"- Hairline Border: `{palette['border_hairline']}`",
|
|
673
|
+
f"- Primary Accent: `{palette['accent_primary']}`",
|
|
674
|
+
f"- Primary Text: `{palette['text_primary']}`",
|
|
675
|
+
"",
|
|
676
|
+
"#### 🔤 Typographic Pairings:",
|
|
677
|
+
f"- Display: `{typo['display']}`",
|
|
678
|
+
f"- Body: `{typo['body']}`",
|
|
679
|
+
f"- Monospace: `{typo['mono']}`",
|
|
680
|
+
"",
|
|
681
|
+
"#### 📐 Layout Architecture:",
|
|
682
|
+
f"- Hero Stack: Max {layout['hero_stack_max_elements']} text elements, cap at {layout['hero_top_padding_cap']}",
|
|
683
|
+
f"- Navigation: {layout['navigation_height_cap']}",
|
|
684
|
+
f"- Grid: {layout['bento_grid_structure']}",
|
|
685
|
+
f"- CTA Constraint: {layout['desktop_cta_rule']}",
|
|
686
|
+
]
|
|
687
|
+
md_output = "\n".join(lines)
|
|
688
|
+
if session and session.execution_locked:
|
|
689
|
+
md_output += SILENT_DELIBERATION_REMINDER
|
|
690
|
+
return md_output
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
def _handle_generate_design_tokens(arguments: Dict[str, Any]) -> str:
|
|
694
|
+
archetype = arguments.get("archetype") or arguments.get("name") or "cyber_obsidian_monolith"
|
|
695
|
+
session_name = arguments.get("session_name", "").strip()
|
|
696
|
+
session = get_or_load_session(session_name) if session_name else None
|
|
697
|
+
engine = _get_design_engine()
|
|
698
|
+
if engine is None:
|
|
699
|
+
return "Error: DesignEngine module is unavailable."
|
|
700
|
+
|
|
701
|
+
data = engine.generate_design_tokens(archetype=archetype)
|
|
702
|
+
lines = [
|
|
703
|
+
f"### 🎛️ Haute Design Tokens: `{data['title']}`",
|
|
704
|
+
"",
|
|
705
|
+
f"> {data['description']}",
|
|
706
|
+
"",
|
|
707
|
+
f"- **Radius Scale**: `{data['border_radius_scale']}`",
|
|
708
|
+
f"- **Spring Physics**: `{data['spring_physics']['name']}` (Stiffness: {data['spring_physics']['stiffness']}, Damping: {data['spring_physics']['damping']}, Mass: {data['spring_physics']['mass']})",
|
|
709
|
+
f"- **WCAG Contrast**: `{data['wcag_aa_contrast']['primary_to_bg_ratio']}:1` ({'✅ Meets AA' if data['wcag_aa_contrast']['meets_wcag_aa'] else '⚠️ Below AA'})",
|
|
710
|
+
"",
|
|
711
|
+
"```css",
|
|
712
|
+
data["tailwind_v4_theme"],
|
|
713
|
+
"```",
|
|
714
|
+
]
|
|
715
|
+
md_output = "\n".join(lines)
|
|
716
|
+
if session and session.execution_locked:
|
|
717
|
+
md_output += SILENT_DELIBERATION_REMINDER
|
|
718
|
+
return md_output
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
def _handle_generate_awwwards_scaffold(arguments: Dict[str, Any]) -> str:
|
|
722
|
+
prompt = arguments.get("prompt") or arguments.get("user_prompt") or arguments.get("brief") or "Modern software platform"
|
|
723
|
+
archetype = arguments.get("archetype") or arguments.get("archetype_override") or arguments.get("name")
|
|
724
|
+
session_name = arguments.get("session_name", "").strip()
|
|
725
|
+
session = get_or_load_session(session_name) if session_name else None
|
|
726
|
+
engine = _get_design_engine()
|
|
727
|
+
if engine is None:
|
|
728
|
+
return "Error: DesignEngine module is unavailable."
|
|
729
|
+
|
|
730
|
+
res = engine.generate_awwwards_scaffold(prompt=prompt, archetype_override=archetype)
|
|
731
|
+
lines = [
|
|
732
|
+
f"### 🏆 Awwwards-Caliber Zero-Slop Scaffold Generated",
|
|
733
|
+
"",
|
|
734
|
+
f"> **{res['design_read']}**",
|
|
735
|
+
"",
|
|
736
|
+
f"- **Aesthetic Archetype**: `{res['theme_title']}` (`{res['archetype']}`)",
|
|
737
|
+
f"- **Anti-Slop Verified**: `{'✅ 100% CLEAN' if res['anti_slop_verified'] else '⚠️ VIOLATIONS DETECTED'}` (Score: `{res['audit_result']['score'] * 100:.1f}%`)",
|
|
738
|
+
"",
|
|
739
|
+
"#### 🎨 Tailwind CSS v4 Theme:",
|
|
740
|
+
"```css",
|
|
741
|
+
res["tailwind_v4_theme"],
|
|
742
|
+
"```",
|
|
743
|
+
"",
|
|
744
|
+
"#### 🏗️ Semantic 7-Layer HTML/JSX Layout:",
|
|
745
|
+
"```html",
|
|
746
|
+
res["html_layout"][:2000] + "\n... [Full layout available via code export]",
|
|
747
|
+
"```",
|
|
748
|
+
]
|
|
749
|
+
md_output = "\n".join(lines)
|
|
750
|
+
if session and session.execution_locked:
|
|
751
|
+
md_output += SILENT_DELIBERATION_REMINDER
|
|
752
|
+
return md_output
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
def _handle_validate_preflight_design(arguments: Dict[str, Any]) -> str:
|
|
756
|
+
code = arguments.get("code") or arguments.get("content") or arguments.get("html") or arguments.get("source") or ""
|
|
757
|
+
session_name = arguments.get("session_name", "").strip()
|
|
758
|
+
session = get_or_load_session(session_name) if session_name else None
|
|
759
|
+
engine = _get_design_engine()
|
|
760
|
+
if engine is None:
|
|
761
|
+
return "Error: DesignEngine module is unavailable."
|
|
762
|
+
|
|
763
|
+
res = engine.validate_preflight_design(code)
|
|
764
|
+
status_badge = "🟢 PRE-FLIGHT APPROVED" if res["approved"] else "🔴 PRE-FLIGHT REJECTED"
|
|
765
|
+
lines = [
|
|
766
|
+
f"### 🚦 5-Point Pre-Flight Design Gate: {status_badge}",
|
|
767
|
+
"",
|
|
768
|
+
f"- **Composite Score**: `{res['composite_score'] * 100:.1f}%`",
|
|
769
|
+
f"- **Passed Checks**: `{res['passed_checks']}/{res['total_checks']}`",
|
|
770
|
+
f"- **Approved**: `{res['approved']}`",
|
|
771
|
+
"",
|
|
772
|
+
"#### 📋 5-Point Verification Checklist:",
|
|
773
|
+
]
|
|
774
|
+
for chk in res["checklist"]:
|
|
775
|
+
mark = "✅ PASSED" if chk["passed"] else "❌ FAILED"
|
|
776
|
+
lines.append(f"- **Point {chk['point']} ({chk['name']})**: {mark} — {chk['details']}")
|
|
777
|
+
|
|
778
|
+
md_output = "\n".join(lines)
|
|
779
|
+
if session and session.execution_locked:
|
|
780
|
+
md_output += SILENT_DELIBERATION_REMINDER
|
|
781
|
+
return md_output
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
def _handle_list_design_archetypes(arguments: Dict[str, Any]) -> str:
|
|
785
|
+
session_name = arguments.get("session_name", "").strip()
|
|
786
|
+
session = get_or_load_session(session_name) if session_name else None
|
|
787
|
+
engine = _get_design_engine()
|
|
788
|
+
if engine is None:
|
|
789
|
+
return "Error: DesignEngine module is unavailable."
|
|
790
|
+
|
|
791
|
+
archetypes = engine.list_design_archetypes()
|
|
792
|
+
lines = [
|
|
793
|
+
"### 🏛️ Haute Aesthetic Archetypes (Anti-Slop Universes)",
|
|
794
|
+
"",
|
|
795
|
+
"| Archetype Key | Title | Dials (V/M/D) | Aesthetic Character |",
|
|
796
|
+
"| :--- | :--- | :--- | :--- |",
|
|
797
|
+
]
|
|
798
|
+
for arch in archetypes:
|
|
799
|
+
d = arch["dials"]
|
|
800
|
+
lines.append(f"| `{arch['archetype']}` | **{arch['title']}** | `{d['variance']}/{d['motion']}/{d['density']}` | {arch['description']} |")
|
|
801
|
+
|
|
802
|
+
lines.append("")
|
|
803
|
+
lines.append("Use `action: 'generate_design_tokens'` with `archetype: '<key>'` or `action: 'generate_awwwards_scaffold'` to scaffold.")
|
|
804
|
+
md_output = "\n".join(lines)
|
|
805
|
+
if session and session.execution_locked:
|
|
806
|
+
md_output += SILENT_DELIBERATION_REMINDER
|
|
807
|
+
return md_output
|