algo-cli-runtime 0.14.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. algo_cli/__init__.py +3 -0
  2. algo_cli/__main__.py +7 -0
  3. algo_cli/_internal/__init__.py +12 -0
  4. algo_cli/_internal/policy_chain.py +259 -0
  5. algo_cli/action_registry.py +1047 -0
  6. algo_cli/agent_blocks.py +550 -0
  7. algo_cli/agent_pipeline.py +1457 -0
  8. algo_cli/agent_threads.py +308 -0
  9. algo_cli/animations.py +316 -0
  10. algo_cli/cache_admission.py +209 -0
  11. algo_cli/capability_mask.py +66 -0
  12. algo_cli/chat_protocol.py +116 -0
  13. algo_cli/chatgpt_auth.py +510 -0
  14. algo_cli/chatgpt_client.py +657 -0
  15. algo_cli/code_rag.py +479 -0
  16. algo_cli/config.py +651 -0
  17. algo_cli/context_budget.py +679 -0
  18. algo_cli/credential_helpers.py +315 -0
  19. algo_cli/deliberation.py +29 -0
  20. algo_cli/display.py +1470 -0
  21. algo_cli/evals/__init__.py +21 -0
  22. algo_cli/evals/algorithm_effectiveness.py +560 -0
  23. algo_cli/evals/competitive_harness_rating.py +702 -0
  24. algo_cli/evals/cot_quality.py +220 -0
  25. algo_cli/evals/harness_retrieval_benchmark.py +401 -0
  26. algo_cli/evals/performance_regression.py +136 -0
  27. algo_cli/evals/scorecard_grading.py +308 -0
  28. algo_cli/evals/session_distribution.py +84 -0
  29. algo_cli/execution_guardrails.py +806 -0
  30. algo_cli/extensions_manifest.py +84 -0
  31. algo_cli/git_evidence.py +227 -0
  32. algo_cli/google_workspace.py +407 -0
  33. algo_cli/google_workspace_auth.py +523 -0
  34. algo_cli/harness.py +2587 -0
  35. algo_cli/identity.py +557 -0
  36. algo_cli/index_compute_lab.py +228 -0
  37. algo_cli/inference_harness.py +70 -0
  38. algo_cli/intelligence/__init__.py +1103 -0
  39. algo_cli/intelligence/acrobat_config.py +307 -0
  40. algo_cli/intelligence/acrobat_manifests.py +338 -0
  41. algo_cli/intelligence/acrobat_models.py +195 -0
  42. algo_cli/intelligence/acrobat_pipeline.py +295 -0
  43. algo_cli/intelligence/acrobat_runtime.py +302 -0
  44. algo_cli/intelligence/acrobat_security.py +261 -0
  45. algo_cli/intelligence/acrobat_workflows.py +226 -0
  46. algo_cli/intelligence/actionability.py +165 -0
  47. algo_cli/intelligence/adversarial_audit.py +136 -0
  48. algo_cli/intelligence/agent_arena.py +92 -0
  49. algo_cli/intelligence/agent_benchmark.py +236 -0
  50. algo_cli/intelligence/agent_runtime.py +171 -0
  51. algo_cli/intelligence/agents_as_tools.py +70 -0
  52. algo_cli/intelligence/artifact_binding.py +80 -0
  53. algo_cli/intelligence/autonomous_engineer.py +1976 -0
  54. algo_cli/intelligence/backpressure.py +99 -0
  55. algo_cli/intelligence/bloom_filter.py +186 -0
  56. algo_cli/intelligence/bonferroni.py +66 -0
  57. algo_cli/intelligence/boundary_compaction.py +98 -0
  58. algo_cli/intelligence/catalog_verifier.py +172 -0
  59. algo_cli/intelligence/cavecrew.py +118 -0
  60. algo_cli/intelligence/changelog.py +176 -0
  61. algo_cli/intelligence/checkpoint_resume.py +92 -0
  62. algo_cli/intelligence/circuit_breaker.py +88 -0
  63. algo_cli/intelligence/clarification_gate.py +101 -0
  64. algo_cli/intelligence/code_graph.py +180 -0
  65. algo_cli/intelligence/coderank.py +97 -0
  66. algo_cli/intelligence/consistent_hash.py +150 -0
  67. algo_cli/intelligence/consortium_synthesis.py +139 -0
  68. algo_cli/intelligence/construction/__init__.py +241 -0
  69. algo_cli/intelligence/construction/common.py +273 -0
  70. algo_cli/intelligence/construction/documents.py +496 -0
  71. algo_cli/intelligence/construction/labor_units.py +1395 -0
  72. algo_cli/intelligence/construction/payments.py +470 -0
  73. algo_cli/intelligence/construction/risk.py +784 -0
  74. algo_cli/intelligence/content_extractor.py +132 -0
  75. algo_cli/intelligence/context_adaptive.py +102 -0
  76. algo_cli/intelligence/context_ops.py +95 -0
  77. algo_cli/intelligence/count_min.py +145 -0
  78. algo_cli/intelligence/cow_state.py +103 -0
  79. algo_cli/intelligence/critic_loop.py +119 -0
  80. algo_cli/intelligence/cross_source.py +113 -0
  81. algo_cli/intelligence/daemon_mode.py +99 -0
  82. algo_cli/intelligence/dag_orchestration.py +151 -0
  83. algo_cli/intelligence/deep_research.py +155 -0
  84. algo_cli/intelligence/degenerate_detector.py +78 -0
  85. algo_cli/intelligence/delta_report.py +92 -0
  86. algo_cli/intelligence/discovery_event_log.py +92 -0
  87. algo_cli/intelligence/document_ingest.py +298 -0
  88. algo_cli/intelligence/dual_layer_validate.py +151 -0
  89. algo_cli/intelligence/echo_fidelity.py +73 -0
  90. algo_cli/intelligence/ema_tuning.py +104 -0
  91. algo_cli/intelligence/event_log.py +92 -0
  92. algo_cli/intelligence/evidence_graph.py +114 -0
  93. algo_cli/intelligence/extension_host.py +162 -0
  94. algo_cli/intelligence/extension_manifest.py +115 -0
  95. algo_cli/intelligence/falsification_suite.py +178 -0
  96. algo_cli/intelligence/finance/__init__.py +169 -0
  97. algo_cli/intelligence/finance/anomalies.py +135 -0
  98. algo_cli/intelligence/finance/ap_ar.py +351 -0
  99. algo_cli/intelligence/finance/cash.py +162 -0
  100. algo_cli/intelligence/finance/close.py +332 -0
  101. algo_cli/intelligence/finance/common.py +244 -0
  102. algo_cli/intelligence/finance/construction.py +135 -0
  103. algo_cli/intelligence/finance/controls.py +172 -0
  104. algo_cli/intelligence/finance/evidence.py +119 -0
  105. algo_cli/intelligence/finance/exceptions.py +157 -0
  106. algo_cli/intelligence/finance/reconciliations.py +254 -0
  107. algo_cli/intelligence/finance/revenue.py +109 -0
  108. algo_cli/intelligence/finance/tax.py +74 -0
  109. algo_cli/intelligence/finance/workpapers.py +111 -0
  110. algo_cli/intelligence/finding_record.py +120 -0
  111. algo_cli/intelligence/flow_dag.py +267 -0
  112. algo_cli/intelligence/gatherer.py +223 -0
  113. algo_cli/intelligence/golden_master.py +98 -0
  114. algo_cli/intelligence/graph_rag.py +195 -0
  115. algo_cli/intelligence/group_chat.py +143 -0
  116. algo_cli/intelligence/hash_dedup.py +145 -0
  117. algo_cli/intelligence/hyperloglog.py +128 -0
  118. algo_cli/intelligence/incremental_index.py +316 -0
  119. algo_cli/intelligence/index_store.py +16 -0
  120. algo_cli/intelligence/iteration_plan.py +133 -0
  121. algo_cli/intelligence/kernel_plugins.py +167 -0
  122. algo_cli/intelligence/lesson_catalog.py +135 -0
  123. algo_cli/intelligence/llm_fallback.py +169 -0
  124. algo_cli/intelligence/log2_histogram.py +267 -0
  125. algo_cli/intelligence/lsp_integration.py +147 -0
  126. algo_cli/intelligence/memory_evolution.py +117 -0
  127. algo_cli/intelligence/minhash_lsh.py +182 -0
  128. algo_cli/intelligence/multi_model_score.py +174 -0
  129. algo_cli/intelligence/multi_tier_grade.py +211 -0
  130. algo_cli/intelligence/negative_controls.py +113 -0
  131. algo_cli/intelligence/numeric_clamp.py +63 -0
  132. algo_cli/intelligence/occ_editor.py +66 -0
  133. algo_cli/intelligence/output_normalize.py +112 -0
  134. algo_cli/intelligence/parallel_delegation.py +98 -0
  135. algo_cli/intelligence/parallel_fanout.py +104 -0
  136. algo_cli/intelligence/permission_modes.py +105 -0
  137. algo_cli/intelligence/pre_push_gate.py +68 -0
  138. algo_cli/intelligence/prefetch.py +171 -0
  139. algo_cli/intelligence/process_framework.py +217 -0
  140. algo_cli/intelligence/project_graph.py +387 -0
  141. algo_cli/intelligence/query_expansion.py +146 -0
  142. algo_cli/intelligence/ralph_loop.py +117 -0
  143. algo_cli/intelligence/rate_limiter.py +153 -0
  144. algo_cli/intelligence/refactor_transaction.py +94 -0
  145. algo_cli/intelligence/research_workspace.py +108 -0
  146. algo_cli/intelligence/retraction_ledger.py +72 -0
  147. algo_cli/intelligence/saga_pattern.py +88 -0
  148. algo_cli/intelligence/session_fork.py +100 -0
  149. algo_cli/intelligence/shadow_editor.py +67 -0
  150. algo_cli/intelligence/shell_session.py +213 -0
  151. algo_cli/intelligence/source_registry.py +143 -0
  152. algo_cli/intelligence/spawn_scales.py +99 -0
  153. algo_cli/intelligence/stat_stability.py +104 -0
  154. algo_cli/intelligence/structural_validator.py +148 -0
  155. algo_cli/intelligence/subagent_spawner.py +111 -0
  156. algo_cli/intelligence/symmetric_verify.py +70 -0
  157. algo_cli/intelligence/task_classifier.py +129 -0
  158. algo_cli/intelligence/team_execution.py +122 -0
  159. algo_cli/intelligence/tiered_access.py +121 -0
  160. algo_cli/intelligence/utility_registry.py +159 -0
  161. algo_cli/intuition_engine.py +560 -0
  162. algo_cli/intuition_injector.py +82 -0
  163. algo_cli/kernels/__init__.py +5 -0
  164. algo_cli/kernels/manifest.py +763 -0
  165. algo_cli/main.py +3903 -0
  166. algo_cli/memory_candidates.py +541 -0
  167. algo_cli/memory_echo_veil.py +394 -0
  168. algo_cli/memory_runtime.py +112 -0
  169. algo_cli/model_info.py +548 -0
  170. algo_cli/model_profile.py +160 -0
  171. algo_cli/model_routing.py +74 -0
  172. algo_cli/oneshot.py +331 -0
  173. algo_cli/perf_telemetry.py +389 -0
  174. algo_cli/plugins.py +245 -0
  175. algo_cli/private_event_store.py +654 -0
  176. algo_cli/quantization/__init__.py +24 -0
  177. algo_cli/quantization/lloyd_max.py +98 -0
  178. algo_cli/quantization/turbo_quant.py +308 -0
  179. algo_cli/reasoning/__init__.py +46 -0
  180. algo_cli/reasoning/combinatorial.py +356 -0
  181. algo_cli/reasoning/graph_of_thought.py +297 -0
  182. algo_cli/reasoning/mcts.py +220 -0
  183. algo_cli/reasoning/neuro_symbolic.py +250 -0
  184. algo_cli/reasoning/react.py +246 -0
  185. algo_cli/reasoning/reflexion.py +225 -0
  186. algo_cli/reasoning/tree_of_thought.py +241 -0
  187. algo_cli/reasoning_bridge.py +150 -0
  188. algo_cli/reconciliation.py +284 -0
  189. algo_cli/reflex.py +385 -0
  190. algo_cli/resources/docs/ALGO.md +13958 -0
  191. algo_cli/resources/docs/algo-cli-algorithm-evidence-contract.md +60 -0
  192. algo_cli/resources/docs/algo-cli-execution-verification-contract.md +59 -0
  193. algo_cli/resources/docs/algo-cli-memory-lifecycle-contract.md +72 -0
  194. algo_cli/resources/docs/harness-extension-cleanup-recommendation.md +41 -0
  195. algo_cli/resources/docs/index-compute-lab-integration.md +32 -0
  196. algo_cli/resources/docs/inference-harness-loop-blueprint-2026-06.md +55 -0
  197. algo_cli/resources/docs/main-split-map.md +35 -0
  198. algo_cli/resources/docs/privacy-and-context.md +48 -0
  199. algo_cli/resources/docs/reflex-loop-v0.2.md +354 -0
  200. algo_cli/resources/skills/README.md +26 -0
  201. algo_cli/resources/skills/algo-cli.md +59 -0
  202. algo_cli/resources/skills/edit-file-precision.md +49 -0
  203. algo_cli/resources/skills/harness-search-first.md +47 -0
  204. algo_cli/resources/skills/memory-recall-ritual.md +51 -0
  205. algo_cli/resources/skills/qol-algorithms.md +224 -0
  206. algo_cli/resources/skills/smart-error-recovery.md +56 -0
  207. algo_cli/resources/skills/tool-selection-cheatsheet.md +65 -0
  208. algo_cli/retrieval_algorithms.py +127 -0
  209. algo_cli/runtime_qos.py +236 -0
  210. algo_cli/runtime_services.py +320 -0
  211. algo_cli/session_commands.py +95 -0
  212. algo_cli/session_mode.py +113 -0
  213. algo_cli/skills.py +430 -0
  214. algo_cli/slash_dispatch.py +1265 -0
  215. algo_cli/small_context.py +206 -0
  216. algo_cli/spawn_budget.py +89 -0
  217. algo_cli/task_ledger.py +84 -0
  218. algo_cli/task_router.py +197 -0
  219. algo_cli/tool_context.py +94 -0
  220. algo_cli/tool_contract.py +99 -0
  221. algo_cli/tool_policy.py +357 -0
  222. algo_cli/tool_runtime.py +647 -0
  223. algo_cli/tools.py +3056 -0
  224. algo_cli/url_scheme.py +174 -0
  225. algo_cli/verify.py +154 -0
  226. algo_cli/version_manifest.py +178 -0
  227. algo_cli/vision_screenshot_verify.py +76 -0
  228. algo_cli/workspace_resolver.py +68 -0
  229. algo_cli/x_account.py +209 -0
  230. algo_cli/xai_auth.py +374 -0
  231. algo_cli/xai_client.py +600 -0
  232. algo_cli_runtime-0.14.0.dist-info/METADATA +369 -0
  233. algo_cli_runtime-0.14.0.dist-info/RECORD +237 -0
  234. algo_cli_runtime-0.14.0.dist-info/WHEEL +4 -0
  235. algo_cli_runtime-0.14.0.dist-info/entry_points.txt +3 -0
  236. algo_cli_runtime-0.14.0.dist-info/licenses/LICENSE +21 -0
  237. ollama_cli/__init__.py +67 -0
