capability-compiler 0.1.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.
- capability_compiler/__init__.py +76 -0
- capability_compiler/_version.py +8 -0
- capability_compiler/adapters/__init__.py +70 -0
- capability_compiler/adapters/base.py +166 -0
- capability_compiler/adapters/browser/__init__.py +7 -0
- capability_compiler/adapters/browser/adapter.py +474 -0
- capability_compiler/adapters/browser/aria.py +147 -0
- capability_compiler/adapters/browser/elements.py +185 -0
- capability_compiler/adapters/desktop/__init__.py +9 -0
- capability_compiler/adapters/desktop/base.py +90 -0
- capability_compiler/adapters/fake_adapter.py +242 -0
- capability_compiler/benchmark/__init__.py +42 -0
- capability_compiler/benchmark/data/capability_bench.json +81 -0
- capability_compiler/benchmark/data/seed.json +148 -0
- capability_compiler/benchmark/report.py +164 -0
- capability_compiler/benchmark/spec.py +249 -0
- capability_compiler/benchmark/suite.py +396 -0
- capability_compiler/cli/__init__.py +5 -0
- capability_compiler/cli/_common.py +135 -0
- capability_compiler/cli/_register.py +35 -0
- capability_compiler/cli/benchmark_cmd.py +284 -0
- capability_compiler/cli/config_cmds.py +230 -0
- capability_compiler/cli/execute_cmd.py +196 -0
- capability_compiler/cli/learn_cmd.py +134 -0
- capability_compiler/cli/main.py +184 -0
- capability_compiler/cli/registry_cmds.py +127 -0
- capability_compiler/cli/serve_cmd.py +124 -0
- capability_compiler/compiler.py +203 -0
- capability_compiler/config.py +282 -0
- capability_compiler/errors.py +348 -0
- capability_compiler/exploration/__init__.py +33 -0
- capability_compiler/exploration/effects.py +227 -0
- capability_compiler/exploration/engine.py +347 -0
- capability_compiler/exploration/semantics.py +257 -0
- capability_compiler/logging.py +228 -0
- capability_compiler/models/__init__.py +127 -0
- capability_compiler/models/action.py +216 -0
- capability_compiler/models/capability.py +389 -0
- capability_compiler/models/observation.py +281 -0
- capability_compiler/models/state.py +49 -0
- capability_compiler/models/transition.py +124 -0
- capability_compiler/models/verification.py +85 -0
- capability_compiler/models/versioning.py +77 -0
- capability_compiler/perception/__init__.py +22 -0
- capability_compiler/perception/pipeline.py +70 -0
- capability_compiler/perception/semantic.py +245 -0
- capability_compiler/providers/__init__.py +60 -0
- capability_compiler/providers/anthropic.py +132 -0
- capability_compiler/providers/base.py +185 -0
- capability_compiler/providers/http.py +216 -0
- capability_compiler/providers/mock.py +158 -0
- capability_compiler/providers/ollama.py +124 -0
- capability_compiler/providers/openai_compat.py +153 -0
- capability_compiler/recording/__init__.py +6 -0
- capability_compiler/recording/recorder.py +255 -0
- capability_compiler/recording/replay.py +174 -0
- capability_compiler/refinement/__init__.py +11 -0
- capability_compiler/refinement/engine.py +188 -0
- capability_compiler/refinement/repair.py +254 -0
- capability_compiler/registry/__init__.py +24 -0
- capability_compiler/registry/permissions.py +191 -0
- capability_compiler/registry/registry.py +251 -0
- capability_compiler/runtime/__init__.py +17 -0
- capability_compiler/runtime/assertions.py +114 -0
- capability_compiler/runtime/executor.py +422 -0
- capability_compiler/server/__init__.py +114 -0
- capability_compiler/server/auth.py +141 -0
- capability_compiler/server/executor_factory.py +75 -0
- capability_compiler/server/server.py +555 -0
- capability_compiler/server/tool_defs.py +98 -0
- capability_compiler/storage/__init__.py +7 -0
- capability_compiler/storage/base.py +62 -0
- capability_compiler/storage/filesystem.py +236 -0
- capability_compiler/storage/sqlite.py +284 -0
- capability_compiler/synthesis/__init__.py +20 -0
- capability_compiler/synthesis/engine.py +549 -0
- capability_compiler/synthesis/templating.py +84 -0
- capability_compiler/types.py +97 -0
- capability_compiler/verification/__init__.py +42 -0
- capability_compiler/verification/base.py +97 -0
- capability_compiler/verification/file_visual.py +224 -0
- capability_compiler/verification/runner.py +79 -0
- capability_compiler/verification/verifiers.py +292 -0
- capability_compiler-0.1.0.dist-info/METADATA +261 -0
- capability_compiler-0.1.0.dist-info/RECORD +88 -0
- capability_compiler-0.1.0.dist-info/WHEEL +4 -0
- capability_compiler-0.1.0.dist-info/entry_points.txt +2 -0
- capability_compiler-0.1.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Capability Compiler — turn any software into an API for AI.
|
|
2
|
+
|
|
3
|
+
Observe software, explore it, compile interaction trajectories into verified
|
|
4
|
+
reusable capabilities, and expose them to any LLM through Python, a CLI, and
|
|
5
|
+
MCP. Fully local-first: the default configuration runs offline.
|
|
6
|
+
|
|
7
|
+
Stable public API (import from the package root)::
|
|
8
|
+
|
|
9
|
+
from capability_compiler import Compiler, CompilerSettings
|
|
10
|
+
from capability_compiler import Capability, Observation, Action, Trajectory
|
|
11
|
+
from capability_compiler import MockProvider, load_settings
|
|
12
|
+
|
|
13
|
+
Submodule namespaces (``capability_compiler.models``, ``.adapters``,
|
|
14
|
+
``.providers``, ``.verification``, ``.storage``) are also public but may
|
|
15
|
+
grow faster than the root API; the root re-exports below are the
|
|
16
|
+
backward-compatible surface.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from capability_compiler._version import __version__
|
|
20
|
+
from capability_compiler.compiler import Compiler
|
|
21
|
+
from capability_compiler.config import CompilerSettings, load_settings, settings_to_toml
|
|
22
|
+
from capability_compiler.errors import CapabilityCompilerError, FailureCategory
|
|
23
|
+
from capability_compiler.exploration import (
|
|
24
|
+
ActionSemanticsEngine,
|
|
25
|
+
ExplorationEngine,
|
|
26
|
+
SemanticActionHypothesis,
|
|
27
|
+
)
|
|
28
|
+
from capability_compiler.models import (
|
|
29
|
+
Action,
|
|
30
|
+
ActionResult,
|
|
31
|
+
Capability,
|
|
32
|
+
Episode,
|
|
33
|
+
Observation,
|
|
34
|
+
SoftwareState,
|
|
35
|
+
StateFingerprint,
|
|
36
|
+
Trajectory,
|
|
37
|
+
Transition,
|
|
38
|
+
VerificationOutcome,
|
|
39
|
+
VerificationSpec,
|
|
40
|
+
)
|
|
41
|
+
from capability_compiler.perception import PerceptionPipeline, SemanticState, StateDiff
|
|
42
|
+
from capability_compiler.providers import MockProvider
|
|
43
|
+
from capability_compiler.registry import CapabilityRegistry, CapabilitySummary, Permission
|
|
44
|
+
from capability_compiler.types import canonical_json_hash
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
"Action",
|
|
48
|
+
"ActionResult",
|
|
49
|
+
"ActionSemanticsEngine",
|
|
50
|
+
"Capability",
|
|
51
|
+
"CapabilityCompilerError",
|
|
52
|
+
"CapabilityRegistry",
|
|
53
|
+
"CapabilitySummary",
|
|
54
|
+
"Compiler",
|
|
55
|
+
"CompilerSettings",
|
|
56
|
+
"Episode",
|
|
57
|
+
"ExplorationEngine",
|
|
58
|
+
"FailureCategory",
|
|
59
|
+
"MockProvider",
|
|
60
|
+
"Observation",
|
|
61
|
+
"PerceptionPipeline",
|
|
62
|
+
"Permission",
|
|
63
|
+
"SemanticActionHypothesis",
|
|
64
|
+
"SemanticState",
|
|
65
|
+
"SoftwareState",
|
|
66
|
+
"StateDiff",
|
|
67
|
+
"StateFingerprint",
|
|
68
|
+
"Trajectory",
|
|
69
|
+
"Transition",
|
|
70
|
+
"VerificationOutcome",
|
|
71
|
+
"VerificationSpec",
|
|
72
|
+
"__version__",
|
|
73
|
+
"canonical_json_hash",
|
|
74
|
+
"load_settings",
|
|
75
|
+
"settings_to_toml",
|
|
76
|
+
]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""Single source of truth for the package version.
|
|
2
|
+
|
|
3
|
+
Kept in its own module so ``pip install -e .`` environments can read it
|
|
4
|
+
without importing the whole package (pyproject reads it at build time via
|
|
5
|
+
hatchling's version hook — see ``[tool.hatch.version]``).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Environment adapters: protocol, registry, and built-in registration.
|
|
2
|
+
|
|
3
|
+
Importing this package registers every built-in adapter whose dependencies
|
|
4
|
+
are installed. The browser adapter requires the ``browser`` extra
|
|
5
|
+
(Playwright); without it, ``create_adapter("browser")`` fails with an
|
|
6
|
+
actionable error instead of an import crash.
|
|
7
|
+
|
|
8
|
+
Third parties register their own via
|
|
9
|
+
:func:`capability_compiler.adapters.base.register_adapter`.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from capability_compiler.adapters.base import EnvironmentAdapter as Adapter # alias
|
|
13
|
+
from capability_compiler.adapters.base import (
|
|
14
|
+
available_adapters,
|
|
15
|
+
create_adapter,
|
|
16
|
+
register_adapter,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _register_builtins() -> None:
|
|
21
|
+
# Fake adapter is dependency-free; always registered and used by tests,
|
|
22
|
+
# the CapabilityBench suite, and the default MCP executor.
|
|
23
|
+
from capability_compiler.adapters.fake_adapter import FakeAdapter
|
|
24
|
+
|
|
25
|
+
if "fake" not in available_adapters():
|
|
26
|
+
register_adapter(
|
|
27
|
+
"fake",
|
|
28
|
+
FakeAdapter,
|
|
29
|
+
description="Deterministic in-memory adapter for tests + benchmarks.",
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
# Desktop skeleton is dependency-free; always registered (fails loudly
|
|
33
|
+
# and honestly when used).
|
|
34
|
+
from capability_compiler.adapters.desktop import DesktopAdapterSkeleton
|
|
35
|
+
|
|
36
|
+
if "desktop" not in available_adapters():
|
|
37
|
+
register_adapter(
|
|
38
|
+
"desktop",
|
|
39
|
+
DesktopAdapterSkeleton,
|
|
40
|
+
description="desktop adapter skeleton (not yet functional — see docs)",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Browser adapter needs Playwright; register only when importable.
|
|
44
|
+
try:
|
|
45
|
+
from capability_compiler.adapters.browser import BrowserAdapter
|
|
46
|
+
|
|
47
|
+
if "browser" not in available_adapters():
|
|
48
|
+
register_adapter(
|
|
49
|
+
"browser",
|
|
50
|
+
BrowserAdapter,
|
|
51
|
+
description="Playwright browser adapter (chromium/firefox/webkit)",
|
|
52
|
+
)
|
|
53
|
+
except ImportError: # pragma: no cover - exercised only without extra
|
|
54
|
+
from capability_compiler.logging import get_logger
|
|
55
|
+
|
|
56
|
+
get_logger("adapters").debug(
|
|
57
|
+
"browser adapter unavailable (install capability-compiler[browser])"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
_register_builtins()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
__all__ = [
|
|
65
|
+
"Adapter",
|
|
66
|
+
"EnvironmentAdapter",
|
|
67
|
+
"available_adapters",
|
|
68
|
+
"create_adapter",
|
|
69
|
+
"register_adapter",
|
|
70
|
+
]
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""The environment adapter boundary — how Capability Compiler touches software.
|
|
2
|
+
|
|
3
|
+
An :class:`EnvironmentAdapter` wraps one class of target software (a browser,
|
|
4
|
+
a desktop application, a CLI) behind four verbs:
|
|
5
|
+
|
|
6
|
+
* :meth:`connect` / :meth:`disconnect` — lifecycle
|
|
7
|
+
* :meth:`observe` — produce a normalized :class:`~capability_compiler.models.Observation`
|
|
8
|
+
* :meth:`execute` — apply an :class:`~capability_compiler.models.Action`, return an
|
|
9
|
+
:class:`~capability_compiler.models.ActionResult`
|
|
10
|
+
* :meth:`reset` — return the environment to its start state (best effort)
|
|
11
|
+
|
|
12
|
+
Adapters are protocols (structural typing): any object with these methods
|
|
13
|
+
works — subclassing nothing is required. Implementations MUST:
|
|
14
|
+
|
|
15
|
+
1. Prefer semantic targets (ref/role/name) over coordinates when resolving
|
|
16
|
+
:class:`~capability_compiler.models.action.ActionTarget`.
|
|
17
|
+
2. Never trust action parameters as instructions (they are data).
|
|
18
|
+
3. Raise :class:`~capability_compiler.errors.AdapterError` subclasses, not
|
|
19
|
+
bare exceptions, so failures classify cleanly.
|
|
20
|
+
|
|
21
|
+
The adapter registry (:func:`register_adapter` / :func:`create_adapter`)
|
|
22
|
+
keeps adapters pluggable — third parties can ship their own.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
from __future__ import annotations
|
|
26
|
+
|
|
27
|
+
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
|
|
28
|
+
|
|
29
|
+
from capability_compiler.errors import UnknownAdapterError
|
|
30
|
+
from capability_compiler.logging import get_logger
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from capability_compiler.config import CompilerSettings
|
|
34
|
+
from capability_compiler.models import Action, ActionResult, Observation
|
|
35
|
+
from capability_compiler.models.action import ActionTarget
|
|
36
|
+
|
|
37
|
+
log = get_logger("adapters")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@runtime_checkable
|
|
41
|
+
class EnvironmentAdapter(Protocol):
|
|
42
|
+
"""Protocol every environment adapter implements."""
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def kind(self) -> str:
|
|
46
|
+
"""Short adapter kind name, e.g. ``browser`` (used as ``adapter_kind``)."""
|
|
47
|
+
...
|
|
48
|
+
|
|
49
|
+
@property
|
|
50
|
+
def connected(self) -> bool:
|
|
51
|
+
"""Whether the adapter currently holds a live environment session."""
|
|
52
|
+
...
|
|
53
|
+
|
|
54
|
+
async def connect(self) -> None:
|
|
55
|
+
"""Start the environment (launch browser, attach to app window).
|
|
56
|
+
|
|
57
|
+
Raises:
|
|
58
|
+
AdapterError: when the environment cannot be started/attached.
|
|
59
|
+
"""
|
|
60
|
+
...
|
|
61
|
+
|
|
62
|
+
async def disconnect(self) -> None:
|
|
63
|
+
"""Release the environment session (idempotent)."""
|
|
64
|
+
...
|
|
65
|
+
|
|
66
|
+
async def observe(self) -> Observation:
|
|
67
|
+
"""Capture a normalized observation of the current state.
|
|
68
|
+
|
|
69
|
+
Raises:
|
|
70
|
+
ObservationError: when the environment cannot be read.
|
|
71
|
+
"""
|
|
72
|
+
...
|
|
73
|
+
|
|
74
|
+
async def execute(self, action: Action) -> ActionResult:
|
|
75
|
+
"""Apply *action* and report the outcome (never raises for action-level
|
|
76
|
+
failures; transport/environment errors raise AdapterError)."""
|
|
77
|
+
...
|
|
78
|
+
|
|
79
|
+
async def reset(self) -> None:
|
|
80
|
+
"""Return the environment to its initial state (best effort)."""
|
|
81
|
+
...
|
|
82
|
+
|
|
83
|
+
def capabilities_description(self) -> list[str]:
|
|
84
|
+
"""Primitives this adapter supports, e.g. ``["click", "type", ...]``."""
|
|
85
|
+
...
|
|
86
|
+
|
|
87
|
+
async def resolve_target(self, target: ActionTarget) -> Any:
|
|
88
|
+
"""Resolve a semantic target to an adapter-native locator.
|
|
89
|
+
|
|
90
|
+
Used by verification/repair to re-find drifted elements. Adapters may
|
|
91
|
+
return any object meaningful to them (e.g. a Playwright Locator).
|
|
92
|
+
"""
|
|
93
|
+
...
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class AdapterInfo:
|
|
97
|
+
"""Registry entry describing an adapter factory."""
|
|
98
|
+
|
|
99
|
+
def __init__(self, kind: str, factory: Any, description: str = "") -> None:
|
|
100
|
+
self.kind = kind
|
|
101
|
+
self.factory = factory
|
|
102
|
+
self.description = description
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
_REGISTRY: dict[str, AdapterInfo] = {}
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def register_adapter(
|
|
109
|
+
kind: str,
|
|
110
|
+
factory: Any,
|
|
111
|
+
*,
|
|
112
|
+
description: str = "",
|
|
113
|
+
replace: bool = False,
|
|
114
|
+
) -> None:
|
|
115
|
+
"""Register an adapter factory under *kind* (e.g. ``"browser"``).
|
|
116
|
+
|
|
117
|
+
The factory is called as ``factory(settings)`` and must return an object
|
|
118
|
+
satisfying :class:`EnvironmentAdapter`.
|
|
119
|
+
"""
|
|
120
|
+
import re
|
|
121
|
+
|
|
122
|
+
if not re.fullmatch(r"[a-z][a-z0-9_]{0,30}", kind):
|
|
123
|
+
msg = f"adapter kind must be snake_case, got {kind!r}"
|
|
124
|
+
raise ValueError(msg)
|
|
125
|
+
if kind in _REGISTRY and not replace:
|
|
126
|
+
msg = f"adapter {kind!r} already registered"
|
|
127
|
+
raise ValueError(msg)
|
|
128
|
+
_REGISTRY[kind] = AdapterInfo(kind, factory, description)
|
|
129
|
+
log.debug("adapter.registered", extra={"extra_fields": {"kind": kind}})
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def create_adapter(kind: str, settings: CompilerSettings | None = None) -> Any:
|
|
133
|
+
"""Instantiate a registered adapter by kind.
|
|
134
|
+
|
|
135
|
+
Raises:
|
|
136
|
+
UnknownAdapterError: when *kind* was never registered.
|
|
137
|
+
"""
|
|
138
|
+
info = _REGISTRY.get(kind)
|
|
139
|
+
if info is None:
|
|
140
|
+
raise UnknownAdapterError(
|
|
141
|
+
f"no adapter registered for {kind!r}",
|
|
142
|
+
context={"available": sorted(_REGISTRY)},
|
|
143
|
+
suggestions=[
|
|
144
|
+
"install the adapter's extra (e.g. pip install capability-compiler[browser])",
|
|
145
|
+
"check spelling of the adapter kind",
|
|
146
|
+
],
|
|
147
|
+
)
|
|
148
|
+
if settings is None:
|
|
149
|
+
from capability_compiler.config import CompilerSettings
|
|
150
|
+
|
|
151
|
+
settings = CompilerSettings()
|
|
152
|
+
return info.factory(settings)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def available_adapters() -> list[str]:
|
|
156
|
+
"""Sorted kind names of all registered adapters."""
|
|
157
|
+
return sorted(_REGISTRY)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
__all__ = [
|
|
161
|
+
"AdapterInfo",
|
|
162
|
+
"EnvironmentAdapter",
|
|
163
|
+
"available_adapters",
|
|
164
|
+
"create_adapter",
|
|
165
|
+
"register_adapter",
|
|
166
|
+
]
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"""Browser adapter package (Playwright-based)."""
|
|
2
|
+
|
|
3
|
+
from capability_compiler.adapters.browser.adapter import BrowserAdapter, register, url_allowed
|
|
4
|
+
from capability_compiler.adapters.browser.aria import parse_aria_snapshot
|
|
5
|
+
from capability_compiler.adapters.browser.elements import parse_scan
|
|
6
|
+
|
|
7
|
+
__all__ = ["BrowserAdapter", "parse_aria_snapshot", "parse_scan", "register", "url_allowed"]
|