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,104 @@
1
+ """B65. Multi-Source Parallel Fan-Out.
2
+
3
+ N questions × M sources = NM parallel tasks.
4
+ Source: deep-research-agent pattern.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import time
9
+ from concurrent.futures import ThreadPoolExecutor, as_completed
10
+ from dataclasses import dataclass, field
11
+ from typing import Callable
12
+
13
+
14
+ @dataclass
15
+ class FanOutTask:
16
+ question: str
17
+ source: str # "web", "github", "arxiv", "local"
18
+ query: str
19
+ priority: int = 5
20
+
21
+
22
+ @dataclass
23
+ class FanOutResult:
24
+ question: str
25
+ source: str
26
+ query: str
27
+ results: list[tuple[str, str]] = field(default_factory=list) # (title, content)
28
+ duration_s: float = 0.0
29
+ error: str | None = None
30
+ success: bool = True
31
+
32
+
33
+ class ParallelFanOut:
34
+ """Execute N questions × M sources in parallel."""
35
+
36
+ def __init__(self, max_workers: int = 4, timeout: float = 30.0) -> None:
37
+ self._max_workers = max_workers
38
+ self._timeout = timeout
39
+ self._source_handlers: dict[str, Callable[[str], list[tuple[str, str]]]] = {}
40
+
41
+ def register_source(self, name: str,
42
+ handler: Callable[[str], list[tuple[str, str]]]) -> None:
43
+ self._source_handlers[name] = handler
44
+
45
+ def fan_out(self, questions: list[str], sources: list[str]) -> list[FanOutResult]:
46
+ """Run all question×source combinations in parallel."""
47
+ tasks: list[FanOutTask] = []
48
+ for q in questions:
49
+ for src in sources:
50
+ tasks.append(FanOutTask(question=q, source=src, query=q))
51
+
52
+ return self._execute(tasks)
53
+
54
+ def _execute(self, tasks: list[FanOutTask]) -> list[FanOutResult]:
55
+ results: list[FanOutResult] = []
56
+
57
+ with ThreadPoolExecutor(max_workers=self._max_workers) as pool:
58
+ future_to_task = {
59
+ pool.submit(self._run_task, task): task for task in tasks
60
+ }
61
+ for future in as_completed(future_to_task, timeout=self._timeout):
62
+ task = future_to_task[future]
63
+ try:
64
+ results.append(future.result())
65
+ except Exception as e:
66
+ results.append(FanOutResult(
67
+ question=task.question, source=task.source,
68
+ query=task.query, error=str(e), success=False,
69
+ ))
70
+
71
+ return results
72
+
73
+ def _run_task(self, task: FanOutTask) -> FanOutResult:
74
+ handler = self._source_handlers.get(task.source)
75
+ if not handler:
76
+ return FanOutResult(
77
+ question=task.question, source=task.source,
78
+ query=task.query, error=f"No handler for source '{task.source}'",
79
+ success=False,
80
+ )
81
+ start = time.time()
82
+ try:
83
+ results = handler(task.query)
84
+ return FanOutResult(
85
+ question=task.question, source=task.source,
86
+ query=task.query, results=results,
87
+ duration_s=time.time() - start,
88
+ )
89
+ except Exception as e:
90
+ return FanOutResult(
91
+ question=task.question, source=task.source,
92
+ query=task.query, error=str(e), success=False,
93
+ duration_s=time.time() - start,
94
+ )
95
+
96
+ def merge_results(self, results: list[FanOutResult]) -> dict[str, list[tuple[str, str, str]]]:
97
+ """Merge results by question: {question: [(source, title, content), ...]}"""
98
+ merged: dict[str, list[tuple[str, str, str]]] = {}
99
+ for r in results:
100
+ if not r.success:
101
+ continue
102
+ for title, content in r.results:
103
+ merged.setdefault(r.question, []).append((r.source, title, content))
104
+ return merged
@@ -0,0 +1,105 @@
1
+ """B51. Declarative Permission Modes + Structural Spawn Safety.
2
+
3
+ Config-level tool sets and path restrictions. Prevent permission
4
+ escalation structurally. Source: aloop pattern.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ from dataclasses import dataclass, field
9
+ from enum import Enum, auto
10
+
11
+
12
+ class PermissionLevel(Enum):
13
+ READ_ONLY = auto()
14
+ STANDARD = auto()
15
+ ELEVATED = auto()
16
+ UNRESTRICTED = auto()
17
+
18
+
19
+ # Tool sets per permission level
20
+ DEFAULT_TOOL_SETS: dict[PermissionLevel, set[str]] = {
21
+ PermissionLevel.READ_ONLY: {
22
+ "read_file", "search_files", "list_directory", "harness_search",
23
+ "harness_read", "web_search", "web_fetch", "read_pdf",
24
+ },
25
+ PermissionLevel.STANDARD: {
26
+ "read_file", "search_files", "list_directory", "write_file",
27
+ "edit_file", "run_shell", "harness_search", "harness_read",
28
+ "web_search", "web_fetch", "read_pdf", "embed_text",
29
+ },
30
+ PermissionLevel.ELEVATED: {
31
+ "read_file", "search_files", "list_directory", "write_file",
32
+ "edit_file", "run_shell", "harness_search", "harness_read",
33
+ "web_search", "web_fetch", "read_pdf", "embed_text",
34
+ "model_create", "model_delete", "git_status", "git_diff",
35
+ },
36
+ PermissionLevel.UNRESTRICTED: {"*"},
37
+ }
38
+
39
+ # Which levels can spawn which levels (prevent escalation)
40
+ SPAWN_MATRIX: dict[PermissionLevel, set[PermissionLevel]] = {
41
+ PermissionLevel.READ_ONLY: set(),
42
+ PermissionLevel.STANDARD: {PermissionLevel.READ_ONLY},
43
+ PermissionLevel.ELEVATED: {PermissionLevel.READ_ONLY, PermissionLevel.STANDARD},
44
+ PermissionLevel.UNRESTRICTED: {
45
+ PermissionLevel.READ_ONLY, PermissionLevel.STANDARD,
46
+ PermissionLevel.ELEVATED, PermissionLevel.UNRESTRICTED,
47
+ },
48
+ }
49
+
50
+
51
+ @dataclass
52
+ class PermissionMode:
53
+ level: PermissionLevel
54
+ allowed_tools: set[str] = field(default_factory=set)
55
+ allowed_paths: list[str] = field(default_factory=list) # glob patterns
56
+ denied_paths: list[str] = field(default_factory=list)
57
+ spawnable_modes: set[PermissionLevel] = field(default_factory=set)
58
+
59
+ def __post_init__(self) -> None:
60
+ if not self.allowed_tools:
61
+ self.allowed_tools = DEFAULT_TOOL_SETS.get(self.level, set()).copy()
62
+ if not self.spawnable_modes:
63
+ self.spawnable_modes = SPAWN_MATRIX.get(self.level, set()).copy()
64
+
65
+ def can_use_tool(self, tool_name: str) -> bool:
66
+ return "*" in self.allowed_tools or tool_name in self.allowed_tools
67
+
68
+ def can_access_path(self, path: str) -> bool:
69
+ import fnmatch
70
+ for denied in self.denied_paths:
71
+ if fnmatch.fnmatch(path, denied):
72
+ return False
73
+ if not self.allowed_paths:
74
+ return True
75
+ return any(fnmatch.fnmatch(path, p) for p in self.allowed_paths)
76
+
77
+ def can_spawn(self, target_level: PermissionLevel) -> bool:
78
+ return target_level in self.spawnable_modes
79
+
80
+
81
+ class PermissionManager:
82
+ """Manage permission modes and enforce structural spawn safety."""
83
+
84
+ def __init__(self, default_level: PermissionLevel = PermissionLevel.STANDARD) -> None:
85
+ self._modes: dict[str, PermissionMode] = {}
86
+ self._default = PermissionMode(level=default_level)
87
+
88
+ def register(self, name: str, mode: PermissionMode) -> None:
89
+ self._modes[name] = mode
90
+
91
+ def get(self, name: str | None) -> PermissionMode:
92
+ if name and name in self._modes:
93
+ return self._modes[name]
94
+ return self._default
95
+
96
+ def validate_spawn(
97
+ self,
98
+ parent_name: str | None,
99
+ child_level: PermissionLevel,
100
+ ) -> bool:
101
+ parent = self.get(parent_name)
102
+ return parent.can_spawn(child_level)
103
+
104
+ def list_modes(self) -> dict[str, PermissionMode]:
105
+ return dict(self._modes)
@@ -0,0 +1,68 @@
1
+ """H32 — Pre-Push Scrubbing Gate.
2
+
3
+ Hard-blocks raw pushes of private working tree; requires explicit env var
4
+ override. Mirrors T3MP3ST ``.githooks/pre-push`` pattern.
5
+
6
+ Source: T3MP3ST ``.githooks/pre-push``.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ from dataclasses import dataclass
11
+ from typing import Callable, Optional
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class GateResult:
16
+ """Result of a pre-push gate check."""
17
+
18
+ allowed: bool
19
+ reason: str
20
+ override_used: bool
21
+
22
+
23
+ class PrePushGate:
24
+ """Gate that blocks pushes unless an override env var is set."""
25
+
26
+ def __init__(self, override_env_var: str = "ALGO_ALLOW_RAW_PUSH") -> None:
27
+ self.override_env_var = override_env_var
28
+
29
+ def check(
30
+ self,
31
+ env_getter: Callable[[str], Optional[str]] = lambda _k: None,
32
+ allow_override: bool = False,
33
+ ) -> GateResult:
34
+ """Check whether a push should be allowed.
35
+
36
+ Args:
37
+ env_getter: Function that returns env var values (defaults to None).
38
+ allow_override: If True, skip the env var check entirely.
39
+
40
+ Returns:
41
+ GateResult with allowed=True if push should proceed.
42
+ """
43
+ if allow_override:
44
+ return GateResult(
45
+ allowed=True,
46
+ reason="Override explicitly granted by caller.",
47
+ override_used=True,
48
+ )
49
+ env_value = env_getter(self.override_env_var)
50
+ if env_value and env_value.lower() in ("1", "true", "yes"):
51
+ return GateResult(
52
+ allowed=True,
53
+ reason=f"Override env var {self.override_env_var} is set.",
54
+ override_used=True,
55
+ )
56
+ return GateResult(
57
+ allowed=False,
58
+ reason=(
59
+ f"Raw push blocked. Set {self.override_env_var}=1 to override, "
60
+ "or use a scrubbed export path."
61
+ ),
62
+ override_used=False,
63
+ )
64
+
65
+ def require_override(self, env_getter: Callable[[str], Optional[str]] = lambda _k: None) -> bool:
66
+ """Return True if an override is required to push."""
67
+ result = self.check(env_getter=env_getter)
68
+ return not result.allowed
@@ -0,0 +1,171 @@
1
+ """Content Prefetch — predictive cache warming via transition matrix.
2
+
3
+ Borrowed from Windows.Networking.BackgroundTransfer.ContentPrefetchTask.dll:
4
+ Windows allows apps to register prefetch tasks that run before the user opens
5
+ the app — warming the cache with content the user is likely to request.
6
+
7
+ This module learns access patterns ("after reading X, user usually reads Y")
8
+ and pre-loads predicted files into an LRU cache before they're requested.
9
+
10
+ Pattern: B33 in ALGO.md.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import time
15
+ from collections import Counter, OrderedDict
16
+ from dataclasses import dataclass
17
+ from typing import Any, Callable
18
+
19
+
20
+ @dataclass
21
+ class AccessRecord:
22
+ """A single file access record."""
23
+ path: str
24
+ timestamp: float
25
+ action: str = "read"
26
+
27
+
28
+ class PredictivePrefetch:
29
+ """Predict next likely accesses based on temporal transition patterns.
30
+
31
+ Usage:
32
+ cache = PredictivePrefetch(max_cache=32)
33
+ content = cache.get("foo.py", loader=read_file)
34
+ # cache learns: after foo.py, user often reads test_foo.py
35
+ # next time foo.py is read, test_foo.py is pre-warmed
36
+ """
37
+
38
+ def __init__(self, max_cache: int = 32, max_history: int = 1000):
39
+ self.max_cache = max_cache
40
+ self.max_history = max_history
41
+ self.access_history: list[AccessRecord] = []
42
+ self.prefetch_cache: OrderedDict[str, Any] = OrderedDict()
43
+ self.transition_counts: Counter = Counter()
44
+ # Per-path access frequency (for cold-start predictions)
45
+ self.access_frequency: Counter = Counter()
46
+
47
+ # --- learning ---------------------------------------------------------
48
+
49
+ def record_access(self, path: str, action: str = "read") -> None:
50
+ """Record a file access for pattern learning."""
51
+ now = time.time()
52
+ # Learn transition: previous access → this access
53
+ if self.access_history:
54
+ prev = self.access_history[-1]
55
+ key = f"{prev.path}|{prev.action}->{path}|{action}"
56
+ self.transition_counts[key] += 1
57
+ self.access_history.append(AccessRecord(path, now, action))
58
+ self.access_frequency[path] += 1
59
+ # Bound history
60
+ if len(self.access_history) > self.max_history:
61
+ self.access_history = self.access_history[-self.max_history // 2 :]
62
+
63
+ # --- prediction -------------------------------------------------------
64
+
65
+ def predict_next(self, current_path: str, action: str = "read") -> list[str]:
66
+ """Predict likely next accesses given current access.
67
+
68
+ Returns paths sorted by transition probability (descending).
69
+ """
70
+ candidates: Counter = Counter()
71
+ prefix = f"{current_path}|{action}->"
72
+ for key, count in self.transition_counts.items():
73
+ if key.startswith(prefix):
74
+ suffix = key[len(prefix):]
75
+ next_path = suffix.split("|")[0]
76
+ candidates[next_path] = count
77
+
78
+ # If no transitions learned, fall back to most-accessed paths
79
+ if not candidates:
80
+ for path, freq in self.access_frequency.most_common(self.max_cache):
81
+ if path != current_path:
82
+ candidates[path] = freq
83
+
84
+ return [p for p, _ in candidates.most_common(self.max_cache)]
85
+
86
+ # --- cache management -------------------------------------------------
87
+
88
+ def warm_cache(self, paths: list[str], loader: Callable[[str], Any]) -> int:
89
+ """Pre-load predicted paths into cache. Returns number warmed."""
90
+ warmed = 0
91
+ for path in paths:
92
+ if path not in self.prefetch_cache:
93
+ try:
94
+ self.prefetch_cache[path] = loader(path)
95
+ warmed += 1
96
+ except Exception:
97
+ pass # prefetch failures are silent (best-effort)
98
+ self._evict()
99
+ return warmed
100
+
101
+ def prefetch_for(self, current_path: str, loader: Callable[[str], Any]) -> int:
102
+ """Predict and warm cache for likely-next accesses."""
103
+ predicted = self.predict_next(current_path)
104
+ return self.warm_cache(predicted, loader)
105
+
106
+ def get(self, path: str, loader: Callable[[str], Any]) -> Any:
107
+ """Get from cache or load on miss. Records access for learning."""
108
+ if path in self.prefetch_cache:
109
+ self.prefetch_cache.move_to_end(path)
110
+ self.record_access(path, "read")
111
+ return self.prefetch_cache[path]
112
+ result = loader(path)
113
+ self.prefetch_cache[path] = result
114
+ self.record_access(path, "read")
115
+ self._evict()
116
+ # After loading, prefetch likely-next files in background
117
+ # (caller can call prefetch_for explicitly for async warming)
118
+ return result
119
+
120
+ def _evict(self) -> None:
121
+ """Evict oldest entries if over capacity (LRU)."""
122
+ while len(self.prefetch_cache) > self.max_cache:
123
+ self.prefetch_cache.popitem(last=False)
124
+
125
+ # --- queries ----------------------------------------------------------
126
+
127
+ def cache_size(self) -> int:
128
+ return len(self.prefetch_cache)
129
+
130
+ def cache_hit_rate(self) -> float:
131
+ """Calculate cache hit rate from access history."""
132
+ if not self.access_history:
133
+ return 0.0
134
+ hits = sum(
135
+ 1 for rec in self.access_history
136
+ if rec.path in self.prefetch_cache
137
+ )
138
+ return hits / len(self.access_history)
139
+
140
+ def cached_paths(self) -> list[str]:
141
+ return list(self.prefetch_cache.keys())
142
+
143
+ def stats(self) -> dict[str, Any]:
144
+ return {
145
+ "cache_size": self.cache_size(),
146
+ "cache_capacity": self.max_cache,
147
+ "history_size": len(self.access_history),
148
+ "transitions_learned": len(self.transition_counts),
149
+ "unique_paths_accessed": len(self.access_frequency),
150
+ "cache_hit_rate": round(self.cache_hit_rate(), 3),
151
+ }
152
+
153
+ # --- persistence ------------------------------------------------------
154
+
155
+ def export_transitions(self) -> dict[str, int]:
156
+ """Export transition counts for persistence/analysis."""
157
+ return dict(self.transition_counts)
158
+
159
+ def import_transitions(self, data: dict[str, int]) -> None:
160
+ """Import previously learned transition counts."""
161
+ for key, count in data.items():
162
+ self.transition_counts[key] += count
163
+
164
+ def export_frequency(self) -> dict[str, int]:
165
+ """Export access frequency for persistence."""
166
+ return dict(self.access_frequency)
167
+
168
+ def import_frequency(self, data: dict[str, int]) -> None:
169
+ """Import previously learned access frequency."""
170
+ for path, count in data.items():
171
+ self.access_frequency[path] += count
@@ -0,0 +1,217 @@
1
+ """B46. Process Framework for Business Workflows (Semantic Kernel Pattern).
2
+
3
+ Models real-world business processes (bid → permit → install → invoice)
4
+ as state machines with typed steps, conditional transitions, retries,
5
+ and failure fallbacks. Processes are serializable for pause/resume.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ from dataclasses import dataclass, field
12
+ from enum import Enum
13
+ from typing import Any, Callable
14
+
15
+
16
+ class ProcessState(Enum):
17
+ PENDING = "pending"
18
+ RUNNING = "running"
19
+ WAITING = "waiting"
20
+ COMPLETED = "completed"
21
+ FAILED = "failed"
22
+ SKIPPED = "skipped"
23
+
24
+
25
+ @dataclass
26
+ class ProcessStep:
27
+ name: str
28
+ action: Callable[[dict], Any]
29
+ inputs: dict[str, Any] = field(default_factory=dict)
30
+ outputs: dict[str, Any] = field(default_factory=dict)
31
+ state: ProcessState = ProcessState.PENDING
32
+ condition: Callable[[dict], bool] | None = None
33
+ on_success: str | None = None
34
+ on_failure: str | None = None
35
+ retries: int = 0
36
+ max_retries: int = 3
37
+
38
+ def to_dict(self) -> dict:
39
+ return {
40
+ "name": self.name,
41
+ "state": self.state.value,
42
+ "retries": self.retries,
43
+ "outputs": self.outputs,
44
+ }
45
+
46
+
47
+ class Process:
48
+ """State-machine workflow with conditional transitions."""
49
+
50
+ def __init__(self, name: str):
51
+ self.name = name
52
+ self.steps: dict[str, ProcessStep] = {}
53
+ self.start_step: str | None = None
54
+ self.context: dict[str, Any] = {}
55
+ self.completed: bool = False
56
+
57
+ def add_step(self, step: ProcessStep, is_start: bool = False) -> None:
58
+ self.steps[step.name] = step
59
+ if is_start:
60
+ self.start_step = step.name
61
+
62
+ def run(self, context: dict[str, Any] | None = None) -> dict[str, Any]:
63
+ """Execute the process from start to end (or failure)."""
64
+ if context:
65
+ self.context.update(context)
66
+ current = self.start_step
67
+ while current:
68
+ step = self.steps.get(current)
69
+ if not step:
70
+ break
71
+ # Condition gate
72
+ if step.condition and not step.condition(self.context):
73
+ step.state = ProcessState.SKIPPED
74
+ current = step.on_success
75
+ continue
76
+ step.state = ProcessState.RUNNING
77
+ try:
78
+ result = step.action(self.context)
79
+ step.outputs = result if isinstance(result, dict) else {"result": result}
80
+ self.context.update(step.outputs)
81
+ step.state = ProcessState.COMPLETED
82
+ current = step.on_success
83
+ except Exception as e:
84
+ step.retries += 1
85
+ if step.retries < step.max_retries:
86
+ step.state = ProcessState.WAITING
87
+ continue # retry same step
88
+ step.state = ProcessState.FAILED
89
+ self.context[f"{step.name}_error"] = str(e)
90
+ current = step.on_failure
91
+ self.completed = True
92
+ return self.context
93
+
94
+ def status(self) -> dict[str, Any]:
95
+ """Return current process status."""
96
+ return {
97
+ "name": self.name,
98
+ "completed": self.completed,
99
+ "steps": {name: step.to_dict() for name, step in self.steps.items()},
100
+ "context_keys": list(self.context.keys()),
101
+ }
102
+
103
+ def serialize(self) -> str:
104
+ """Serialize process state for persistence."""
105
+ return json.dumps({
106
+ "name": self.name,
107
+ "start_step": self.start_step,
108
+ "completed": self.completed,
109
+ "context": {k: v for k, v in self.context.items() if isinstance(v, (str, int, float, bool, list, dict))},
110
+ "steps": {name: step.to_dict() for name, step in self.steps.items()},
111
+ }, indent=2)
112
+
113
+ def resume_from(self, step_name: str) -> dict[str, Any]:
114
+ """Resume execution from a specific step."""
115
+ current = step_name
116
+ while current:
117
+ step = self.steps.get(current)
118
+ if not step:
119
+ break
120
+ if step.state == ProcessState.COMPLETED:
121
+ current = step.on_success
122
+ continue
123
+ if step.condition and not step.condition(self.context):
124
+ step.state = ProcessState.SKIPPED
125
+ current = step.on_success
126
+ continue
127
+ step.state = ProcessState.RUNNING
128
+ try:
129
+ result = step.action(self.context)
130
+ step.outputs = result if isinstance(result, dict) else {"result": result}
131
+ self.context.update(step.outputs)
132
+ step.state = ProcessState.COMPLETED
133
+ current = step.on_success
134
+ except Exception as e:
135
+ step.retries += 1
136
+ if step.retries < step.max_retries:
137
+ step.state = ProcessState.WAITING
138
+ continue
139
+ step.state = ProcessState.FAILED
140
+ self.context[f"{step.name}_error"] = str(e)
141
+ current = step.on_failure
142
+ self.completed = True
143
+ return self.context
144
+
145
+
146
+ # ── factories for reusable business workflows ────────────────────────
147
+
148
+
149
+ def make_bid_process() -> Process:
150
+ """Create a standard bid workflow."""
151
+ p = Process("bid_process")
152
+
153
+ def site_visit(ctx: dict) -> dict:
154
+ return {"site_visited": True, "notes": ctx.get("notes", "")}
155
+
156
+ def estimate(ctx: dict) -> dict:
157
+ return {"estimate_total": ctx.get("estimate_total", 0)}
158
+
159
+ def send_bid(ctx: dict) -> dict:
160
+ return {"bid_sent": True, "bid_amount": ctx.get("estimate_total", 0)}
161
+
162
+ def follow_up(ctx: dict) -> dict:
163
+ return {"follow_up_sent": True}
164
+
165
+ def won(ctx: dict) -> dict:
166
+ return {"status": "won"}
167
+
168
+ def lost(ctx: dict) -> dict:
169
+ return {"status": "lost"}
170
+
171
+ p.add_step(ProcessStep(name="site_visit", action=site_visit, on_success="estimate"), is_start=True)
172
+ p.add_step(ProcessStep(name="estimate", action=estimate, on_success="send_bid"))
173
+ p.add_step(ProcessStep(name="send_bid", action=send_bid, on_success="follow_up"))
174
+ p.add_step(ProcessStep(name="follow_up", action=follow_up, on_success="check_result"))
175
+ p.add_step(ProcessStep(
176
+ name="check_result",
177
+ action=lambda ctx: {"won": ctx.get("won", False)},
178
+ condition=lambda ctx: ctx.get("won", False),
179
+ on_success="won",
180
+ on_failure="lost",
181
+ ))
182
+ p.add_step(ProcessStep(name="won", action=won))
183
+ p.add_step(ProcessStep(name="lost", action=lost))
184
+ return p
185
+
186
+
187
+ def make_permit_process() -> Process:
188
+ """Create a standard permit workflow."""
189
+ p = Process("permit_process")
190
+
191
+ def apply(ctx: dict) -> dict:
192
+ return {"permit_submitted": True}
193
+
194
+ def review(ctx: dict) -> dict:
195
+ return {"reviewed": True, "approved": ctx.get("approved", False)}
196
+
197
+ def corrections(ctx: dict) -> dict:
198
+ return {"corrections_made": True}
199
+
200
+ def approval(ctx: dict) -> dict:
201
+ return {"permit_approved": True}
202
+
203
+ def schedule_inspection(ctx: dict) -> dict:
204
+ return {"inspection_scheduled": True}
205
+
206
+ p.add_step(ProcessStep(name="apply", action=apply, on_success="review"), is_start=True)
207
+ p.add_step(ProcessStep(
208
+ name="review",
209
+ action=review,
210
+ condition=lambda ctx: ctx.get("approved", False),
211
+ on_success="approval",
212
+ on_failure="corrections",
213
+ ))
214
+ p.add_step(ProcessStep(name="corrections", action=corrections, on_success="review"))
215
+ p.add_step(ProcessStep(name="approval", action=approval, on_success="schedule_inspection"))
216
+ p.add_step(ProcessStep(name="schedule_inspection", action=schedule_inspection))
217
+ return p