@heretek-ai/epistemic-swarm 0.2.2 ā 0.3.0
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.
- package/.agents/skills/brainstorming/SKILL.md +13 -0
- package/.agents/skills/code_audit/SKILL.md +13 -0
- package/.agents/skills/epistemic_search/SKILL.md +13 -0
- package/.agents/skills/grilling/SKILL.md +13 -0
- package/.agents/skills/oss_scout/SKILL.md +13 -0
- package/.agents/skills/research_cache/SKILL.md +13 -0
- package/.agents/skills/swarm_config/SKILL.md +13 -0
- package/.claude-plugin/plugin.json +15 -5
- package/.omp/README.md +39 -0
- package/.omp/SYSTEM.md +12 -0
- package/.omp/commands/audit.md +10 -0
- package/.omp/commands/brainstorming.md +12 -0
- package/.omp/commands/grill.md +9 -0
- package/.omp/commands/scout.md +10 -0
- package/.omp/commands/swarm-config.md +10 -0
- package/.omp/commands/swarm.md +9 -0
- package/.omp/hooks/post/epistemic-audit.ts +16 -0
- package/.omp/hooks/pre/epistemic-redirect.ts +21 -0
- package/.omp/prompts/brainstorming.md +8 -0
- package/.omp/prompts/swarm.md +8 -0
- package/MARKETPLACE.md +8 -0
- package/README.md +53 -8
- package/bin/cli.js +27 -3
- package/config/domain_packs/biopharma.json +23 -0
- package/config/domain_packs/legal.json +19 -0
- package/config/domain_packs/quant.json +19 -0
- package/config/mcp-research-servers.json +7 -0
- package/config/mcp_launcher.py +48 -137
- package/config/opencode-snippet.json +58 -3
- package/config/searxng_mcp.py +42 -83
- package/extensions/pi/index.js +196 -28
- package/install.sh +20 -4
- package/package.json +40 -5
- package/plugins/antigravity/README.md +28 -0
- package/plugins/antigravity/agents/alpha-thesis.md +6 -0
- package/plugins/antigravity/agents/beta-antithesis.md +7 -0
- package/plugins/antigravity/agents/brainstormer.md +7 -0
- package/plugins/antigravity/agents/epistemic-auditor.md +5 -0
- package/plugins/antigravity/hooks.json +23 -0
- package/plugins/antigravity/mcp_config.json +33 -0
- package/plugins/antigravity/plugin.json +21 -0
- package/plugins/antigravity/rules/epistemic-integrity.md +6 -0
- package/plugins/antigravity/skills/brainstorming/SKILL.md +13 -0
- package/plugins/antigravity/skills/code_audit/SKILL.md +13 -0
- package/plugins/antigravity/skills/epistemic_search/SKILL.md +13 -0
- package/plugins/antigravity/skills/grilling/SKILL.md +13 -0
- package/plugins/antigravity/skills/oss_scout/SKILL.md +13 -0
- package/plugins/antigravity/skills/research_cache/SKILL.md +13 -0
- package/plugins/antigravity/skills/swarm_config/SKILL.md +13 -0
- package/plugins/codex/AGENTS.md.snippet +10 -0
- package/plugins/codex/README.md +37 -0
- package/plugins/codex/config.toml.snippet +28 -0
- package/plugins/codex/openai.yaml +24 -0
- package/plugins/codex/skills/brainstorming/SKILL.md +13 -0
- package/plugins/codex/skills/code_audit/SKILL.md +13 -0
- package/plugins/codex/skills/epistemic_search/SKILL.md +13 -0
- package/plugins/codex/skills/grilling/SKILL.md +13 -0
- package/plugins/codex/skills/oss_scout/SKILL.md +13 -0
- package/plugins/codex/skills/research_cache/SKILL.md +13 -0
- package/plugins/codex/skills/swarm_config/SKILL.md +13 -0
- package/plugins/gemini/GEMINI.md +15 -0
- package/plugins/gemini/README.md +19 -0
- package/plugins/gemini/commands/audit.toml +6 -0
- package/plugins/gemini/commands/brainstorming.toml +10 -0
- package/plugins/gemini/commands/grill.toml +6 -0
- package/plugins/gemini/commands/scout.toml +7 -0
- package/plugins/gemini/commands/swarm-config.toml +7 -0
- package/plugins/gemini/commands/swarm.toml +8 -0
- package/plugins/gemini/gemini-extension.json +38 -0
- package/plugins/gemini/hooks/hooks.json +11 -0
- package/plugins/gemini/skills/brainstorming/SKILL.md +13 -0
- package/plugins/gemini/skills/code_audit/SKILL.md +13 -0
- package/plugins/gemini/skills/epistemic_search/SKILL.md +13 -0
- package/plugins/gemini/skills/grilling/SKILL.md +13 -0
- package/plugins/gemini/skills/oss_scout/SKILL.md +13 -0
- package/plugins/gemini/skills/research_cache/SKILL.md +13 -0
- package/plugins/gemini/skills/swarm_config/SKILL.md +13 -0
- package/plugins/opencode/index.js +335 -118
- package/prompts/agent_brainstormer.md +97 -0
- package/runner/__pycache__/__init__.cpython-311.pyc +0 -0
- package/runner/__pycache__/auctioneer.cpython-311.pyc +0 -0
- package/runner/__pycache__/auditor_engine.cpython-311.pyc +0 -0
- package/runner/__pycache__/claim_store.cpython-311.pyc +0 -0
- package/runner/__pycache__/claim_witness.cpython-311.pyc +0 -0
- package/runner/__pycache__/living_dossiers.cpython-311.pyc +0 -0
- package/runner/__pycache__/mcp_protocol.cpython-311.pyc +0 -0
- package/runner/__pycache__/mcp_server.cpython-311.pyc +0 -0
- package/runner/__pycache__/pcrb.cpython-311.pyc +0 -0
- package/runner/__pycache__/pcrb_verify.cpython-311.pyc +0 -0
- package/runner/__pycache__/refinement.cpython-311.pyc +0 -0
- package/runner/__pycache__/research_swarm.cpython-311.pyc +0 -0
- package/runner/__pycache__/state_machine.cpython-311.pyc +0 -0
- package/runner/auctioneer.py +169 -0
- package/runner/auditor_engine.py +127 -12
- package/runner/claim_store.py +361 -0
- package/runner/claim_witness.py +183 -0
- package/runner/living_dossiers.py +355 -0
- package/runner/mcp_protocol.py +188 -0
- package/runner/mcp_server.py +567 -0
- package/runner/pcrb.py +212 -0
- package/runner/pcrb_verify.py +237 -0
- package/runner/refinement.py +335 -0
- package/runner/research_swarm.py +378 -94
- package/runner/tests/__pycache__/test_auction_order.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_claim_store.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_claim_witness.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_domain_packs.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_fleet_seam.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_living_dossiers.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_mcp_server.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_pcrb.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_refinement.cpython-311.pyc +0 -0
- package/runner/tests/__pycache__/test_swarm.cpython-311.pyc +0 -0
- package/runner/tests/fixtures/auction_objective.json +35 -0
- package/runner/tests/fixtures/borderline_claims.json +27 -0
- package/runner/tests/fixtures/divergence_objectives.json +31 -0
- package/runner/tests/test_auction_order.py +173 -0
- package/runner/tests/test_claim_store.py +162 -0
- package/runner/tests/test_claim_witness.py +186 -0
- package/runner/tests/test_domain_packs.py +217 -0
- package/runner/tests/test_fleet_seam.py +113 -0
- package/runner/tests/test_living_dossiers.py +204 -0
- package/runner/tests/test_mcp_server.py +212 -0
- package/runner/tests/test_pcrb.py +240 -0
- package/runner/tests/test_refinement.py +255 -0
- package/runner/tests/test_swarm.py +173 -15
- package/scripts/auction_experiment.py +180 -0
- package/scripts/build_adapters.py +183 -0
- package/scripts/divergence_experiment.py +184 -0
- package/skills/brainstorming/SKILL.md +106 -0
- package/skills/brainstorming/__init__.py +1 -0
- package/skills/brainstorming/scripts/brainstorm.py +200 -0
- package/skills/research_cache/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/research_cache/__pycache__/hasher.cpython-311.pyc +0 -0
- package/skills/swarm_config/SKILL.md +1 -1
- package/skills/swarm_config/__pycache__/__init__.cpython-311.pyc +0 -0
- package/skills/swarm_config/__pycache__/configure.cpython-311.pyc +0 -0
- package/skills/swarm_config/configure.py +45 -11
package/runner/research_swarm.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Epistemic Swarm: Dialectic Multi-Agent Research Runner.
|
|
4
4
|
Executes parallel Claude Code sub-processes (claude -p) for Proponent and Adversary agents,
|
|
5
5
|
monitors filesystem IPC scratchpads, and invokes the Epistemic Auditor.
|
|
6
|
-
Supports multiple modes: research, audit (codebase), scout (OSS), and
|
|
6
|
+
Supports multiple modes: research, audit (codebase), scout (OSS), hybrid, and brainstorm (lateral ideation).
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
9
|
import os
|
|
@@ -15,7 +15,7 @@ import subprocess
|
|
|
15
15
|
from pathlib import Path
|
|
16
16
|
from datetime import datetime, timezone
|
|
17
17
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
18
|
-
from typing import Dict, Any, List, Optional
|
|
18
|
+
from typing import Dict, Any, List, Optional, Tuple
|
|
19
19
|
|
|
20
20
|
# Ensure project root is in sys.path
|
|
21
21
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
@@ -26,38 +26,97 @@ from runner.auditor_engine import EpistemicAuditorEngine
|
|
|
26
26
|
from skills.research_cache.hasher import SourceHasher
|
|
27
27
|
from skills.swarm_config.configure import load_config
|
|
28
28
|
|
|
29
|
+
|
|
29
30
|
class SwarmRunner:
|
|
30
|
-
def __init__(
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
base_dir: Optional[Path] = None,
|
|
34
|
+
mock_mode: bool = False,
|
|
35
|
+
mode: Optional[str] = None,
|
|
36
|
+
engine: Optional[str] = None,
|
|
37
|
+
depth: Optional[int] = None,
|
|
38
|
+
agent_overrides: Optional[Dict[str, Dict[str, Any]]] = None,
|
|
39
|
+
allocation: Optional[str] = None,
|
|
40
|
+
domain_pack: Optional[str] = None,
|
|
41
|
+
):
|
|
33
42
|
self.base_dir = base_dir or Path(".research")
|
|
34
43
|
self.mock_mode = mock_mode
|
|
35
44
|
self.config = load_config(str(self.base_dir))
|
|
36
45
|
self.mode = mode or self.config.get("mode", "research")
|
|
37
46
|
self.engine = engine or self.config.get("search_engine", "duckduckgo")
|
|
38
47
|
self.depth = depth or self.config.get("max_iterations", 2)
|
|
48
|
+
# Stream F: "dag" (legacy default) or "auction" (Frontier Markets).
|
|
49
|
+
self.allocation = allocation or self.config.get("allocation", "dag")
|
|
50
|
+
# Stream G: optional Domain Pack (constitution) for the auditor.
|
|
51
|
+
self.domain_pack = domain_pack if domain_pack is not None else self.config.get("domain_pack")
|
|
52
|
+
# Per-agent backend/model overrides (CLI > env > config > default).
|
|
53
|
+
# Keys are role names ("alpha", "beta"); values are {"backend": [...],
|
|
54
|
+
# "model": str|None}. Empty dict means "fall through to next source".
|
|
55
|
+
self.agent_overrides: Dict[str, Dict[str, Any]] = agent_overrides or {}
|
|
39
56
|
self.state_machine = ResearchStateMachine(base_dir=self.base_dir)
|
|
40
57
|
self.auditor = EpistemicAuditorEngine(base_dir=self.base_dir)
|
|
41
58
|
self.hasher = SourceHasher(base_dir=self.base_dir)
|
|
42
59
|
self.prompts_dir = PROJECT_ROOT / "prompts"
|
|
43
60
|
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
|
|
61
|
+
def _resolve_agent_backend(self, role: str) -> Tuple[List[str], Optional[str]]:
|
|
62
|
+
"""Resolve (backend_cmd, model) for an agent role.
|
|
63
|
+
|
|
64
|
+
Precedence (Stream E): explicit override (set by CLI flags) > env >
|
|
65
|
+
config > default. Returns (["claude", "-p"], None) when nothing is
|
|
66
|
+
configured, preserving prior behavior byte-for-byte.
|
|
67
|
+
"""
|
|
68
|
+
override = self.agent_overrides.get(role) or {}
|
|
69
|
+
env_backend = os.environ.get(f"IUMBTEMS_BACKEND_{role.upper()}")
|
|
70
|
+
env_model = os.environ.get(f"IUMBTEMS_MODEL_{role.upper()}")
|
|
71
|
+
|
|
72
|
+
agents_cfg = self.config.get("agents") or {}
|
|
73
|
+
role_cfg = agents_cfg.get(role) or {}
|
|
74
|
+
|
|
75
|
+
backend = (
|
|
76
|
+
override.get("backend")
|
|
77
|
+
or (env_backend.split() if env_backend else None)
|
|
78
|
+
or role_cfg.get("backend")
|
|
79
|
+
or ["claude", "-p"]
|
|
80
|
+
)
|
|
81
|
+
model = override.get("model") or env_model or role_cfg.get("model")
|
|
82
|
+
return list(backend), model
|
|
83
|
+
|
|
84
|
+
def build_agent_cmd(
|
|
85
|
+
self,
|
|
86
|
+
prompt: str,
|
|
87
|
+
system_prompt_file: Optional[Path] = None,
|
|
88
|
+
tools: str = "default",
|
|
89
|
+
role: str = "alpha",
|
|
90
|
+
) -> List[str]:
|
|
91
|
+
"""Construct the backend argv for an agent. Pure ā no subprocess.
|
|
92
|
+
|
|
93
|
+
Exposed separately so tests can assert argv shape (e.g. `--model`
|
|
94
|
+
present when configured, absent in mock/default) without spawning.
|
|
95
|
+
"""
|
|
96
|
+
backend, model = self._resolve_agent_backend(role)
|
|
97
|
+
cmd = list(backend) + [prompt, "--tools", tools]
|
|
98
|
+
if model:
|
|
99
|
+
cmd.extend(["--model", str(model)])
|
|
100
|
+
if system_prompt_file and system_prompt_file.exists():
|
|
101
|
+
cmd.extend(["--system-prompt", str(system_prompt_file)])
|
|
102
|
+
return cmd
|
|
103
|
+
|
|
104
|
+
def run_claude_process(
|
|
105
|
+
self,
|
|
106
|
+
prompt: str,
|
|
107
|
+
system_prompt_file: Optional[Path] = None,
|
|
108
|
+
tools: str = "default",
|
|
109
|
+
role: str = "alpha",
|
|
110
|
+
) -> str:
|
|
111
|
+
"""Executes a headless agent session on the configured backend."""
|
|
47
112
|
if self.mock_mode:
|
|
48
113
|
return self._mock_claude_response(prompt)
|
|
49
114
|
|
|
50
|
-
cmd =
|
|
51
|
-
if system_prompt_file and system_prompt_file.exists():
|
|
52
|
-
cmd.extend(["--system-prompt", str(system_prompt_file)])
|
|
115
|
+
cmd = self.build_agent_cmd(prompt, system_prompt_file, tools, role=role)
|
|
53
116
|
|
|
54
117
|
try:
|
|
55
118
|
res = subprocess.run(
|
|
56
|
-
cmd,
|
|
57
|
-
capture_output=True,
|
|
58
|
-
text=True,
|
|
59
|
-
check=True,
|
|
60
|
-
cwd=str(PROJECT_ROOT)
|
|
119
|
+
cmd, capture_output=True, text=True, check=True, cwd=str(PROJECT_ROOT)
|
|
61
120
|
)
|
|
62
121
|
return res.stdout.strip()
|
|
63
122
|
except subprocess.CalledProcessError as e:
|
|
@@ -67,25 +126,35 @@ class SwarmRunner:
|
|
|
67
126
|
def _mock_claude_response(self, prompt: str) -> str:
|
|
68
127
|
"""Mock response generator for unit testing without live API keys."""
|
|
69
128
|
if "Orchestrator" in prompt or "manifest.json" in prompt:
|
|
70
|
-
return json.dumps(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
129
|
+
return json.dumps(
|
|
130
|
+
{
|
|
131
|
+
"session_id": "mock-session-001",
|
|
132
|
+
"objective": "Evaluate ZK prover latency",
|
|
133
|
+
"scopes": [
|
|
134
|
+
{
|
|
135
|
+
"scope_id": "scope_01_latency",
|
|
136
|
+
"title": "Hardware Prover Latency Bounds",
|
|
137
|
+
"objective": "Evaluate Poseidon hash witness generation latency on FPGAs vs GPUs",
|
|
138
|
+
"dependencies": [],
|
|
139
|
+
"affirmative_targets": [
|
|
140
|
+
"Sub-200ms witness generation on 2^20 constraints"
|
|
141
|
+
],
|
|
142
|
+
"adversarial_targets": [
|
|
143
|
+
"PCIe bus bottlenecks during batch streaming"
|
|
144
|
+
],
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
}
|
|
148
|
+
)
|
|
84
149
|
return "MOCK_RESPONSE"
|
|
85
150
|
|
|
86
|
-
def orchestrate_objective(
|
|
151
|
+
def orchestrate_objective(
|
|
152
|
+
self, objective: str, frontier_file: Optional[Path] = None
|
|
153
|
+
) -> List[Dict[str, Any]]:
|
|
87
154
|
"""Phase 1: Run Swarm Orchestrator to decompose the research/audit question."""
|
|
88
|
-
print(
|
|
155
|
+
print(
|
|
156
|
+
f"\nš§ [Phase 1: Orchestration] Decomposing objective ({self.mode.upper()} mode): '{objective}'..."
|
|
157
|
+
)
|
|
89
158
|
self.state_machine.init_session(objective)
|
|
90
159
|
self.state_machine.update_session_status(SessionStatus.ORCHESTRATING)
|
|
91
160
|
|
|
@@ -105,8 +174,10 @@ Max Depth: {self.depth}
|
|
|
105
174
|
Output ONLY valid JSON representing the scope decomposition conforming to prompts/orchestrator.md.
|
|
106
175
|
"""
|
|
107
176
|
system_prompt = self.prompts_dir / "orchestrator.md"
|
|
108
|
-
raw_output = self.run_claude_process(
|
|
109
|
-
|
|
177
|
+
raw_output = self.run_claude_process(
|
|
178
|
+
orchestrator_prompt, system_prompt_file=system_prompt
|
|
179
|
+
)
|
|
180
|
+
|
|
110
181
|
# Parse JSON
|
|
111
182
|
try:
|
|
112
183
|
# Handle potential markdown fence blocks
|
|
@@ -118,7 +189,9 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
118
189
|
manifest_data = json.loads(clean_json.strip())
|
|
119
190
|
scopes = manifest_data.get("scopes", [])
|
|
120
191
|
except Exception as e:
|
|
121
|
-
print(
|
|
192
|
+
print(
|
|
193
|
+
f"[WARN] Failed to parse JSON from orchestrator output: {e}. Using fallback decomposition."
|
|
194
|
+
)
|
|
122
195
|
scopes = [
|
|
123
196
|
{
|
|
124
197
|
"scope_id": "scope_01_primary_investigation",
|
|
@@ -126,7 +199,9 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
126
199
|
"objective": objective,
|
|
127
200
|
"dependencies": [],
|
|
128
201
|
"affirmative_targets": ["Find corroborating empirical data"],
|
|
129
|
-
"adversarial_targets": [
|
|
202
|
+
"adversarial_targets": [
|
|
203
|
+
"Probe counter-arguments and failure modes"
|
|
204
|
+
],
|
|
130
205
|
}
|
|
131
206
|
]
|
|
132
207
|
|
|
@@ -137,12 +212,16 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
137
212
|
def run_agent_alpha(self, scope: Dict[str, Any]):
|
|
138
213
|
"""Executes Agent Alpha (Thesis / Proponent / Structural Auditor) for a scope."""
|
|
139
214
|
scope_id = scope["scope_id"]
|
|
140
|
-
print(
|
|
215
|
+
print(
|
|
216
|
+
f" [Alpha] šļø Starting Agent Alpha ({self.mode.upper()} Thesis) on [{scope_id}]..."
|
|
217
|
+
)
|
|
141
218
|
|
|
142
219
|
if self.mock_mode:
|
|
143
220
|
if self.mode == "audit":
|
|
144
221
|
sample_content = "# System State Machine Architecture\nAtomic state transitions enforce ACID consistency via write-then-rename."
|
|
145
|
-
shash = self.hasher.store_source(
|
|
222
|
+
shash = self.hasher.store_source(
|
|
223
|
+
"file:///runner/state_machine.py", sample_content, "State Machine"
|
|
224
|
+
)
|
|
146
225
|
dossier = {
|
|
147
226
|
"agent": "Agent Alpha (Code Architect)",
|
|
148
227
|
"mode": "code_audit",
|
|
@@ -155,15 +234,17 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
155
234
|
"statement": "State machine transitions enforce atomic ACID guarantees across scratchpad files.",
|
|
156
235
|
"source_hash": shash,
|
|
157
236
|
"source_url": "file:///runner/state_machine.py#L45-L65",
|
|
158
|
-
"verbatim_quote": "Atomic state transitions enforce ACID consistency via write-then-rename."
|
|
237
|
+
"verbatim_quote": "Atomic state transitions enforce ACID consistency via write-then-rename.",
|
|
159
238
|
}
|
|
160
239
|
],
|
|
161
240
|
"inferred_implications": [],
|
|
162
|
-
"negative_knowledge": []
|
|
241
|
+
"negative_knowledge": [],
|
|
163
242
|
}
|
|
164
243
|
elif self.mode == "scout":
|
|
165
244
|
sample_content = "# High Performance Raft in Rust\nZero-dependency Raft implementation with 150k ops/sec throughput under Apache-2.0."
|
|
166
|
-
shash = self.hasher.store_source(
|
|
245
|
+
shash = self.hasher.store_source(
|
|
246
|
+
"https://github.com/example/rust-raft", sample_content, "Rust Raft"
|
|
247
|
+
)
|
|
167
248
|
dossier = {
|
|
168
249
|
"agent": "Agent Alpha (OSS Scout)",
|
|
169
250
|
"mode": "oss_scout",
|
|
@@ -176,15 +257,51 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
176
257
|
"statement": "Rust-Raft achieves 150k ops/sec with zero external dependencies.",
|
|
177
258
|
"source_hash": shash,
|
|
178
259
|
"source_url": "https://github.com/example/rust-raft",
|
|
179
|
-
"verbatim_quote": "Zero-dependency Raft implementation with 150k ops/sec throughput under Apache-2.0."
|
|
260
|
+
"verbatim_quote": "Zero-dependency Raft implementation with 150k ops/sec throughput under Apache-2.0.",
|
|
180
261
|
}
|
|
181
262
|
],
|
|
182
263
|
"inferred_implications": [],
|
|
183
|
-
"negative_knowledge": []
|
|
264
|
+
"negative_knowledge": [],
|
|
265
|
+
}
|
|
266
|
+
elif self.mode == "brainstorm":
|
|
267
|
+
sample_content = "# Workspace Domain Snapshot\nEntities: swarm runner, dialectic dossiers, content-addressed cache. Constraint: evidence primacy."
|
|
268
|
+
shash = self.hasher.store_source(
|
|
269
|
+
"file:///.research/domain_model.json",
|
|
270
|
+
sample_content,
|
|
271
|
+
"Domain Snapshot",
|
|
272
|
+
)
|
|
273
|
+
dossier = {
|
|
274
|
+
"agent": "Agent Alpha (Wild Proponent)",
|
|
275
|
+
"mode": "brainstorm",
|
|
276
|
+
"scope_id": scope_id,
|
|
277
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
278
|
+
"affirmative_claims": [
|
|
279
|
+
{
|
|
280
|
+
"claim_id": "ALPHA-B01",
|
|
281
|
+
"tag": "VERIFIED",
|
|
282
|
+
"statement": "Workspace entities center on swarm runner, dialectic dossiers, and content-addressed cache.",
|
|
283
|
+
"source_hash": shash,
|
|
284
|
+
"source_url": "file:///.research/domain_model.json",
|
|
285
|
+
"verbatim_quote": "Entities: swarm runner, dialectic dossiers, content-addressed cache.",
|
|
286
|
+
}
|
|
287
|
+
],
|
|
288
|
+
"inferred_implications": [
|
|
289
|
+
{
|
|
290
|
+
"inference_id": "ALPHA-BI01",
|
|
291
|
+
"tag": "HYPOTHESIS",
|
|
292
|
+
"statement": "What-if: divergence-rewarded synthesis produces higher-upside feature vectors than evidence-gated synthesis.",
|
|
293
|
+
"parent_claims": ["ALPHA-B01"],
|
|
294
|
+
"deductive_logic": "Falsified if blind A/B of brainstorm vs research briefs shows no novelty gain per reviewer vote.",
|
|
295
|
+
"falsification": "Blind reviewer novelty vote shows no gain within 2 review rounds.",
|
|
296
|
+
}
|
|
297
|
+
],
|
|
298
|
+
"negative_knowledge": [],
|
|
184
299
|
}
|
|
185
300
|
else:
|
|
186
301
|
sample_content = "# FPGA Prover Benchmark\nOur FPGA pipeline executes the Poseidon round constraints in 184ms with a peak memory bandwidth of 45 GB/s."
|
|
187
|
-
shash = self.hasher.store_source(
|
|
302
|
+
shash = self.hasher.store_source(
|
|
303
|
+
"https://arxiv.org/abs/2405.0001", sample_content, "FPGA Benchmark"
|
|
304
|
+
)
|
|
188
305
|
dossier = {
|
|
189
306
|
"agent": "Agent Alpha (Thesis)",
|
|
190
307
|
"scope_id": scope_id,
|
|
@@ -196,7 +313,7 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
196
313
|
"statement": "FPGA-accelerated Poseidon provers achieve sub-200ms latency on 2^20 constraints.",
|
|
197
314
|
"source_hash": shash,
|
|
198
315
|
"source_url": "https://arxiv.org/abs/2405.0001",
|
|
199
|
-
"verbatim_quote": "Our FPGA pipeline executes the Poseidon round constraints in 184ms with a peak memory bandwidth of 45 GB/s."
|
|
316
|
+
"verbatim_quote": "Our FPGA pipeline executes the Poseidon round constraints in 184ms with a peak memory bandwidth of 45 GB/s.",
|
|
200
317
|
}
|
|
201
318
|
],
|
|
202
319
|
"inferred_implications": [
|
|
@@ -205,10 +322,10 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
205
322
|
"tag": "INFERRED",
|
|
206
323
|
"statement": "Hardware provers satisfy 1-second block finality bounds.",
|
|
207
324
|
"parent_claims": ["ALPHA-C01"],
|
|
208
|
-
"deductive_logic": "184ms << 1000ms target."
|
|
325
|
+
"deductive_logic": "184ms << 1000ms target.",
|
|
209
326
|
}
|
|
210
327
|
],
|
|
211
|
-
"negative_knowledge": []
|
|
328
|
+
"negative_knowledge": [],
|
|
212
329
|
}
|
|
213
330
|
else:
|
|
214
331
|
prompt = f"Run Agent Alpha ({self.mode} mode) for scope: {json.dumps(scope)}. Engine: {self.engine}. Depth: {self.depth}. Save findings to {scope_id} scratchpad."
|
|
@@ -216,10 +333,14 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
216
333
|
system_prompt = self.prompts_dir / "agent_code_auditor.md"
|
|
217
334
|
elif self.mode == "scout":
|
|
218
335
|
system_prompt = self.prompts_dir / "agent_oss_scout.md"
|
|
336
|
+
elif self.mode == "brainstorm":
|
|
337
|
+
system_prompt = self.prompts_dir / "agent_brainstormer.md"
|
|
219
338
|
else:
|
|
220
339
|
system_prompt = self.prompts_dir / "agent_alpha_thesis.md"
|
|
221
|
-
self.run_claude_process(prompt, system_prompt_file=system_prompt)
|
|
222
|
-
dossier_path =
|
|
340
|
+
self.run_claude_process(prompt, system_prompt_file=system_prompt, role="alpha")
|
|
341
|
+
dossier_path = (
|
|
342
|
+
self.state_machine.get_scope_dir(scope_id) / "alpha_dossier.json"
|
|
343
|
+
)
|
|
223
344
|
with open(dossier_path, "r", encoding="utf-8") as f:
|
|
224
345
|
dossier = json.load(f)
|
|
225
346
|
|
|
@@ -229,12 +350,18 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
229
350
|
def run_agent_beta(self, scope: Dict[str, Any]):
|
|
230
351
|
"""Executes Agent Beta (Antithesis / Red Team) for a scope."""
|
|
231
352
|
scope_id = scope["scope_id"]
|
|
232
|
-
print(
|
|
353
|
+
print(
|
|
354
|
+
f" [Beta] šÆ Starting Agent Beta ({self.mode.upper()} Red Team) on [{scope_id}]..."
|
|
355
|
+
)
|
|
233
356
|
|
|
234
357
|
if self.mock_mode:
|
|
235
358
|
if self.mode == "audit":
|
|
236
359
|
sample_content = "# Concurrency Analysis\nSubprocess writes may conflict if file descriptors are left open across parallel threads."
|
|
237
|
-
shash = self.hasher.store_source(
|
|
360
|
+
shash = self.hasher.store_source(
|
|
361
|
+
"file:///runner/state_machine.py#race",
|
|
362
|
+
sample_content,
|
|
363
|
+
"Concurrency Check",
|
|
364
|
+
)
|
|
238
365
|
dossier = {
|
|
239
366
|
"agent": "Agent Beta (Code Red Team)",
|
|
240
367
|
"mode": "code_audit",
|
|
@@ -248,21 +375,23 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
248
375
|
"source_hash": shash,
|
|
249
376
|
"source_url": "file:///runner/state_machine.py#race",
|
|
250
377
|
"verbatim_quote": "Subprocess writes may conflict if file descriptors are left open across parallel threads.",
|
|
251
|
-
"severity": "MEDIUM"
|
|
378
|
+
"severity": "MEDIUM",
|
|
252
379
|
}
|
|
253
380
|
],
|
|
254
381
|
"methodological_critiques": [
|
|
255
382
|
{
|
|
256
383
|
"target_assertion": "State machine transitions enforce atomic ACID guarantees across scratchpad files.",
|
|
257
384
|
"critique": "Unprotected open(..., 'w') creates race condition window between concurrent agents.",
|
|
258
|
-
"evidence_hash": shash
|
|
385
|
+
"evidence_hash": shash,
|
|
259
386
|
}
|
|
260
387
|
],
|
|
261
|
-
"negative_knowledge": []
|
|
388
|
+
"negative_knowledge": [],
|
|
262
389
|
}
|
|
263
390
|
elif self.mode == "scout":
|
|
264
391
|
sample_content = "# High Performance Raft in Rust\nZero-dependency Raft implementation with 150k ops/sec throughput under Apache-2.0."
|
|
265
|
-
shash = self.hasher.store_source(
|
|
392
|
+
shash = self.hasher.store_source(
|
|
393
|
+
"https://github.com/example/rust-raft", sample_content, "Rust Raft"
|
|
394
|
+
)
|
|
266
395
|
dossier = {
|
|
267
396
|
"agent": "Agent Beta (OSS Red Team)",
|
|
268
397
|
"mode": "oss_scout",
|
|
@@ -276,21 +405,57 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
276
405
|
"source_hash": shash,
|
|
277
406
|
"source_url": "https://github.com/example/rust-raft",
|
|
278
407
|
"verbatim_quote": "Zero-dependency Raft implementation with 150k ops/sec throughput under Apache-2.0.",
|
|
279
|
-
"severity": "LOW"
|
|
408
|
+
"severity": "LOW",
|
|
280
409
|
}
|
|
281
410
|
],
|
|
282
411
|
"methodological_critiques": [
|
|
283
412
|
{
|
|
284
413
|
"target_assertion": "Rust-Raft achieves 150k ops/sec with zero external dependencies.",
|
|
285
414
|
"critique": "Throughput degrades during log compaction due to unbuffered disk sync.",
|
|
286
|
-
"evidence_hash": shash
|
|
415
|
+
"evidence_hash": shash,
|
|
287
416
|
}
|
|
288
417
|
],
|
|
289
|
-
"negative_knowledge": []
|
|
418
|
+
"negative_knowledge": [],
|
|
419
|
+
}
|
|
420
|
+
elif self.mode == "brainstorm":
|
|
421
|
+
sample_content = "# Inversion Probe\nWhat if the evidence gate is the bottleneck? Divergence-rewarded synthesis explores what-if mechanics first."
|
|
422
|
+
shash = self.hasher.store_source(
|
|
423
|
+
"file:///.research/domain_model.json#inversion",
|
|
424
|
+
sample_content,
|
|
425
|
+
"Inversion Probe",
|
|
426
|
+
)
|
|
427
|
+
dossier = {
|
|
428
|
+
"agent": "Agent Beta (Radical Inverter)",
|
|
429
|
+
"mode": "brainstorm",
|
|
430
|
+
"scope_id": scope_id,
|
|
431
|
+
"timestamp": datetime.now(timezone.utc).isoformat(),
|
|
432
|
+
"falsification_claims": [
|
|
433
|
+
{
|
|
434
|
+
"claim_id": "BETA-B01",
|
|
435
|
+
"tag": "VERIFIED",
|
|
436
|
+
"statement": "Inversion probe: evidence gating may bottleneck lateral ideation throughput.",
|
|
437
|
+
"source_hash": shash,
|
|
438
|
+
"source_url": "file:///.research/domain_model.json#inversion",
|
|
439
|
+
"verbatim_quote": "What if the evidence gate is the bottleneck?",
|
|
440
|
+
"severity": "INFO",
|
|
441
|
+
}
|
|
442
|
+
],
|
|
443
|
+
"methodological_critiques": [
|
|
444
|
+
{
|
|
445
|
+
"target_assertion": "Divergence-rewarded synthesis produces higher-upside feature vectors.",
|
|
446
|
+
"critique": "Novelty without falsification probes is indistinguishable from hallucination; require spike tests.",
|
|
447
|
+
"evidence_hash": shash,
|
|
448
|
+
}
|
|
449
|
+
],
|
|
450
|
+
"negative_knowledge": [],
|
|
290
451
|
}
|
|
291
452
|
else:
|
|
292
453
|
sample_content = "# PCIe Bus Saturation Study\nIn continuous batch streaming, PCIe 4.0 transfers introduce a 650ms delay, yielding total latency > 800ms."
|
|
293
|
-
shash = self.hasher.store_source(
|
|
454
|
+
shash = self.hasher.store_source(
|
|
455
|
+
"https://arxiv.org/abs/2406.9999",
|
|
456
|
+
sample_content,
|
|
457
|
+
"PCIe Bottlenecks",
|
|
458
|
+
)
|
|
294
459
|
|
|
295
460
|
dossier = {
|
|
296
461
|
"agent": "Agent Beta (Red Team)",
|
|
@@ -303,22 +468,22 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
303
468
|
"statement": "Batch streaming incurs a 650ms PCIe transfer delay under production loads.",
|
|
304
469
|
"source_hash": shash,
|
|
305
470
|
"source_url": "https://arxiv.org/abs/2406.9999",
|
|
306
|
-
"verbatim_quote": "In continuous batch streaming, PCIe 4.0 transfers introduce a 650ms delay, yielding total latency > 800ms."
|
|
471
|
+
"verbatim_quote": "In continuous batch streaming, PCIe 4.0 transfers introduce a 650ms delay, yielding total latency > 800ms.",
|
|
307
472
|
}
|
|
308
473
|
],
|
|
309
474
|
"methodological_critiques": [
|
|
310
475
|
{
|
|
311
476
|
"target_assertion": "FPGA-accelerated Poseidon provers achieve sub-200ms latency on 2^20 constraints.",
|
|
312
477
|
"critique": "Benchmark isolates compute kernel and ignores host-to-device PCIe latency in pipelined batches.",
|
|
313
|
-
"evidence_hash": shash
|
|
478
|
+
"evidence_hash": shash,
|
|
314
479
|
}
|
|
315
480
|
],
|
|
316
481
|
"negative_knowledge": [
|
|
317
482
|
{
|
|
318
483
|
"query": "Zero-latency PCIe streaming ZK provers",
|
|
319
|
-
"finding": "No architecture eliminates bus transfer overhead without on-chip memory > 128GB."
|
|
484
|
+
"finding": "No architecture eliminates bus transfer overhead without on-chip memory > 128GB.",
|
|
320
485
|
}
|
|
321
|
-
]
|
|
486
|
+
],
|
|
322
487
|
}
|
|
323
488
|
else:
|
|
324
489
|
prompt = f"Run Agent Beta ({self.mode} mode) for scope: {json.dumps(scope)}. Engine: {self.engine}. Depth: {self.depth}. Save findings to {scope_id} scratchpad."
|
|
@@ -326,42 +491,62 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
326
491
|
system_prompt = self.prompts_dir / "agent_code_auditor.md"
|
|
327
492
|
elif self.mode == "scout":
|
|
328
493
|
system_prompt = self.prompts_dir / "agent_oss_scout.md"
|
|
494
|
+
elif self.mode == "brainstorm":
|
|
495
|
+
system_prompt = self.prompts_dir / "agent_brainstormer.md"
|
|
329
496
|
else:
|
|
330
497
|
system_prompt = self.prompts_dir / "agent_beta_antithesis.md"
|
|
331
|
-
self.run_claude_process(prompt, system_prompt_file=system_prompt)
|
|
332
|
-
dossier_path =
|
|
498
|
+
self.run_claude_process(prompt, system_prompt_file=system_prompt, role="beta")
|
|
499
|
+
dossier_path = (
|
|
500
|
+
self.state_machine.get_scope_dir(scope_id) / "beta_dossier.json"
|
|
501
|
+
)
|
|
333
502
|
with open(dossier_path, "r", encoding="utf-8") as f:
|
|
334
503
|
dossier = json.load(f)
|
|
335
504
|
|
|
336
505
|
self.state_machine.record_agent_completion(scope_id, "beta", dossier)
|
|
337
506
|
print(f" [Beta] ā
Completed Agent Beta for [{scope_id}].")
|
|
338
507
|
|
|
339
|
-
def execute_scope_dialectic(self, scope: Dict[str, Any]):
|
|
340
|
-
"""Dispatches Agent Alpha and Agent Beta concurrently."""
|
|
508
|
+
def execute_scope_dialectic(self, scope: Dict[str, Any]) -> Dict[str, Any]:
|
|
509
|
+
"""Dispatches Agent Alpha and Agent Beta concurrently. Returns the audit report."""
|
|
341
510
|
scope_id = scope["scope_id"]
|
|
342
|
-
print(
|
|
511
|
+
print(
|
|
512
|
+
f"\nā” [Swarm Dispatch] Launching Dialectic Pair for [{scope_id}]: '{scope.get('title')}'"
|
|
513
|
+
)
|
|
343
514
|
self.state_machine.update_scope_status(scope_id, ScopeStatus.RUNNING_PARALLEL)
|
|
344
|
-
|
|
515
|
+
|
|
345
516
|
with ThreadPoolExecutor(max_workers=2) as executor:
|
|
346
517
|
future_alpha = executor.submit(self.run_agent_alpha, scope)
|
|
347
518
|
future_beta = executor.submit(self.run_agent_beta, scope)
|
|
348
|
-
|
|
519
|
+
|
|
349
520
|
# Wait for both
|
|
350
521
|
future_alpha.result()
|
|
351
522
|
future_beta.result()
|
|
352
523
|
|
|
353
524
|
# Phase 4: Run Epistemic Auditor
|
|
354
|
-
print(
|
|
355
|
-
|
|
525
|
+
print(
|
|
526
|
+
f"āļø [Auditor] Auditing evidence & computing divergence for [{scope_id}]..."
|
|
527
|
+
)
|
|
528
|
+
constitution = None
|
|
529
|
+
if self.domain_pack:
|
|
530
|
+
from runner.refinement import load_domain_pack
|
|
531
|
+
|
|
532
|
+
constitution = load_domain_pack(self.domain_pack)
|
|
533
|
+
audit_report = self.auditor.audit_scope(scope_id, constitution=constitution)
|
|
356
534
|
summary = audit_report["summary"]
|
|
357
|
-
print(
|
|
535
|
+
print(
|
|
536
|
+
f" [Audit Result] Score: {summary['epistemic_score']}/1.0 | Divergence: {summary['divergence_score']} | Verified: {summary['verified_passed']} | Rejected: {summary['unverified_rejected']}"
|
|
537
|
+
)
|
|
538
|
+
return audit_report
|
|
358
539
|
|
|
359
540
|
def run_swarm(self, objective: str, frontier_file: Optional[Path] = None):
|
|
360
541
|
"""Full end-to-end execution loop."""
|
|
361
542
|
start_time = datetime.now(timezone.utc)
|
|
362
543
|
print("=" * 70)
|
|
363
|
-
print(
|
|
364
|
-
|
|
544
|
+
print(
|
|
545
|
+
f"š EPISTEMIC SWARM: HIGH-INTEGRITY RESEARCH HARNESS [{self.mode.upper()} MODE]"
|
|
546
|
+
)
|
|
547
|
+
print(
|
|
548
|
+
f" Engine: {self.engine.upper()} | Depth: {self.depth} | Dir: {self.base_dir}"
|
|
549
|
+
)
|
|
365
550
|
print("=" * 70)
|
|
366
551
|
|
|
367
552
|
# 1. Orchestrate
|
|
@@ -374,24 +559,61 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
374
559
|
# Check if all scopes are complete
|
|
375
560
|
manifest = self.state_machine.load_global_manifest()
|
|
376
561
|
all_complete = all(
|
|
377
|
-
self.state_machine.load_scope_manifest(s["scope_id"]).get("status")
|
|
562
|
+
self.state_machine.load_scope_manifest(s["scope_id"]).get("status")
|
|
563
|
+
== ScopeStatus.COMPLETE.value
|
|
378
564
|
for s in manifest["scopes"]
|
|
379
565
|
)
|
|
380
566
|
if all_complete:
|
|
381
567
|
break
|
|
382
568
|
else:
|
|
383
|
-
print(
|
|
569
|
+
print(
|
|
570
|
+
"[ERROR] Deadlock in scope dependency graph.", file=sys.stderr
|
|
571
|
+
)
|
|
384
572
|
self.state_machine.update_session_status(SessionStatus.FAILED)
|
|
385
573
|
return
|
|
386
574
|
|
|
387
|
-
|
|
388
|
-
|
|
575
|
+
# Stream F: "auction" reorders each ready batch by expected
|
|
576
|
+
# information gain; "dag" keeps legacy dependency order (all ready
|
|
577
|
+
# scopes dispatched in the batch, unchanged).
|
|
578
|
+
if self.allocation == "auction":
|
|
579
|
+
from runner.auctioneer import (
|
|
580
|
+
estimate_tokens,
|
|
581
|
+
record_scope_telemetry,
|
|
582
|
+
score_scopes,
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
scored = score_scopes(ready_scopes, base_dir=self.base_dir)
|
|
586
|
+
ordered = [s for _b, s in scored]
|
|
587
|
+
bids = {s.get("scope_id"): b for b, s in scored}
|
|
588
|
+
for ordered_scope in ordered:
|
|
589
|
+
audit_report = self.execute_scope_dialectic(ordered_scope)
|
|
590
|
+
summary = (audit_report or {}).get("summary", {})
|
|
591
|
+
sid = ordered_scope.get("scope_id", "")
|
|
592
|
+
# tokens_used is a chars/4 ESTIMATE ā flagged approximation.
|
|
593
|
+
dossier_chars = 0
|
|
594
|
+
scope_dir = self.state_machine.get_scope_dir(sid)
|
|
595
|
+
for name in ("alpha_dossier.json", "beta_dossier.json"):
|
|
596
|
+
p = scope_dir / name
|
|
597
|
+
if p.exists():
|
|
598
|
+
dossier_chars += p.stat().st_size
|
|
599
|
+
record_scope_telemetry(
|
|
600
|
+
self.base_dir,
|
|
601
|
+
sid,
|
|
602
|
+
tokens_used=estimate_tokens("x" * dossier_chars),
|
|
603
|
+
verified_claims=summary.get("verified_passed", 0),
|
|
604
|
+
bid=bids.get(sid),
|
|
605
|
+
)
|
|
606
|
+
else:
|
|
607
|
+
for scope in ready_scopes:
|
|
608
|
+
self.execute_scope_dialectic(scope)
|
|
389
609
|
|
|
390
610
|
# 3. Master Synthesis Compilation
|
|
391
|
-
print(
|
|
611
|
+
print(
|
|
612
|
+
f"\nš [Phase 5: Master Synthesis] Aggregating {self.mode.upper()} dossiers..."
|
|
613
|
+
)
|
|
392
614
|
report_path = self._compile_master_synthesis(objective)
|
|
393
615
|
self.state_machine.update_session_status(SessionStatus.COMPLETED)
|
|
394
|
-
|
|
616
|
+
|
|
395
617
|
duration = (datetime.now(timezone.utc) - start_time).total_seconds()
|
|
396
618
|
print(f"\nš Swarm run completed in {duration:.1f}s. Report: {report_path}")
|
|
397
619
|
|
|
@@ -401,7 +623,8 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
401
623
|
"audit": "Codebase Architectural & Security Audit",
|
|
402
624
|
"scout": "Open-Source Software Discovery & Clean-Room Blueprint",
|
|
403
625
|
"hybrid": "Hybrid Codebase & Literature Epistemic Report",
|
|
404
|
-
"
|
|
626
|
+
"brainstorm": "Lateral Brainstorm & Speculative Ideation Portfolio",
|
|
627
|
+
"research": "Master Epistemic Research Report",
|
|
405
628
|
}
|
|
406
629
|
title = mode_titles.get(self.mode, "Master Epistemic Research Report")
|
|
407
630
|
|
|
@@ -410,7 +633,7 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
410
633
|
f"**Session ID**: `{manifest['session_id']}` | **Mode**: `{self.mode.upper()}` | **Engine**: `{self.engine}` | **Generated**: `{manifest['updated_at']}`\n",
|
|
411
634
|
"## Executive Summary",
|
|
412
635
|
f"This brief was compiled using the Epistemic Swarm dialectic harness ({self.mode} mode). Every factual statement carries an empirical verification pointer backed by a content-addressed raw document cache.\n",
|
|
413
|
-
"## Scope Findings & Dialectic Balance Sheets\n"
|
|
636
|
+
"## Scope Findings & Dialectic Balance Sheets\n",
|
|
414
637
|
]
|
|
415
638
|
|
|
416
639
|
total_verified = 0
|
|
@@ -437,8 +660,12 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
437
660
|
|
|
438
661
|
avg_div = round(sum(all_divergences) / max(1, len(all_divergences)), 2)
|
|
439
662
|
synthesis_lines.append(f"\n## Swarm Epistemic Audit Totals\n")
|
|
440
|
-
synthesis_lines.append(
|
|
441
|
-
|
|
663
|
+
synthesis_lines.append(
|
|
664
|
+
f"- **Total Verified Primary Citations**: `{total_verified}`"
|
|
665
|
+
)
|
|
666
|
+
synthesis_lines.append(
|
|
667
|
+
f"- **Total Unverified Claims Purged**: `{total_rejected}`"
|
|
668
|
+
)
|
|
442
669
|
synthesis_lines.append(f"- **Mean Swarm Divergence Score**: `{avg_div}`")
|
|
443
670
|
|
|
444
671
|
final_path = self.base_dir / "final_synthesis.md"
|
|
@@ -456,28 +683,85 @@ Output ONLY valid JSON representing the scope decomposition conforming to prompt
|
|
|
456
683
|
with open(scout_path, "w", encoding="utf-8") as f:
|
|
457
684
|
f.write("\n".join(synthesis_lines))
|
|
458
685
|
return scout_path
|
|
686
|
+
elif self.mode == "brainstorm":
|
|
687
|
+
brainstorm_path = self.base_dir / "brainstorm_report.md"
|
|
688
|
+
with open(brainstorm_path, "w", encoding="utf-8") as f:
|
|
689
|
+
f.write("\n".join(synthesis_lines))
|
|
690
|
+
return brainstorm_path
|
|
459
691
|
|
|
460
692
|
return final_path
|
|
461
693
|
|
|
462
694
|
|
|
463
695
|
def main():
|
|
464
|
-
parser = argparse.ArgumentParser(
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
parser.add_argument(
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
parser.add_argument(
|
|
471
|
-
|
|
696
|
+
parser = argparse.ArgumentParser(
|
|
697
|
+
description="Epistemic Swarm Dialectic Research Runner"
|
|
698
|
+
)
|
|
699
|
+
parser.add_argument(
|
|
700
|
+
"--objective", type=str, required=True, help="Research question or objective"
|
|
701
|
+
)
|
|
702
|
+
parser.add_argument(
|
|
703
|
+
"--frontier", type=str, help="Path to settled frontier.json from /grilling"
|
|
704
|
+
)
|
|
705
|
+
parser.add_argument(
|
|
706
|
+
"--mock-claude",
|
|
707
|
+
action="store_true",
|
|
708
|
+
help="Run with synthetic test data without invoking Claude Code",
|
|
709
|
+
)
|
|
710
|
+
parser.add_argument(
|
|
711
|
+
"--dir", default=".research", help="Path to .research workspace"
|
|
712
|
+
)
|
|
713
|
+
parser.add_argument(
|
|
714
|
+
"--mode",
|
|
715
|
+
choices=["research", "audit", "scout", "hybrid", "brainstorm"],
|
|
716
|
+
default=None,
|
|
717
|
+
help="Operating mode",
|
|
718
|
+
)
|
|
719
|
+
parser.add_argument(
|
|
720
|
+
"--engine",
|
|
721
|
+
choices=["duckduckgo", "brave", "firecrawl", "searxng"],
|
|
722
|
+
default=None,
|
|
723
|
+
help="Search engine",
|
|
724
|
+
)
|
|
725
|
+
parser.add_argument(
|
|
726
|
+
"--depth",
|
|
727
|
+
"--iterations",
|
|
728
|
+
type=int,
|
|
729
|
+
default=None,
|
|
730
|
+
help="Max dialectic depth / iterations",
|
|
731
|
+
)
|
|
732
|
+
|
|
733
|
+
# Stream E: per-agent backend/model overrides (CLI > env > config).
|
|
734
|
+
parser.add_argument("--model-alpha", type=str, default=None,
|
|
735
|
+
help="Model id for Agent Alpha (thesis)")
|
|
736
|
+
parser.add_argument("--model-beta", type=str, default=None,
|
|
737
|
+
help="Model id for Agent Beta (antithesis)")
|
|
738
|
+
parser.add_argument("--beta-backend", type=str, nargs="+", default=None,
|
|
739
|
+
help="Backend command list for Beta, e.g. --beta-backend ollama run qwen3")
|
|
740
|
+
parser.add_argument("--allocation", choices=["dag", "auction"], default=None,
|
|
741
|
+
help="Scope allocation policy (default: config/dag; auction = Frontier Markets)")
|
|
742
|
+
parser.add_argument("--domain-pack", type=str, default=None,
|
|
743
|
+
help="Regulated Domain Pack id (config/domain_packs/<id>.json), e.g. biopharma")
|
|
472
744
|
|
|
473
745
|
args = parser.parse_args()
|
|
474
746
|
frontier_path = Path(args.frontier) if args.frontier else None
|
|
747
|
+
|
|
748
|
+
agent_overrides: Dict[str, Dict[str, Any]] = {}
|
|
749
|
+
if args.model_alpha:
|
|
750
|
+
agent_overrides.setdefault("alpha", {})["model"] = args.model_alpha
|
|
751
|
+
if args.model_beta:
|
|
752
|
+
agent_overrides.setdefault("beta", {})["model"] = args.model_beta
|
|
753
|
+
if args.beta_backend:
|
|
754
|
+
agent_overrides.setdefault("beta", {})["backend"] = args.beta_backend
|
|
755
|
+
|
|
475
756
|
runner = SwarmRunner(
|
|
476
757
|
base_dir=Path(args.dir),
|
|
477
758
|
mock_mode=args.mock_claude,
|
|
478
759
|
mode=args.mode,
|
|
479
760
|
engine=args.engine,
|
|
480
|
-
depth=args.depth
|
|
761
|
+
depth=args.depth,
|
|
762
|
+
agent_overrides=agent_overrides or None,
|
|
763
|
+
allocation=args.allocation,
|
|
764
|
+
domain_pack=args.domain_pack,
|
|
481
765
|
)
|
|
482
766
|
runner.run_swarm(args.objective, frontier_file=frontier_path)
|
|
483
767
|
|