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.
- algo_cli/__init__.py +3 -0
- algo_cli/__main__.py +7 -0
- algo_cli/_internal/__init__.py +12 -0
- algo_cli/_internal/policy_chain.py +259 -0
- algo_cli/action_registry.py +1047 -0
- algo_cli/agent_blocks.py +550 -0
- algo_cli/agent_pipeline.py +1457 -0
- algo_cli/agent_threads.py +308 -0
- algo_cli/animations.py +316 -0
- algo_cli/cache_admission.py +209 -0
- algo_cli/capability_mask.py +66 -0
- algo_cli/chat_protocol.py +116 -0
- algo_cli/chatgpt_auth.py +510 -0
- algo_cli/chatgpt_client.py +657 -0
- algo_cli/code_rag.py +479 -0
- algo_cli/config.py +651 -0
- algo_cli/context_budget.py +679 -0
- algo_cli/credential_helpers.py +315 -0
- algo_cli/deliberation.py +29 -0
- algo_cli/display.py +1470 -0
- algo_cli/evals/__init__.py +21 -0
- algo_cli/evals/algorithm_effectiveness.py +560 -0
- algo_cli/evals/competitive_harness_rating.py +702 -0
- algo_cli/evals/cot_quality.py +220 -0
- algo_cli/evals/harness_retrieval_benchmark.py +401 -0
- algo_cli/evals/performance_regression.py +136 -0
- algo_cli/evals/scorecard_grading.py +308 -0
- algo_cli/evals/session_distribution.py +84 -0
- algo_cli/execution_guardrails.py +806 -0
- algo_cli/extensions_manifest.py +84 -0
- algo_cli/git_evidence.py +227 -0
- algo_cli/google_workspace.py +407 -0
- algo_cli/google_workspace_auth.py +523 -0
- algo_cli/harness.py +2587 -0
- algo_cli/identity.py +557 -0
- algo_cli/index_compute_lab.py +228 -0
- algo_cli/inference_harness.py +70 -0
- algo_cli/intelligence/__init__.py +1103 -0
- algo_cli/intelligence/acrobat_config.py +307 -0
- algo_cli/intelligence/acrobat_manifests.py +338 -0
- algo_cli/intelligence/acrobat_models.py +195 -0
- algo_cli/intelligence/acrobat_pipeline.py +295 -0
- algo_cli/intelligence/acrobat_runtime.py +302 -0
- algo_cli/intelligence/acrobat_security.py +261 -0
- algo_cli/intelligence/acrobat_workflows.py +226 -0
- algo_cli/intelligence/actionability.py +165 -0
- algo_cli/intelligence/adversarial_audit.py +136 -0
- algo_cli/intelligence/agent_arena.py +92 -0
- algo_cli/intelligence/agent_benchmark.py +236 -0
- algo_cli/intelligence/agent_runtime.py +171 -0
- algo_cli/intelligence/agents_as_tools.py +70 -0
- algo_cli/intelligence/artifact_binding.py +80 -0
- algo_cli/intelligence/autonomous_engineer.py +1976 -0
- algo_cli/intelligence/backpressure.py +99 -0
- algo_cli/intelligence/bloom_filter.py +186 -0
- algo_cli/intelligence/bonferroni.py +66 -0
- algo_cli/intelligence/boundary_compaction.py +98 -0
- algo_cli/intelligence/catalog_verifier.py +172 -0
- algo_cli/intelligence/cavecrew.py +118 -0
- algo_cli/intelligence/changelog.py +176 -0
- algo_cli/intelligence/checkpoint_resume.py +92 -0
- algo_cli/intelligence/circuit_breaker.py +88 -0
- algo_cli/intelligence/clarification_gate.py +101 -0
- algo_cli/intelligence/code_graph.py +180 -0
- algo_cli/intelligence/coderank.py +97 -0
- algo_cli/intelligence/consistent_hash.py +150 -0
- algo_cli/intelligence/consortium_synthesis.py +139 -0
- algo_cli/intelligence/construction/__init__.py +241 -0
- algo_cli/intelligence/construction/common.py +273 -0
- algo_cli/intelligence/construction/documents.py +496 -0
- algo_cli/intelligence/construction/labor_units.py +1395 -0
- algo_cli/intelligence/construction/payments.py +470 -0
- algo_cli/intelligence/construction/risk.py +784 -0
- algo_cli/intelligence/content_extractor.py +132 -0
- algo_cli/intelligence/context_adaptive.py +102 -0
- algo_cli/intelligence/context_ops.py +95 -0
- algo_cli/intelligence/count_min.py +145 -0
- algo_cli/intelligence/cow_state.py +103 -0
- algo_cli/intelligence/critic_loop.py +119 -0
- algo_cli/intelligence/cross_source.py +113 -0
- algo_cli/intelligence/daemon_mode.py +99 -0
- algo_cli/intelligence/dag_orchestration.py +151 -0
- algo_cli/intelligence/deep_research.py +155 -0
- algo_cli/intelligence/degenerate_detector.py +78 -0
- algo_cli/intelligence/delta_report.py +92 -0
- algo_cli/intelligence/discovery_event_log.py +92 -0
- algo_cli/intelligence/document_ingest.py +298 -0
- algo_cli/intelligence/dual_layer_validate.py +151 -0
- algo_cli/intelligence/echo_fidelity.py +73 -0
- algo_cli/intelligence/ema_tuning.py +104 -0
- algo_cli/intelligence/event_log.py +92 -0
- algo_cli/intelligence/evidence_graph.py +114 -0
- algo_cli/intelligence/extension_host.py +162 -0
- algo_cli/intelligence/extension_manifest.py +115 -0
- algo_cli/intelligence/falsification_suite.py +178 -0
- algo_cli/intelligence/finance/__init__.py +169 -0
- algo_cli/intelligence/finance/anomalies.py +135 -0
- algo_cli/intelligence/finance/ap_ar.py +351 -0
- algo_cli/intelligence/finance/cash.py +162 -0
- algo_cli/intelligence/finance/close.py +332 -0
- algo_cli/intelligence/finance/common.py +244 -0
- algo_cli/intelligence/finance/construction.py +135 -0
- algo_cli/intelligence/finance/controls.py +172 -0
- algo_cli/intelligence/finance/evidence.py +119 -0
- algo_cli/intelligence/finance/exceptions.py +157 -0
- algo_cli/intelligence/finance/reconciliations.py +254 -0
- algo_cli/intelligence/finance/revenue.py +109 -0
- algo_cli/intelligence/finance/tax.py +74 -0
- algo_cli/intelligence/finance/workpapers.py +111 -0
- algo_cli/intelligence/finding_record.py +120 -0
- algo_cli/intelligence/flow_dag.py +267 -0
- algo_cli/intelligence/gatherer.py +223 -0
- algo_cli/intelligence/golden_master.py +98 -0
- algo_cli/intelligence/graph_rag.py +195 -0
- algo_cli/intelligence/group_chat.py +143 -0
- algo_cli/intelligence/hash_dedup.py +145 -0
- algo_cli/intelligence/hyperloglog.py +128 -0
- algo_cli/intelligence/incremental_index.py +316 -0
- algo_cli/intelligence/index_store.py +16 -0
- algo_cli/intelligence/iteration_plan.py +133 -0
- algo_cli/intelligence/kernel_plugins.py +167 -0
- algo_cli/intelligence/lesson_catalog.py +135 -0
- algo_cli/intelligence/llm_fallback.py +169 -0
- algo_cli/intelligence/log2_histogram.py +267 -0
- algo_cli/intelligence/lsp_integration.py +147 -0
- algo_cli/intelligence/memory_evolution.py +117 -0
- algo_cli/intelligence/minhash_lsh.py +182 -0
- algo_cli/intelligence/multi_model_score.py +174 -0
- algo_cli/intelligence/multi_tier_grade.py +211 -0
- algo_cli/intelligence/negative_controls.py +113 -0
- algo_cli/intelligence/numeric_clamp.py +63 -0
- algo_cli/intelligence/occ_editor.py +66 -0
- algo_cli/intelligence/output_normalize.py +112 -0
- algo_cli/intelligence/parallel_delegation.py +98 -0
- algo_cli/intelligence/parallel_fanout.py +104 -0
- algo_cli/intelligence/permission_modes.py +105 -0
- algo_cli/intelligence/pre_push_gate.py +68 -0
- algo_cli/intelligence/prefetch.py +171 -0
- algo_cli/intelligence/process_framework.py +217 -0
- algo_cli/intelligence/project_graph.py +387 -0
- algo_cli/intelligence/query_expansion.py +146 -0
- algo_cli/intelligence/ralph_loop.py +117 -0
- algo_cli/intelligence/rate_limiter.py +153 -0
- algo_cli/intelligence/refactor_transaction.py +94 -0
- algo_cli/intelligence/research_workspace.py +108 -0
- algo_cli/intelligence/retraction_ledger.py +72 -0
- algo_cli/intelligence/saga_pattern.py +88 -0
- algo_cli/intelligence/session_fork.py +100 -0
- algo_cli/intelligence/shadow_editor.py +67 -0
- algo_cli/intelligence/shell_session.py +213 -0
- algo_cli/intelligence/source_registry.py +143 -0
- algo_cli/intelligence/spawn_scales.py +99 -0
- algo_cli/intelligence/stat_stability.py +104 -0
- algo_cli/intelligence/structural_validator.py +148 -0
- algo_cli/intelligence/subagent_spawner.py +111 -0
- algo_cli/intelligence/symmetric_verify.py +70 -0
- algo_cli/intelligence/task_classifier.py +129 -0
- algo_cli/intelligence/team_execution.py +122 -0
- algo_cli/intelligence/tiered_access.py +121 -0
- algo_cli/intelligence/utility_registry.py +159 -0
- algo_cli/intuition_engine.py +560 -0
- algo_cli/intuition_injector.py +82 -0
- algo_cli/kernels/__init__.py +5 -0
- algo_cli/kernels/manifest.py +763 -0
- algo_cli/main.py +3903 -0
- algo_cli/memory_candidates.py +541 -0
- algo_cli/memory_echo_veil.py +394 -0
- algo_cli/memory_runtime.py +112 -0
- algo_cli/model_info.py +548 -0
- algo_cli/model_profile.py +160 -0
- algo_cli/model_routing.py +74 -0
- algo_cli/oneshot.py +331 -0
- algo_cli/perf_telemetry.py +389 -0
- algo_cli/plugins.py +245 -0
- algo_cli/private_event_store.py +654 -0
- algo_cli/quantization/__init__.py +24 -0
- algo_cli/quantization/lloyd_max.py +98 -0
- algo_cli/quantization/turbo_quant.py +308 -0
- algo_cli/reasoning/__init__.py +46 -0
- algo_cli/reasoning/combinatorial.py +356 -0
- algo_cli/reasoning/graph_of_thought.py +297 -0
- algo_cli/reasoning/mcts.py +220 -0
- algo_cli/reasoning/neuro_symbolic.py +250 -0
- algo_cli/reasoning/react.py +246 -0
- algo_cli/reasoning/reflexion.py +225 -0
- algo_cli/reasoning/tree_of_thought.py +241 -0
- algo_cli/reasoning_bridge.py +150 -0
- algo_cli/reconciliation.py +284 -0
- algo_cli/reflex.py +385 -0
- algo_cli/resources/docs/ALGO.md +13958 -0
- algo_cli/resources/docs/algo-cli-algorithm-evidence-contract.md +60 -0
- algo_cli/resources/docs/algo-cli-execution-verification-contract.md +59 -0
- algo_cli/resources/docs/algo-cli-memory-lifecycle-contract.md +72 -0
- algo_cli/resources/docs/harness-extension-cleanup-recommendation.md +41 -0
- algo_cli/resources/docs/index-compute-lab-integration.md +32 -0
- algo_cli/resources/docs/inference-harness-loop-blueprint-2026-06.md +55 -0
- algo_cli/resources/docs/main-split-map.md +35 -0
- algo_cli/resources/docs/privacy-and-context.md +48 -0
- algo_cli/resources/docs/reflex-loop-v0.2.md +354 -0
- algo_cli/resources/skills/README.md +26 -0
- algo_cli/resources/skills/algo-cli.md +59 -0
- algo_cli/resources/skills/edit-file-precision.md +49 -0
- algo_cli/resources/skills/harness-search-first.md +47 -0
- algo_cli/resources/skills/memory-recall-ritual.md +51 -0
- algo_cli/resources/skills/qol-algorithms.md +224 -0
- algo_cli/resources/skills/smart-error-recovery.md +56 -0
- algo_cli/resources/skills/tool-selection-cheatsheet.md +65 -0
- algo_cli/retrieval_algorithms.py +127 -0
- algo_cli/runtime_qos.py +236 -0
- algo_cli/runtime_services.py +320 -0
- algo_cli/session_commands.py +95 -0
- algo_cli/session_mode.py +113 -0
- algo_cli/skills.py +430 -0
- algo_cli/slash_dispatch.py +1265 -0
- algo_cli/small_context.py +206 -0
- algo_cli/spawn_budget.py +89 -0
- algo_cli/task_ledger.py +84 -0
- algo_cli/task_router.py +197 -0
- algo_cli/tool_context.py +94 -0
- algo_cli/tool_contract.py +99 -0
- algo_cli/tool_policy.py +357 -0
- algo_cli/tool_runtime.py +647 -0
- algo_cli/tools.py +3056 -0
- algo_cli/url_scheme.py +174 -0
- algo_cli/verify.py +154 -0
- algo_cli/version_manifest.py +178 -0
- algo_cli/vision_screenshot_verify.py +76 -0
- algo_cli/workspace_resolver.py +68 -0
- algo_cli/x_account.py +209 -0
- algo_cli/xai_auth.py +374 -0
- algo_cli/xai_client.py +600 -0
- algo_cli_runtime-0.14.0.dist-info/METADATA +369 -0
- algo_cli_runtime-0.14.0.dist-info/RECORD +237 -0
- algo_cli_runtime-0.14.0.dist-info/WHEEL +4 -0
- algo_cli_runtime-0.14.0.dist-info/entry_points.txt +3 -0
- algo_cli_runtime-0.14.0.dist-info/licenses/LICENSE +21 -0
- ollama_cli/__init__.py +67 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""B160, B172: Acrobat-derived model and hardware compatibility patterns.
|
|
2
|
+
|
|
3
|
+
- B160: Local Model Manifest Registry + Tensor Schema Gate
|
|
4
|
+
- B172: Hardware/Platform Compatibility Table
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# ── B160: Local Model Manifest Registry + Tensor Schema Gate ──────────
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class TensorSpec:
|
|
18
|
+
"""A tensor input/output specification."""
|
|
19
|
+
name: str
|
|
20
|
+
shape: list[int]
|
|
21
|
+
data_type: str # "float", "int64", etc.
|
|
22
|
+
required: bool = True
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class ModelComponent:
|
|
27
|
+
"""A component file for a model."""
|
|
28
|
+
name: str
|
|
29
|
+
path: str
|
|
30
|
+
encryption_key: str = "none"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class ModelTarget:
|
|
35
|
+
"""A runtime target for a model."""
|
|
36
|
+
runtime: str # "WinML", "onnxruntime", "ollama", etc.
|
|
37
|
+
components: list[ModelComponent] = field(default_factory=list)
|
|
38
|
+
inputs: list[TensorSpec] = field(default_factory=list)
|
|
39
|
+
outputs: list[TensorSpec] = field(default_factory=list)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class ModelManifest:
|
|
44
|
+
"""A local model manifest (B160)."""
|
|
45
|
+
id: str
|
|
46
|
+
name: str
|
|
47
|
+
author: str = ""
|
|
48
|
+
version: int = 1
|
|
49
|
+
targets: dict[str, ModelTarget] = field(default_factory=dict)
|
|
50
|
+
|
|
51
|
+
def get_target(self, runtime: str) -> ModelTarget | None:
|
|
52
|
+
return self.targets.get(runtime)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ModelSchemaGate:
|
|
56
|
+
"""Validates tensor schemas before model invocation (B160)."""
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def validate_input(target: ModelTarget, provided_inputs: dict[str, Any]) -> list[str]:
|
|
60
|
+
"""Validate provided inputs against the target's input specs.
|
|
61
|
+
Returns list of errors (empty = valid).
|
|
62
|
+
"""
|
|
63
|
+
errors: list[str] = []
|
|
64
|
+
for spec in target.inputs:
|
|
65
|
+
if spec.required and spec.name not in provided_inputs:
|
|
66
|
+
errors.append(f"missing required input: {spec.name}")
|
|
67
|
+
continue
|
|
68
|
+
if spec.name in provided_inputs:
|
|
69
|
+
value = provided_inputs[spec.name]
|
|
70
|
+
# Check shape if value has shape attribute
|
|
71
|
+
if hasattr(value, "shape"):
|
|
72
|
+
actual_shape = list(value.shape)
|
|
73
|
+
if len(actual_shape) != len(spec.shape):
|
|
74
|
+
errors.append(
|
|
75
|
+
f"shape mismatch for {spec.name}: expected {spec.shape}, got {actual_shape}"
|
|
76
|
+
)
|
|
77
|
+
return errors
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def validate_runtime(target: ModelTarget, available_runtimes: set[str]) -> bool:
|
|
81
|
+
"""Check if the target's runtime is available."""
|
|
82
|
+
return target.runtime in available_runtimes
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class ModelManifestRegistry:
|
|
86
|
+
"""Registry of local model manifests (B160)."""
|
|
87
|
+
|
|
88
|
+
def __init__(self) -> None:
|
|
89
|
+
self._manifests: dict[str, ModelManifest] = {}
|
|
90
|
+
|
|
91
|
+
def register(self, manifest: ModelManifest) -> None:
|
|
92
|
+
self._manifests[manifest.id] = manifest
|
|
93
|
+
|
|
94
|
+
def get(self, model_id: str) -> ModelManifest | None:
|
|
95
|
+
return self._manifests.get(model_id)
|
|
96
|
+
|
|
97
|
+
def load_check(
|
|
98
|
+
self, model_id: str, runtime: str, existing_files: set[str], available_runtimes: set[str] | None = None
|
|
99
|
+
) -> tuple[bool, list[str]]:
|
|
100
|
+
"""Check if a model can be loaded. Returns (can_load, errors)."""
|
|
101
|
+
manifest = self._manifests.get(model_id)
|
|
102
|
+
if not manifest:
|
|
103
|
+
return False, [f"unknown model: {model_id}"]
|
|
104
|
+
target = manifest.get_target(runtime)
|
|
105
|
+
if not target:
|
|
106
|
+
return False, [f"runtime not supported: {runtime}"]
|
|
107
|
+
if available_runtimes is not None and not ModelSchemaGate.validate_runtime(target, available_runtimes):
|
|
108
|
+
return False, [f"runtime not available: {runtime}"]
|
|
109
|
+
errors: list[str] = []
|
|
110
|
+
for comp in target.components:
|
|
111
|
+
if comp.path not in existing_files:
|
|
112
|
+
errors.append(f"missing component file: {comp.path}")
|
|
113
|
+
if errors:
|
|
114
|
+
return False, errors
|
|
115
|
+
return True, []
|
|
116
|
+
|
|
117
|
+
def all_models(self) -> list[ModelManifest]:
|
|
118
|
+
return list(self._manifests.values())
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ── B172: Hardware/Platform Compatibility Table ────────────────────────
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@dataclass
|
|
125
|
+
class CompatEntry:
|
|
126
|
+
"""A single hardware compatibility entry (B172)."""
|
|
127
|
+
action: str # "opt_in", "opt_out", "restrict"
|
|
128
|
+
vendor_id: str = ""
|
|
129
|
+
driver: str = ""
|
|
130
|
+
device_name: str = ""
|
|
131
|
+
flags: str = ""
|
|
132
|
+
feature: str = "gpu" # which feature this entry controls
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@dataclass
|
|
136
|
+
class CompatDecision:
|
|
137
|
+
"""Result of a compatibility check."""
|
|
138
|
+
enabled: bool
|
|
139
|
+
reason: str = ""
|
|
140
|
+
entry_id: str = ""
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class HardwareCompatTable:
|
|
144
|
+
"""Hardware/platform compatibility table (B172)."""
|
|
145
|
+
|
|
146
|
+
def __init__(self) -> None:
|
|
147
|
+
self._entries: list[CompatEntry] = []
|
|
148
|
+
|
|
149
|
+
def add_entry(self, entry: CompatEntry) -> None:
|
|
150
|
+
self._entries.append(entry)
|
|
151
|
+
|
|
152
|
+
def check(self, vendor_id: str, driver: str = "", device_name: str = "", feature: str = "gpu") -> CompatDecision:
|
|
153
|
+
"""Check if a feature should be enabled for the given hardware."""
|
|
154
|
+
# Look for exact match first
|
|
155
|
+
for i, entry in enumerate(self._entries):
|
|
156
|
+
if entry.feature != feature:
|
|
157
|
+
continue
|
|
158
|
+
if entry.vendor_id and entry.vendor_id != vendor_id:
|
|
159
|
+
continue
|
|
160
|
+
if entry.driver and driver and entry.driver != driver:
|
|
161
|
+
continue
|
|
162
|
+
if entry.device_name and entry.device_name != device_name:
|
|
163
|
+
continue
|
|
164
|
+
if entry.action == "opt_in":
|
|
165
|
+
return CompatDecision(enabled=True, reason=f"opt_in by entry {i}", entry_id=str(i))
|
|
166
|
+
if entry.action == "opt_out":
|
|
167
|
+
return CompatDecision(enabled=False, reason=f"opt_out by entry {i}", entry_id=str(i))
|
|
168
|
+
if entry.action == "restrict":
|
|
169
|
+
return CompatDecision(enabled=False, reason=f"restricted by entry {i}", entry_id=str(i))
|
|
170
|
+
# Default: conservative opt-out for unknown hardware
|
|
171
|
+
return CompatDecision(enabled=False, reason="unknown hardware, conservative opt-out")
|
|
172
|
+
|
|
173
|
+
def all_entries(self) -> list[CompatEntry]:
|
|
174
|
+
return list(self._entries)
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def default_gpu_compat_table() -> HardwareCompatTable:
|
|
178
|
+
"""Create a default GPU compatibility table from Acrobat's AGMGPUOptIn.ini."""
|
|
179
|
+
table = HardwareCompatTable()
|
|
180
|
+
# Intel G965 Express - opt out
|
|
181
|
+
table.add_entry(CompatEntry(
|
|
182
|
+
action="opt_out", vendor_id="00008086", driver="igxprd32.dll",
|
|
183
|
+
device_name="G965 EXPRESS", feature="gpu",
|
|
184
|
+
))
|
|
185
|
+
# AMD Radeon - opt in
|
|
186
|
+
table.add_entry(CompatEntry(
|
|
187
|
+
action="opt_in", vendor_id="00001002", driver="atiumdag",
|
|
188
|
+
device_name="RADEON", feature="gpu",
|
|
189
|
+
))
|
|
190
|
+
# NVIDIA GeForce - opt in
|
|
191
|
+
table.add_entry(CompatEntry(
|
|
192
|
+
action="opt_in", vendor_id="000010de", driver="nvd3dum",
|
|
193
|
+
device_name="GEFORCE", feature="gpu",
|
|
194
|
+
))
|
|
195
|
+
return table
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
"""B169, B174, B176: Acrobat-derived crash/format/pipeline patterns.
|
|
2
|
+
|
|
3
|
+
- B169: Structured Crash/Failure Reporter
|
|
4
|
+
- B174: Format Mapping/Transformation Tables
|
|
5
|
+
- B176: Specialized OCR/Document Pipeline Stages
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Any, Callable, Protocol
|
|
12
|
+
import time
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# ── B169: Structured Crash/Failure Reporter ───────────────────────────
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class CrashReport:
|
|
20
|
+
"""A structured crash report (B169)."""
|
|
21
|
+
process: str
|
|
22
|
+
version: str = ""
|
|
23
|
+
stack_trace: str = ""
|
|
24
|
+
context_snapshot: dict[str, Any] = field(default_factory=dict)
|
|
25
|
+
user_comment: str = ""
|
|
26
|
+
silent_send: bool = False
|
|
27
|
+
timestamp: float = field(default_factory=time.time)
|
|
28
|
+
tool_call_id: str = ""
|
|
29
|
+
model: str = ""
|
|
30
|
+
context_size: int = 0
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class CrashReportResult:
|
|
35
|
+
"""Result of processing a crash report."""
|
|
36
|
+
stored_locally: bool = False
|
|
37
|
+
uploaded: bool = False
|
|
38
|
+
display_variant: str = "medium" # "small", "medium", "large"
|
|
39
|
+
error: str = ""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class CrashReporter:
|
|
43
|
+
"""Structured crash/failure reporter (B169).
|
|
44
|
+
|
|
45
|
+
Tool-call crashes do not kill the agent loop. Reports are stored
|
|
46
|
+
locally and optionally uploaded with user consent.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
def __init__(self) -> None:
|
|
50
|
+
self._reports: list[CrashReport] = []
|
|
51
|
+
self._upload_enabled: bool = False
|
|
52
|
+
self._upload_url: str = ""
|
|
53
|
+
|
|
54
|
+
def set_upload_config(self, url: str, enabled: bool = False) -> None:
|
|
55
|
+
self._upload_url = url
|
|
56
|
+
self._upload_enabled = enabled
|
|
57
|
+
|
|
58
|
+
def report(self, crash: CrashReport, consent: bool = False) -> CrashReportResult:
|
|
59
|
+
"""Process a crash report."""
|
|
60
|
+
self._reports.append(crash)
|
|
61
|
+
result = CrashReportResult(stored_locally=True)
|
|
62
|
+
|
|
63
|
+
# Determine display variant based on context size
|
|
64
|
+
if crash.context_size > 100000:
|
|
65
|
+
result.display_variant = "large"
|
|
66
|
+
elif crash.context_size < 10000:
|
|
67
|
+
result.display_variant = "small"
|
|
68
|
+
else:
|
|
69
|
+
result.display_variant = "medium"
|
|
70
|
+
|
|
71
|
+
# Upload only with consent and if enabled
|
|
72
|
+
if consent and self._upload_enabled and self._upload_url:
|
|
73
|
+
result.uploaded = True
|
|
74
|
+
return result
|
|
75
|
+
|
|
76
|
+
def get_reports(self) -> list[CrashReport]:
|
|
77
|
+
return list(self._reports)
|
|
78
|
+
|
|
79
|
+
def report_count(self) -> int:
|
|
80
|
+
return len(self._reports)
|
|
81
|
+
|
|
82
|
+
def clear_reports(self) -> None:
|
|
83
|
+
self._reports.clear()
|
|
84
|
+
|
|
85
|
+
def latest_report(self) -> CrashReport | None:
|
|
86
|
+
return self._reports[-1] if self._reports else None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class AgentLoopCrashGuard:
|
|
90
|
+
"""Wraps tool calls so crashes don't kill the agent loop (B169)."""
|
|
91
|
+
|
|
92
|
+
def __init__(self, reporter: CrashReporter | None = None) -> None:
|
|
93
|
+
self._reporter = reporter or CrashReporter()
|
|
94
|
+
|
|
95
|
+
def safe_call(self, fn: Callable[..., Any], *args: Any, context: dict[str, Any] | None = None, **kwargs: Any) -> Any:
|
|
96
|
+
"""Call a function safely, catching exceptions and reporting them."""
|
|
97
|
+
try:
|
|
98
|
+
return fn(*args, **kwargs)
|
|
99
|
+
except Exception as e:
|
|
100
|
+
crash = CrashReport(
|
|
101
|
+
process="agent_loop",
|
|
102
|
+
stack_trace=str(e),
|
|
103
|
+
context_snapshot=context or {},
|
|
104
|
+
)
|
|
105
|
+
self._reporter.report(crash)
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def reporter(self) -> CrashReporter:
|
|
110
|
+
return self._reporter
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# ── B174: Format Mapping/Transformation Tables ────────────────────────
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@dataclass
|
|
117
|
+
class MappingRule:
|
|
118
|
+
"""A single mapping rule (B174)."""
|
|
119
|
+
source_element: str
|
|
120
|
+
target_element: str
|
|
121
|
+
transform: str = "passthrough" # "passthrough", "rename", "regex", "drop"
|
|
122
|
+
pattern: str = ""
|
|
123
|
+
replacement: str = ""
|
|
124
|
+
warnings: list[str] = field(default_factory=list)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@dataclass
|
|
128
|
+
class MappingResult:
|
|
129
|
+
"""Result of applying mapping rules."""
|
|
130
|
+
output: dict[str, Any] = field(default_factory=dict)
|
|
131
|
+
unmapped_elements: list[str] = field(default_factory=list)
|
|
132
|
+
warnings: list[str] = field(default_factory=list)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class FormatMappingTable:
|
|
136
|
+
"""Declarative format mapping/transformation table (B174)."""
|
|
137
|
+
|
|
138
|
+
def __init__(self, source_format: str = "pdf", target_format: str = "text") -> None:
|
|
139
|
+
self.source_format = source_format
|
|
140
|
+
self.target_format = target_format
|
|
141
|
+
self._rules: dict[str, MappingRule] = {}
|
|
142
|
+
|
|
143
|
+
def add_rule(self, rule: MappingRule) -> None:
|
|
144
|
+
self._rules[rule.source_element] = rule
|
|
145
|
+
|
|
146
|
+
def transform(self, content: dict[str, Any]) -> MappingResult:
|
|
147
|
+
"""Transform content using mapping rules."""
|
|
148
|
+
result = MappingResult()
|
|
149
|
+
for key, value in content.items():
|
|
150
|
+
rule = self._rules.get(key)
|
|
151
|
+
if not rule:
|
|
152
|
+
result.unmapped_elements.append(key)
|
|
153
|
+
result.output[key] = value # pass-through with warning
|
|
154
|
+
result.warnings.append(f"unmapped element: {key}")
|
|
155
|
+
continue
|
|
156
|
+
if rule.transform == "drop":
|
|
157
|
+
continue
|
|
158
|
+
elif rule.transform == "rename":
|
|
159
|
+
result.output[rule.target_element] = value
|
|
160
|
+
elif rule.transform == "regex" and rule.pattern:
|
|
161
|
+
import re
|
|
162
|
+
if isinstance(value, str):
|
|
163
|
+
result.output[rule.target_element] = re.sub(
|
|
164
|
+
rule.pattern, rule.replacement, value
|
|
165
|
+
)
|
|
166
|
+
else:
|
|
167
|
+
result.output[rule.target_element] = value
|
|
168
|
+
else:
|
|
169
|
+
result.output[rule.target_element] = value
|
|
170
|
+
result.warnings.extend(rule.warnings)
|
|
171
|
+
return result
|
|
172
|
+
|
|
173
|
+
def all_rules(self) -> list[MappingRule]:
|
|
174
|
+
return list(self._rules.values())
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
# ── B176: Specialized OCR/Document Pipeline Stages ────────────────────
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@dataclass
|
|
181
|
+
class PipelineStageResult:
|
|
182
|
+
"""Result of a single pipeline stage."""
|
|
183
|
+
stage_name: str
|
|
184
|
+
success: bool = True
|
|
185
|
+
output: Any = None
|
|
186
|
+
skipped: bool = False
|
|
187
|
+
error: str = ""
|
|
188
|
+
duration_ms: float = 0.0
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
@dataclass
|
|
192
|
+
class PipelineResult:
|
|
193
|
+
"""Result of running an entire pipeline."""
|
|
194
|
+
stages: list[PipelineStageResult] = field(default_factory=list)
|
|
195
|
+
completed: bool = False
|
|
196
|
+
output: Any = None
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def failed_stages(self) -> list[PipelineStageResult]:
|
|
200
|
+
return [s for s in self.stages if not s.success and not s.skipped]
|
|
201
|
+
|
|
202
|
+
@property
|
|
203
|
+
def skipped_stages(self) -> list[PipelineStageResult]:
|
|
204
|
+
return [s for s in self.stages if s.skipped]
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class PipelineStage(Protocol):
|
|
208
|
+
"""Protocol for pipeline stages (B176)."""
|
|
209
|
+
name: str
|
|
210
|
+
def process(self, input_data: Any, language: str = "ENU") -> PipelineStageResult: ...
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class SimpleStage:
|
|
214
|
+
"""A simple pipeline stage with a handler function."""
|
|
215
|
+
|
|
216
|
+
def __init__(self, name: str, handler: Callable[[Any, str], Any]) -> None:
|
|
217
|
+
self.name = name
|
|
218
|
+
self._handler = handler
|
|
219
|
+
|
|
220
|
+
def process(self, input_data: Any, language: str = "ENU") -> PipelineStageResult:
|
|
221
|
+
start = time.monotonic()
|
|
222
|
+
try:
|
|
223
|
+
output = self._handler(input_data, language)
|
|
224
|
+
return PipelineStageResult(
|
|
225
|
+
stage_name=self.name,
|
|
226
|
+
success=True,
|
|
227
|
+
output=output,
|
|
228
|
+
duration_ms=(time.monotonic() - start) * 1000,
|
|
229
|
+
)
|
|
230
|
+
except Exception as e:
|
|
231
|
+
return PipelineStageResult(
|
|
232
|
+
stage_name=self.name,
|
|
233
|
+
success=False,
|
|
234
|
+
error=str(e),
|
|
235
|
+
duration_ms=(time.monotonic() - start) * 1000,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class DocumentPipeline:
|
|
240
|
+
"""Multi-stage document processing pipeline (B176).
|
|
241
|
+
|
|
242
|
+
Each stage is independently replaceable. Stage failure degrades
|
|
243
|
+
gracefully instead of crashing the whole pipeline.
|
|
244
|
+
"""
|
|
245
|
+
|
|
246
|
+
def __init__(self) -> None:
|
|
247
|
+
self._stages: list[PipelineStage] = []
|
|
248
|
+
self._available_languages: set[str] = {"ENU"}
|
|
249
|
+
|
|
250
|
+
def add_stage(self, stage: PipelineStage) -> None:
|
|
251
|
+
self._stages.append(stage)
|
|
252
|
+
|
|
253
|
+
def register_language(self, lang: str) -> None:
|
|
254
|
+
self._available_languages.add(lang)
|
|
255
|
+
|
|
256
|
+
def run(self, input_data: Any, language: str = "ENU") -> PipelineResult:
|
|
257
|
+
"""Run the pipeline. Stages that fail are skipped with warnings."""
|
|
258
|
+
result = PipelineResult()
|
|
259
|
+
current_data = input_data
|
|
260
|
+
|
|
261
|
+
for stage in self._stages:
|
|
262
|
+
stage_result = stage.process(current_data, language)
|
|
263
|
+
result.stages.append(stage_result)
|
|
264
|
+
|
|
265
|
+
if stage_result.skipped:
|
|
266
|
+
continue
|
|
267
|
+
|
|
268
|
+
if not stage_result.success:
|
|
269
|
+
# Stage failed - degrade gracefully, continue with current data
|
|
270
|
+
continue
|
|
271
|
+
|
|
272
|
+
current_data = stage_result.output
|
|
273
|
+
|
|
274
|
+
result.output = current_data
|
|
275
|
+
result.completed = True
|
|
276
|
+
return result
|
|
277
|
+
|
|
278
|
+
def stage_names(self) -> list[str]:
|
|
279
|
+
return [s.name for s in self._stages]
|
|
280
|
+
|
|
281
|
+
def available_languages(self) -> list[str]:
|
|
282
|
+
return sorted(self._available_languages)
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def default_ocr_pipeline() -> DocumentPipeline:
|
|
286
|
+
"""Create a default OCR pipeline from Acrobat's PaperCapture iDRS15."""
|
|
287
|
+
pipeline = DocumentPipeline()
|
|
288
|
+
pipeline.register_language("ENU")
|
|
289
|
+
pipeline.register_language("JPN")
|
|
290
|
+
pipeline.register_language("ARA")
|
|
291
|
+
|
|
292
|
+
pipeline.add_stage(SimpleStage("preprocess", lambda data, lang: data))
|
|
293
|
+
pipeline.add_stage(SimpleStage("ocr", lambda data, lang: f"ocr:{data}"))
|
|
294
|
+
pipeline.add_stage(SimpleStage("document_output", lambda data, lang: f"out:{data}"))
|
|
295
|
+
return pipeline
|