@@ -0,0 +1,148 @@
1
+ """B78. Incremental Structural Validation.
2
+
3
+ Validate code changes in <200ms using tree-sitter-style AST checks.
4
+ 3-tier resolution. Circuit breaker for false positives.
5
+ Source: Keel pattern.
6
+ """
7
+ from __future__ import annotations
8
+
9
+ import ast
10
+ from dataclasses import dataclass
11
+ from enum import Enum
12
+
13
+
14
+ class Severity(Enum):
15
+ ERROR = "ERROR"
16
+ WARNING = "WARNING"
17
+ INFO = "INFO"
18
+
19
+
20
+ @dataclass
21
+ class Violation:
22
+ code: str
23
+ severity: Severity
24
+ symbol: str
25
+ file: str
26
+ line: int
27
+ message: str
28
+ fix_hint: str = ""
29
+
30
+
31
+ class CircuitBreaker:
32
+ """Auto-downgrade repeated false positives to warnings."""
33
+
34
+ def __init__(self, max_failures: int = 3) -> None:
35
+ self._counts: dict[str, int] = {}
36
+ self._max = max_failures
37
+
38
+ def check(self, violation: Violation) -> Violation:
39
+ if violation.severity == Severity.ERROR:
40
+ key = f"{violation.code}:{violation.symbol}"
41
+ self._counts[key] = self._counts.get(key, 0) + 1
42
+ if self._counts[key] >= self._max:
43
+ violation.severity = Severity.WARNING
44
+ return violation
45
+
46
+ def reset(self) -> None:
47
+ self._counts.clear()
48
+
49
+
50
+ class StructuralValidator:
51
+ """Validate Python code structure using AST."""
52
+
53
+ ERROR_CODES = {
54
+ "E001": "Symbol referenced but not found",
55
+ "E002": "Missing type hints",
56
+ "E003": "Missing docstring",
57
+ "E004": "Function removed but still referenced",
58
+ "E005": "Arity mismatch",
59
+ "W001": "Symbol in wrong module",
60
+ "W002": "Duplicate name across modules",
61
+ }
62
+
63
+ def __init__(self) -> None:
64
+ self._breaker = CircuitBreaker()
65
+ self._defined_names: dict[str, str] = {} # name → file
66
+ self._referenced_names: set[str] = set()
67
+
68
+ def compile_file(self, filepath: str, content: str) -> list[Violation]:
69
+ """Validate a single file. Returns violations."""
70
+ violations: list[Violation] = []
71
+
72
+ try:
73
+ tree = ast.parse(content, filename=filepath)
74
+ except SyntaxError as e:
75
+ violations.append(Violation(
76
+ code="E001", severity=Severity.ERROR,
77
+ symbol="<syntax>", file=filepath, line=e.lineno or 0,
78
+ message=f"Syntax error: {e.msg}",
79
+ fix_hint="Fix the syntax error",
80
+ ))
81
+ return violations
82
+
83
+ # Collect defined names
84
+ for node in ast.walk(tree):
85
+ if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
86
+ self._defined_names[node.name] = filepath
87
+ # Check for type hints
88
+ if not node.returns and not any(a.annotation for a in node.args.args):
89
+ violations.append(Violation(
90
+ code="E002", severity=Severity.WARNING,
91
+ symbol=node.name, file=filepath, line=node.lineno,
92
+ message="Missing type hints",
93
+ fix_hint="Add type annotations",
94
+ ))
95
+ # Check for docstring
96
+ if not ast.get_docstring(node):
97
+ violations.append(Violation(
98
+ code="E003", severity=Severity.INFO,
99
+ symbol=node.name, file=filepath, line=node.lineno,
100
+ message="Missing docstring",
101
+ fix_hint="Add a docstring",
102
+ ))
103
+ elif isinstance(node, ast.ClassDef):
104
+ self._defined_names[node.name] = filepath
105
+
106
+ # Collect referenced names
107
+ for node in ast.walk(tree):
108
+ if isinstance(node, ast.Call):
109
+ if isinstance(node.func, ast.Name):
110
+ self._referenced_names.add(node.func.name)
111
+
112
+ # Check for broken callers
113
+ for ref in self._referenced_names:
114
+ if ref not in self._defined_names and not ref.startswith("_"):
115
+ # Only flag if it looks like a local reference
116
+ pass # Could be built-in or import
117
+
118
+ # Apply circuit breaker
119
+ violations = [self._breaker.check(v) for v in violations]
120
+ return violations
121
+
122
+ def check_broken_callers(self, removed_name: str) -> list[Violation]:
123
+ """Check if a removed function is still referenced."""
124
+ if removed_name in self._referenced_names:
125
+ return [Violation(
126
+ code="E004", severity=Severity.ERROR,
127
+ symbol=removed_name, file="<unknown>", line=0,
128
+ message=f"Function '{removed_name}' removed but still referenced",
129
+ fix_hint="Update callers or restore function",
130
+ )]
131
+ return []
132
+
133
+ def find_duplicates(self) -> list[Violation]:
134
+ """Find duplicate names across modules."""
135
+ name_to_files: dict[str, list[str]] = {}
136
+ for name, filepath in self._defined_names.items():
137
+ name_to_files.setdefault(name, []).append(filepath)
138
+
139
+ violations: list[Violation] = []
140
+ for name, files in name_to_files.items():
141
+ if len(set(files)) > 1:
142
+ violations.append(Violation(
143
+ code="W002", severity=Severity.WARNING,
144
+ symbol=name, file=files[0], line=0,
145
+ message=f"Duplicate name '{name}' in {len(set(files))} files",
146
+ fix_hint="Rename to avoid confusion",
147
+ ))
148
+ return violations
@@ -0,0 +1,111 @@
1
+ """B69. Sub-Agent Spawning with Virtual File Isolation.
2
+
3
+ Spawn focused sub-agents with fresh context, explicit file passing,
4
+ and tool scoping. Source: Sub-Agent-MCP pattern.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import time
9
+ from dataclasses import dataclass, field
10
+ from enum import Enum, auto
11
+ from typing import Callable
12
+
13
+
14
+ class AgentState(Enum):
15
+ PENDING = auto()
16
+ RUNNING = auto()
17
+ DONE = auto()
18
+ FAILED = auto()
19
+ CANCELLED = auto()
20
+
21
+
22
+ @dataclass
23
+ class SubAgentConfig:
24
+ id: str
25
+ name: str
26
+ system_prompt: str = ""
27
+ model: str = "" # empty = use parent's model
28
+ allowed_tools: list[str] = field(default_factory=list)
29
+ allowed_files: list[str] = field(default_factory=list) # explicit file passing
30
+ max_iterations: int = 5
31
+ timeout_s: float = 60.0
32
+
33
+
34
+ @dataclass
35
+ class SubAgentResult:
36
+ agent_id: str
37
+ state: AgentState = AgentState.PENDING
38
+ output: str = ""
39
+ files_read: list[str] = field(default_factory=list)
40
+ files_written: list[str] = field(default_factory=list)
41
+ tool_calls: int = 0
42
+ duration_s: float = 0.0
43
+ error: str | None = None
44
+
45
+
46
+ class SubAgentSpawner:
47
+ """Spawn sub-agents with virtual file isolation."""
48
+
49
+ def __init__(self) -> None:
50
+ self._configs: dict[str, SubAgentConfig] = {}
51
+ self._results: dict[str, SubAgentResult] = {}
52
+ self._active: dict[str, SubAgentResult] = {}
53
+
54
+ def register(self, config: SubAgentConfig) -> None:
55
+ self._configs[config.id] = config
56
+
57
+ def spawn(self, agent_id: str, task: str,
58
+ run_fn: Callable[[SubAgentConfig, str], str] | None = None) -> SubAgentResult:
59
+ config = self._configs.get(agent_id)
60
+ if not config:
61
+ raise KeyError(f"Agent {agent_id} not registered")
62
+
63
+ result = SubAgentResult(agent_id=agent_id, state=AgentState.RUNNING)
64
+ self._active[agent_id] = result
65
+ start = time.time()
66
+
67
+ try:
68
+ if run_fn:
69
+ output = run_fn(config, task)
70
+ else:
71
+ output = f"[{config.name}: {task}]"
72
+ result.output = output
73
+ result.state = AgentState.DONE
74
+ except Exception as e:
75
+ result.error = str(e)
76
+ result.state = AgentState.FAILED
77
+ finally:
78
+ result.duration_s = time.time() - start
79
+ self._results[agent_id] = result
80
+ self._active.pop(agent_id, None)
81
+
82
+ return result
83
+
84
+ def cancel(self, agent_id: str) -> bool:
85
+ result = self._active.get(agent_id)
86
+ if result and result.state == AgentState.RUNNING:
87
+ result.state = AgentState.CANCELLED
88
+ return True
89
+ return False
90
+
91
+ def get_result(self, agent_id: str) -> SubAgentResult | None:
92
+ return self._results.get(agent_id)
93
+
94
+ def list_active(self) -> list[str]:
95
+ return [aid for aid, r in self._active.items() if r.state == AgentState.RUNNING]
96
+
97
+ def can_access_file(self, agent_id: str, file_path: str) -> bool:
98
+ config = self._configs.get(agent_id)
99
+ if not config:
100
+ return False
101
+ if not config.allowed_files:
102
+ return True # no restriction
103
+ return file_path in config.allowed_files
104
+
105
+ def can_use_tool(self, agent_id: str, tool_name: str) -> bool:
106
+ config = self._configs.get(agent_id)
107
+ if not config:
108
+ return False
109
+ if not config.allowed_tools:
110
+ return True
111
+ return tool_name in config.allowed_tools
@@ -0,0 +1,70 @@
1
+ """H14 — Symmetric Encode/Decode Verification.
2
+
3
+ Every creator pattern needs a verifier companion.
4
+ Mined from ST3GG dual-use design.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass, field
9
+
10
+
11
+ @dataclass
12
+ class SymmetricPair:
13
+ """A creator/verifier pair of algorithm entries."""
14
+
15
+ creator_id: str
16
+ verifier_id: str
17
+ creator_title: str = ""
18
+ verifier_title: str = ""
19
+ metadata: dict[str, field] = field(default_factory=dict)
20
+
21
+ def to_dict(self) -> dict[str, str]:
22
+ return {
23
+ "creator_id": self.creator_id,
24
+ "verifier_id": self.verifier_id,
25
+ "creator_title": self.creator_title,
26
+ "verifier_title": self.verifier_title,
27
+ }
28
+
29
+
30
+ class SymmetricVerifier:
31
+ """Check that every creator entry has a matching verifier entry."""
32
+
33
+ def __init__(self) -> None:
34
+ self._pairs: list[SymmetricPair] = []
35
+
36
+ def register(
37
+ self,
38
+ creator_id: str,
39
+ verifier_id: str,
40
+ creator_title: str = "",
41
+ verifier_title: str = "",
42
+ ) -> SymmetricPair:
43
+ pair = SymmetricPair(
44
+ creator_id=creator_id,
45
+ verifier_id=verifier_id,
46
+ creator_title=creator_title,
47
+ verifier_title=verifier_title,
48
+ )
49
+ self._pairs.append(pair)
50
+ return pair
51
+
52
+ def check_symmetry(self, entry_ids: set[str]) -> list[str]:
53
+ """Return list of unpaired creator IDs."""
54
+ missing = []
55
+ for pair in self._pairs:
56
+ if pair.creator_id in entry_ids and pair.verifier_id not in entry_ids:
57
+ missing.append(pair.creator_id)
58
+ return missing
59
+
60
+ def get_pairs(self) -> list[SymmetricPair]:
61
+ return list(self._pairs)
62
+
63
+ def count(self) -> int:
64
+ return len(self._pairs)
65
+
66
+ def find_pair(self, creator_id: str) -> SymmetricPair | None:
67
+ for pair in self._pairs:
68
+ if pair.creator_id == creator_id:
69
+ return pair
70
+ return None
@@ -0,0 +1,129 @@
1
+ """B84. Task Classifier + Agent Delegator.
2
+
3
+ Classify tasks by complexity/domain. Route to appropriate agents.
4
+ Source: CCASP pattern.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass, field
9
+ from enum import Enum, auto
10
+ from typing import Callable
11
+
12
+
13
+ class TaskComplexity(Enum):
14
+ TRIVIAL = auto() # read, list, search — cheap model
15
+ SIMPLE = auto() # single edit, single test — standard model
16
+ MODERATE = auto() # multi-file edit, fix bug — standard model
17
+ COMPLEX = auto() # refactor, new feature — expensive model
18
+ CRITICAL = auto() # architecture, security — expensive model + review
19
+
20
+
21
+ class TaskDomain(Enum):
22
+ CODE = auto()
23
+ RESEARCH = auto()
24
+ MAINTENANCE = auto()
25
+ DOCUMENTATION = auto()
26
+ TESTING = auto()
27
+ DEPLOYMENT = auto()
28
+ UNKNOWN = auto()
29
+
30
+
31
+ @dataclass
32
+ class TaskClassification:
33
+ complexity: TaskComplexity
34
+ domain: TaskDomain
35
+ confidence: float = 0.5
36
+ suggested_model: str = ""
37
+ suggested_agents: list[str] = field(default_factory=list)
38
+ estimated_steps: int = 1
39
+
40
+
41
+ COMPLEXITY_KEYWORDS: dict[TaskComplexity, list[str]] = {
42
+ TaskComplexity.TRIVIAL: ["read", "list", "show", "find", "search", "grep", "where"],
43
+ TaskComplexity.SIMPLE: ["fix", "update", "rename", "add", "remove", "change"],
44
+ TaskComplexity.MODERATE: ["refactor", "migrate", "convert", "split", "merge"],
45
+ TaskComplexity.COMPLEX: ["implement", "design", "architect", "create new", "build"],
46
+ TaskComplexity.CRITICAL: ["security", "deploy", "release", "migration", "rewrite"],
47
+ }
48
+
49
+ DOMAIN_KEYWORDS: dict[TaskDomain, list[str]] = {
50
+ TaskDomain.CODE: ["function", "class", "method", "variable", "import", "module"],
51
+ TaskDomain.RESEARCH: ["research", "analyze", "compare", "investigate", "survey"],
52
+ TaskDomain.MAINTENANCE: ["maintain", "clean", "update", "upgrade", "fix"],
53
+ TaskDomain.DOCUMENTATION: ["document", "readme", "doc", "comment", "explain"],
54
+ TaskDomain.TESTING: ["test", "spec", "coverage", "mock", "fixture"],
55
+ TaskDomain.DEPLOYMENT: ["deploy", "release", "publish", "ci", "cd", "build"],
56
+ }
57
+
58
+ MODEL_BY_COMPLEXITY: dict[TaskComplexity, str] = {
59
+ TaskComplexity.TRIVIAL: "qwen3:4b",
60
+ TaskComplexity.SIMPLE: "glm-5.2",
61
+ TaskComplexity.MODERATE: "glm-5.2",
62
+ TaskComplexity.COMPLEX: "gpt-5.5",
63
+ TaskComplexity.CRITICAL: "gpt-5.5",
64
+ }
65
+
66
+
67
+ class TaskClassifier:
68
+ """Classify tasks by complexity and domain."""
69
+
70
+ def classify(self, task_description: str) -> TaskClassification:
71
+ desc_lower = task_description.lower()
72
+
73
+ # Determine complexity
74
+ complexity_scores: dict[TaskComplexity, int] = {}
75
+ for comp, keywords in COMPLEXITY_KEYWORDS.items():
76
+ score = sum(1 for kw in keywords if kw in desc_lower)
77
+ complexity_scores[comp] = score
78
+
79
+ complexity = max(complexity_scores, key=complexity_scores.get)
80
+ if complexity_scores[complexity] == 0:
81
+ complexity = TaskComplexity.SIMPLE # default
82
+
83
+ # Determine domain
84
+ domain_scores: dict[TaskDomain, int] = {}
85
+ for domain, keywords in DOMAIN_KEYWORDS.items():
86
+ score = sum(1 for kw in keywords if kw in desc_lower)
87
+ domain_scores[domain] = score
88
+
89
+ domain = max(domain_scores, key=domain_scores.get)
90
+ if domain_scores[domain] == 0:
91
+ domain = TaskDomain.UNKNOWN
92
+
93
+ # Estimate steps
94
+ step_count = desc_lower.count(" and ") + desc_lower.count(" then ") + 1
95
+ step_count = min(step_count, 10)
96
+
97
+ # Confidence based on keyword match strength
98
+ total_matches = sum(complexity_scores.values()) + sum(domain_scores.values())
99
+ confidence = min(1.0, total_matches / 5.0)
100
+
101
+ return TaskClassification(
102
+ complexity=complexity,
103
+ domain=domain,
104
+ confidence=confidence,
105
+ suggested_model=MODEL_BY_COMPLEXITY[complexity],
106
+ estimated_steps=step_count,
107
+ )
108
+
109
+
110
+ class AgentDelegator:
111
+ """Route classified tasks to appropriate agents."""
112
+
113
+ def __init__(self) -> None:
114
+ self._handlers: dict[TaskDomain, Callable[[str, TaskClassification], str]] = {}
115
+ self._classifier = TaskClassifier()
116
+
117
+ def register_handler(self, domain: TaskDomain,
118
+ handler: Callable[[str, TaskClassification], str]) -> None:
119
+ self._handlers[domain] = handler
120
+
121
+ def delegate(self, task: str) -> tuple[TaskClassification, str]:
122
+ """Classify and delegate a task. Returns (classification, result)."""
123
+ classification = self._classifier.classify(task)
124
+ handler = self._handlers.get(classification.domain)
125
+ if handler:
126
+ result = handler(task, classification)
127
+ else:
128
+ result = f"No handler for domain {classification.domain.name}"
129
+ return classification, result
@@ -0,0 +1,122 @@
1
+ """B72. Team Execution: ALL vs RACE Strategies.
2
+
3
+ ALL: wait for all agents, compare results.
4
+ RACE: first-success wins with atomic lock.
5
+ Input sharding: split input across agents.
6
+ Source: gecko pattern.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import threading
11
+ import time
12
+ from dataclasses import dataclass, field
13
+ from enum import Enum, auto
14
+ from typing import Any, Callable
15
+
16
+
17
+ class TeamStrategy(Enum):
18
+ ALL = auto() # wait for all, compare
19
+ RACE = auto() # first success wins
20
+
21
+
22
+ @dataclass
23
+ class TeamMember:
24
+ agent_id: str
25
+ model: str = ""
26
+ role: str = "worker"
27
+
28
+
29
+ @dataclass
30
+ class TeamResult:
31
+ strategy: TeamStrategy
32
+ results: dict[str, Any] = field(default_factory=dict) # agent_id → output
33
+ winner: str | None = None
34
+ errors: dict[str, str] = field(default_factory=dict)
35
+ duration_s: float = 0.0
36
+
37
+
38
+ class TeamExecutor:
39
+ """Execute tasks across a team of agents with ALL or RACE strategy."""
40
+
41
+ def __init__(self, members: list[TeamMember]) -> None:
42
+ self._members = {m.agent_id: m for m in members}
43
+ self._lock = threading.Lock()
44
+
45
+ def execute_all(
46
+ self,
47
+ task: str,
48
+ run_fn: Callable[[str, str], Any], # (agent_id, task) → output
49
+ timeout: float = 60.0,
50
+ ) -> TeamResult:
51
+ """ALL strategy: run all agents, wait for all, return all results."""
52
+ result = TeamResult(strategy=TeamStrategy.ALL)
53
+ start = time.time()
54
+ threads: list[threading.Thread] = []
55
+
56
+ def worker(agent_id: str) -> None:
57
+ try:
58
+ output = run_fn(agent_id, task)
59
+ with self._lock:
60
+ result.results[agent_id] = output
61
+ except Exception as e:
62
+ with self._lock:
63
+ result.errors[agent_id] = str(e)
64
+
65
+ for member_id in self._members:
66
+ t = threading.Thread(target=worker, args=(member_id,))
67
+ threads.append(t)
68
+ t.start()
69
+
70
+ for t in threads:
71
+ t.join(timeout=timeout)
72
+
73
+ result.duration_s = time.time() - start
74
+ return result
75
+
76
+ def execute_race(
77
+ self,
78
+ task: str,
79
+ run_fn: Callable[[str, str], Any],
80
+ timeout: float = 60.0,
81
+ ) -> TeamResult:
82
+ """RACE strategy: first agent to succeed wins."""
83
+ result = TeamResult(strategy=TeamStrategy.RACE)
84
+ start = time.time()
85
+ won = threading.Event()
86
+
87
+ def worker(agent_id: str) -> None:
88
+ if won.is_set():
89
+ return
90
+ try:
91
+ output = run_fn(agent_id, task)
92
+ with self._lock:
93
+ if not won.is_set():
94
+ result.results[agent_id] = output
95
+ result.winner = agent_id
96
+ won.set()
97
+ except Exception as e:
98
+ with self._lock:
99
+ result.errors[agent_id] = str(e)
100
+
101
+ threads: list[threading.Thread] = []
102
+ for member_id in self._members:
103
+ t = threading.Thread(target=worker, args=(member_id,))
104
+ threads.append(t)
105
+ t.start()
106
+
107
+ won.wait(timeout=timeout)
108
+ for t in threads:
109
+ t.join(timeout=1.0)
110
+
111
+ result.duration_s = time.time() - start
112
+ return result
113
+
114
+ def shard_input(self, items: list[Any], num_shards: int | None = None) -> list[list[Any]]:
115
+ """Split input items across team members."""
116
+ n = num_shards or len(self._members)
117
+ if n <= 0:
118
+ return [items]
119
+ shards: list[list[Any]] = [[] for _ in range(n)]
120
+ for i, item in enumerate(items):
121
+ shards[i % n].append(item)
122
+ return [s for s in shards if s]
@@ -0,0 +1,121 @@
1
+ """H31 — Tiered Tool Access.
2
+
3
+ Default / opt-in / approval-gated tool tiers.
4
+ Mined from T3MP3ST FEATURES.md §6.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import os
9
+ from dataclasses import dataclass
10
+ from enum import Enum
11
+ from typing import Any
12
+
13
+
14
+ class AccessTier(str, Enum):
15
+ DEFAULT = "default"
16
+ OPT_IN = "opt_in"
17
+ APPROVAL_GATED = "approval_gated"
18
+
19
+
20
+ @dataclass
21
+ class TierConfig:
22
+ """Configuration for a tool's access tier."""
23
+
24
+ tool_name: str
25
+ tier: AccessTier
26
+ env_var: str = ""
27
+ requires_approval: bool = False
28
+ description: str = ""
29
+
30
+ def to_dict(self) -> dict[str, Any]:
31
+ return {
32
+ "tool_name": self.tool_name,
33
+ "tier": self.tier.value,
34
+ "env_var": self.env_var,
35
+ "requires_approval": self.requires_approval,
36
+ "description": self.description,
37
+ }
38
+
39
+
40
+ @dataclass
41
+ class AccessResult:
42
+ """Result of an access check."""
43
+
44
+ granted: bool
45
+ reason: str = ""
46
+ required_tier: AccessTier = AccessTier.DEFAULT
47
+ missing_env_var: str = ""
48
+
49
+ def to_dict(self) -> dict[str, Any]:
50
+ return {
51
+ "granted": self.granted,
52
+ "reason": self.reason,
53
+ "required_tier": self.required_tier.value,
54
+ "missing_env_var": self.missing_env_var,
55
+ }
56
+
57
+
58
+ class TieredAccessGate:
59
+ """Check tool access against tiered configuration."""
60
+
61
+ def __init__(self) -> None:
62
+ self._configs: dict[str, TierConfig] = {}
63
+
64
+ def register(
65
+ self,
66
+ tool_name: str,
67
+ tier: AccessTier,
68
+ env_var: str = "",
69
+ requires_approval: bool = False,
70
+ description: str = "",
71
+ ) -> TierConfig:
72
+ config = TierConfig(
73
+ tool_name=tool_name,
74
+ tier=tier,
75
+ env_var=env_var,
76
+ requires_approval=requires_approval,
77
+ description=description,
78
+ )
79
+ self._configs[tool_name] = config
80
+ return config
81
+
82
+ def check(self, tool_name: str, approved: bool = False) -> AccessResult:
83
+ config = self._configs.get(tool_name)
84
+ if config is None:
85
+ return AccessResult(granted=True, reason="No tier config — default allow")
86
+ if config.tier == AccessTier.DEFAULT:
87
+ return AccessResult(granted=True, reason="Default tier — always allowed")
88
+ if config.tier == AccessTier.OPT_IN:
89
+ if config.env_var and not os.environ.get(config.env_var):
90
+ return AccessResult(
91
+ granted=False,
92
+ reason=f"Opt-in tool requires env var {config.env_var}",
93
+ required_tier=AccessTier.OPT_IN,
94
+ missing_env_var=config.env_var,
95
+ )
96
+ return AccessResult(granted=True, reason="Opt-in env var set")
97
+ if config.tier == AccessTier.APPROVAL_GATED:
98
+ if config.env_var and not os.environ.get(config.env_var):
99
+ return AccessResult(
100
+ granted=False,
101
+ reason=f"Approval-gated tool requires env var {config.env_var}",
102
+ required_tier=AccessTier.APPROVAL_GATED,
103
+ missing_env_var=config.env_var,
104
+ )
105
+ if not approved:
106
+ return AccessResult(
107
+ granted=False,
108
+ reason="Approval-gated tool requires explicit approval",
109
+ required_tier=AccessTier.APPROVAL_GATED,
110
+ )
111
+ return AccessResult(granted=True, reason="Approved and env var set")
112
+ return AccessResult(granted=False, reason="Unknown tier")
113
+
114
+ def get_config(self, tool_name: str) -> TierConfig | None:
115
+ return self._configs.get(tool_name)
116
+
117
+ def all_configs(self) -> list[TierConfig]:
118
+ return list(self._configs.values())
119
+
120
+ def count(self) -> int:
121
+ return len(self._configs)