lisa-harness-runtime 0.1.0__tar.gz
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.
- lisa_harness_runtime-0.1.0/.gitignore +33 -0
- lisa_harness_runtime-0.1.0/.instructions.md +12 -0
- lisa_harness_runtime-0.1.0/PKG-INFO +23 -0
- lisa_harness_runtime-0.1.0/README.md +138 -0
- lisa_harness_runtime-0.1.0/pyproject.toml +47 -0
- lisa_harness_runtime-0.1.0/src/runtime/__init__.py +92 -0
- lisa_harness_runtime-0.1.0/src/runtime/approval/__init__.py +93 -0
- lisa_harness_runtime-0.1.0/src/runtime/approval/orchestration.py +1103 -0
- lisa_harness_runtime-0.1.0/src/runtime/approval/presentation.py +162 -0
- lisa_harness_runtime-0.1.0/src/runtime/approvals.py +179 -0
- lisa_harness_runtime-0.1.0/src/runtime/bootstrap.py +202 -0
- lisa_harness_runtime-0.1.0/src/runtime/callbacks.py +155 -0
- lisa_harness_runtime-0.1.0/src/runtime/capability_bindings.py +77 -0
- lisa_harness_runtime-0.1.0/src/runtime/code_artifacts.py +252 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/__init__.py +512 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/_lists.py +225 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/_log.py +146 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/_mcp.py +187 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/_models.py +451 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/_packs.py +966 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/_policy.py +454 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/_render.py +801 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/_routing.py +160 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/_simple.py +124 -0
- lisa_harness_runtime-0.1.0/src/runtime/commands/_slice.py +179 -0
- lisa_harness_runtime-0.1.0/src/runtime/config.py +657 -0
- lisa_harness_runtime-0.1.0/src/runtime/config_resolver.py +395 -0
- lisa_harness_runtime-0.1.0/src/runtime/content_roots.py +767 -0
- lisa_harness_runtime-0.1.0/src/runtime/context_assembly.py +861 -0
- lisa_harness_runtime-0.1.0/src/runtime/execution_policy.py +79 -0
- lisa_harness_runtime-0.1.0/src/runtime/gateway_provider.py +308 -0
- lisa_harness_runtime-0.1.0/src/runtime/handle_message.py +1540 -0
- lisa_harness_runtime-0.1.0/src/runtime/host_commands.py +175 -0
- lisa_harness_runtime-0.1.0/src/runtime/intake.py +412 -0
- lisa_harness_runtime-0.1.0/src/runtime/introspect.py +401 -0
- lisa_harness_runtime-0.1.0/src/runtime/lisa_config.py +448 -0
- lisa_harness_runtime-0.1.0/src/runtime/mcp_pool.py +1235 -0
- lisa_harness_runtime-0.1.0/src/runtime/mcp_servers.yaml +147 -0
- lisa_harness_runtime-0.1.0/src/runtime/memory_aliases.py +504 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/__init__.py +44 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/classify.py +243 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/discover.py +78 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/known_models.yaml +262 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/manifest.py +729 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/probes/__init__.py +21 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/probes/anthropic.py +172 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/probes/azure.py +258 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/probes/base.py +169 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/probes/google.py +271 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/probes/ollama.py +310 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/probes/openai.py +161 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/probes/openrouter.py +293 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/redact.py +132 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/tests/__init__.py +59 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/tests/test_commands.py +133 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/tests/test_discover.py +164 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/tests/test_enrichment.py +533 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/tests/test_manifest.py +753 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/tests/test_openrouter_probe.py +362 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/tests/test_probes.py +738 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/tests/test_redact.py +150 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/types.py +181 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_discovery/yaml_emit.py +115 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_manifest.py +40 -0
- lisa_harness_runtime-0.1.0/src/runtime/model_runtime.py +460 -0
- lisa_harness_runtime-0.1.0/src/runtime/operator_signal.py +51 -0
- lisa_harness_runtime-0.1.0/src/runtime/pack_autoinstall.py +285 -0
- lisa_harness_runtime-0.1.0/src/runtime/paths.py +439 -0
- lisa_harness_runtime-0.1.0/src/runtime/policy.py +929 -0
- lisa_harness_runtime-0.1.0/src/runtime/policy_service.py +168 -0
- lisa_harness_runtime-0.1.0/src/runtime/provider_endpoints.py +125 -0
- lisa_harness_runtime-0.1.0/src/runtime/providers.py +41 -0
- lisa_harness_runtime-0.1.0/src/runtime/recovery.py +130 -0
- lisa_harness_runtime-0.1.0/src/runtime/runtime.py +846 -0
- lisa_harness_runtime-0.1.0/src/runtime/runtime_paths.py +111 -0
- lisa_harness_runtime-0.1.0/src/runtime/services.py +69 -0
- lisa_harness_runtime-0.1.0/src/runtime/session_context.py +251 -0
- lisa_harness_runtime-0.1.0/src/runtime/session_from_resolver.py +325 -0
- lisa_harness_runtime-0.1.0/src/runtime/state_provider.py +255 -0
- lisa_harness_runtime-0.1.0/src/runtime/testing/__init__.py +11 -0
- lisa_harness_runtime-0.1.0/src/runtime/testing/runtime_factory.py +120 -0
- lisa_harness_runtime-0.1.0/src/runtime/thread/__init__.py +389 -0
- lisa_harness_runtime-0.1.0/src/runtime/thread/_excerpt.py +62 -0
- lisa_harness_runtime-0.1.0/src/runtime/thread/_replay.py +219 -0
- lisa_harness_runtime-0.1.0/src/runtime/thread/_results.py +53 -0
- lisa_harness_runtime-0.1.0/src/runtime/thread/_store.py +304 -0
- lisa_harness_runtime-0.1.0/src/runtime/thread_digest.py +525 -0
- lisa_harness_runtime-0.1.0/src/runtime/token_accounting.py +570 -0
- lisa_harness_runtime-0.1.0/src/runtime/turn_continuation.py +87 -0
- lisa_harness_runtime-0.1.0/src/runtime/turn_hooks/__init__.py +25 -0
- lisa_harness_runtime-0.1.0/src/runtime/turn_hooks/_auto_capture.py +150 -0
- lisa_harness_runtime-0.1.0/src/runtime/turn_hooks_builder.py +1693 -0
- lisa_harness_runtime-0.1.0/src/runtime/turn_logging.py +317 -0
- lisa_harness_runtime-0.1.0/src/runtime/types.py +78 -0
- lisa_harness_runtime-0.1.0/tests/conftest.py +181 -0
- lisa_harness_runtime-0.1.0/tests/test_approval_commands.py +1996 -0
- lisa_harness_runtime-0.1.0/tests/test_auto_capture_tier.py +145 -0
- lisa_harness_runtime-0.1.0/tests/test_auto_capture_wiring.py +198 -0
- lisa_harness_runtime-0.1.0/tests/test_bootstrap.py +171 -0
- lisa_harness_runtime-0.1.0/tests/test_capability_bindings.py +57 -0
- lisa_harness_runtime-0.1.0/tests/test_code_artifacts.py +906 -0
- lisa_harness_runtime-0.1.0/tests/test_commands_dispatch.py +369 -0
- lisa_harness_runtime-0.1.0/tests/test_commands_mcp.py +339 -0
- lisa_harness_runtime-0.1.0/tests/test_context_assembly.py +279 -0
- lisa_harness_runtime-0.1.0/tests/test_context_selection.py +229 -0
- lisa_harness_runtime-0.1.0/tests/test_copilot_auto_injection.py +163 -0
- lisa_harness_runtime-0.1.0/tests/test_core.py +795 -0
- lisa_harness_runtime-0.1.0/tests/test_core_services.py +2164 -0
- lisa_harness_runtime-0.1.0/tests/test_execution_policy.py +99 -0
- lisa_harness_runtime-0.1.0/tests/test_format_operation_error.py +81 -0
- lisa_harness_runtime-0.1.0/tests/test_gateway_provider.py +77 -0
- lisa_harness_runtime-0.1.0/tests/test_gateway_provider_env.py +465 -0
- lisa_harness_runtime-0.1.0/tests/test_host_command_result_yield.py +62 -0
- lisa_harness_runtime-0.1.0/tests/test_host_command_thread_entry.py +220 -0
- lisa_harness_runtime-0.1.0/tests/test_in_process_data_dir.py +203 -0
- lisa_harness_runtime-0.1.0/tests/test_intake.py +329 -0
- lisa_harness_runtime-0.1.0/tests/test_introspect.py +226 -0
- lisa_harness_runtime-0.1.0/tests/test_mcp_pool_env_propagation.py +190 -0
- lisa_harness_runtime-0.1.0/tests/test_memory_aliases.py +402 -0
- lisa_harness_runtime-0.1.0/tests/test_model_manifest.py +258 -0
- lisa_harness_runtime-0.1.0/tests/test_model_manifest_path.py +187 -0
- lisa_harness_runtime-0.1.0/tests/test_pack_autoinstall.py +272 -0
- lisa_harness_runtime-0.1.0/tests/test_pack_manager.py +2079 -0
- lisa_harness_runtime-0.1.0/tests/test_paths_framework_root.py +128 -0
- lisa_harness_runtime-0.1.0/tests/test_paths_venv_version.py +100 -0
- lisa_harness_runtime-0.1.0/tests/test_policy.py +689 -0
- lisa_harness_runtime-0.1.0/tests/test_policy_approvals.py +218 -0
- lisa_harness_runtime-0.1.0/tests/test_policy_command.py +326 -0
- lisa_harness_runtime-0.1.0/tests/test_post_turn_slice_outcome.py +91 -0
- lisa_harness_runtime-0.1.0/tests/test_profile_data_dir.py +142 -0
- lisa_harness_runtime-0.1.0/tests/test_provider_endpoints.py +174 -0
- lisa_harness_runtime-0.1.0/tests/test_recovery_provenance_conformance.py +353 -0
- lisa_harness_runtime-0.1.0/tests/test_recovery_service.py +143 -0
- lisa_harness_runtime-0.1.0/tests/test_replay_budget_wiring.py +196 -0
- lisa_harness_runtime-0.1.0/tests/test_runtime_aclose_cancel.py +100 -0
- lisa_harness_runtime-0.1.0/tests/test_sandbox_floor_wiring.py +200 -0
- lisa_harness_runtime-0.1.0/tests/test_session_budget_gate.py +31 -0
- lisa_harness_runtime-0.1.0/tests/test_session_context_ladder.py +104 -0
- lisa_harness_runtime-0.1.0/tests/test_session_from_resolver.py +634 -0
- lisa_harness_runtime-0.1.0/tests/test_session_plan_activation.py +186 -0
- lisa_harness_runtime-0.1.0/tests/test_slice_budget_config.py +89 -0
- lisa_harness_runtime-0.1.0/tests/test_slice_view_wiring.py +78 -0
- lisa_harness_runtime-0.1.0/tests/test_state_provider.py +236 -0
- lisa_harness_runtime-0.1.0/tests/test_thread.py +549 -0
- lisa_harness_runtime-0.1.0/tests/test_thread_digest.py +629 -0
- lisa_harness_runtime-0.1.0/tests/test_thread_replay.py +649 -0
- lisa_harness_runtime-0.1.0/tests/test_turn_completed_event.py +74 -0
- lisa_harness_runtime-0.1.0/tests/test_turn_hooks_delta_wiring.py +91 -0
- lisa_harness_runtime-0.1.0/tests/test_turn_logging.py +337 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
*.pyo
|
|
5
|
+
*.egg-info/
|
|
6
|
+
dist/
|
|
7
|
+
build/
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Virtual environments
|
|
11
|
+
.venv/
|
|
12
|
+
|
|
13
|
+
# IDE
|
|
14
|
+
.vscode/
|
|
15
|
+
|
|
16
|
+
# OS
|
|
17
|
+
.DS_Store
|
|
18
|
+
Thumbs.db
|
|
19
|
+
|
|
20
|
+
# Testing
|
|
21
|
+
.import_linter_cache/
|
|
22
|
+
.pytest_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
.mypy_cache/
|
|
25
|
+
.lisa-tmp/
|
|
26
|
+
coverage/
|
|
27
|
+
.coverage
|
|
28
|
+
.coverage.*
|
|
29
|
+
htmlcov/
|
|
30
|
+
|
|
31
|
+
# Outputs
|
|
32
|
+
artifacts/
|
|
33
|
+
.e2e/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: runtime — Shared Host Runtime
|
|
3
|
+
applyTo: "runtime/**/*.py"
|
|
4
|
+
description: Package-specific guidance for host runtime work.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Host runtime guidance
|
|
8
|
+
|
|
9
|
+
- Keep the host runtime transport-neutral. Do not introduce transport-specific rendering logic into the shared runtime layer.
|
|
10
|
+
- Preserve the existing separation between configuration, runtime state, and callback delivery.
|
|
11
|
+
- Keep lifecycle and MCP integration explicit so resources are started and closed in the correct event loop.
|
|
12
|
+
- Prefer focused modules and thin dispatch paths over growing one large handler.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: lisa-harness-runtime
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Transport-neutral host runtime for Lisa Harness hosts
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: cel-python>=0.5.0
|
|
7
|
+
Requires-Dist: httpx>=0.27.0
|
|
8
|
+
Requires-Dist: lisa-harness-kernel
|
|
9
|
+
Requires-Dist: lisa-harness-mcp-servers
|
|
10
|
+
Requires-Dist: lisa-harness-sdk
|
|
11
|
+
Requires-Dist: lisa-pack-core
|
|
12
|
+
Requires-Dist: lisa-pack-introspect
|
|
13
|
+
Requires-Dist: lisa-pack-memory
|
|
14
|
+
Requires-Dist: lisa-pack-recovery
|
|
15
|
+
Requires-Dist: openai>=1.30.0
|
|
16
|
+
Requires-Dist: pydantic>=2.7.0
|
|
17
|
+
Requires-Dist: pyyaml>=6.0
|
|
18
|
+
Requires-Dist: zstandard>=0.23.0
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
21
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
22
|
+
Requires-Dist: ruff>=0.8.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: types-pyyaml>=6.0; extra == 'dev'
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# Runtime
|
|
2
|
+
|
|
3
|
+
`lisa-harness-runtime` is an abstract runtime, i.e., host for the Lisa Harness kernel.
|
|
4
|
+
It offers a transport-neutral but otherwise near complete runtime implementation.
|
|
5
|
+
The separate [lisa-cli host](https://github.com/Lisa-Harness/lisa-cli) builds
|
|
6
|
+
on it to create a concrete running host.
|
|
7
|
+
|
|
8
|
+
See [host integration](../docs/HOST_INTEGRATION.md), [configuration](../docs/CONFIGURATION.md),
|
|
9
|
+
and the [documentation index](../docs/README.md) for maintained task guides.
|
|
10
|
+
|
|
11
|
+
## Design Philosophy
|
|
12
|
+
|
|
13
|
+
The host owns **runtime integration, process boundaries, and environment-specific wiring** — nothing more. Domain logic lives in the kernel or SDK; rendering lives in the transport.
|
|
14
|
+
|
|
15
|
+
Key principles:
|
|
16
|
+
|
|
17
|
+
- **Transport-neutral**: `runtime` never imports Rich, Typer, aiohttp, or any transport-specific package. Transports implement `TransportCallbacks` at their edge to receive stage updates, streamed text, final responses, debug context, and errors.
|
|
18
|
+
- **Typed composition root**: `HostConfig` is the frozen configuration; `HostRuntime` is its mutable counterpart, grouping responsibilities into five focused sub-objects (`paths`, `providers`, `resources`, `session`, `services`) so call sites name the domain they touch.
|
|
19
|
+
- **Single message entry point**: all transports call `handle_message(runtime, text, transport)` — host command dispatch, approval resume, model-turn routing, and turn execution live behind it.
|
|
20
|
+
- **Runtime invariants**: MCP resources start and close in the same task and event loop that runs turns. Housekeeping is slice-budgeted — no `cron`, `sched`, or wall-clock background schedulers.
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
from runtime import NullTransport, handle_message
|
|
26
|
+
from runtime.bootstrap import build_runtime
|
|
27
|
+
|
|
28
|
+
runtime = build_runtime(host_kind="headless", data_dir="./agent-data", user_slug="local-user")
|
|
29
|
+
try:
|
|
30
|
+
await runtime.start()
|
|
31
|
+
result = await handle_message(runtime, "/help", NullTransport())
|
|
32
|
+
finally:
|
|
33
|
+
await runtime.aclose()
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
This fragment runs inside one async task with a configured model manifest.
|
|
37
|
+
`HostRuntime(config)` alone does not perform the bootstrap/wiring sequence.
|
|
38
|
+
For a complete program and an observable production transport, see
|
|
39
|
+
[host integration](../docs/HOST_INTEGRATION.md).
|
|
40
|
+
|
|
41
|
+
## Module Map
|
|
42
|
+
|
|
43
|
+
### Composition Root
|
|
44
|
+
|
|
45
|
+
| Module | Responsibility |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `config.py` | `HostConfig` — typed, frozen configuration built once at startup from CLI args, env vars, or direct construction. Owns surface identity defaults and per-lane context budgets. |
|
|
48
|
+
| `runtime.py` | `HostRuntime` — the typed composition root replacing the old `_RUNTIME_STATE` dict. Owns `config`, `session_plan`, `execution_policy`, and the five sub-objects. `RuntimeResources` implements the async MCP lifecycle beside the object that owns its event loop. |
|
|
49
|
+
| `bootstrap.py` | Shared composition root: builds a `HostRuntime` from CLI args + env vars. |
|
|
50
|
+
| `handle_message.py` | Transport-neutral message dispatcher. Owns host command dispatch (`/help`, `/settings`, `/tokens`, `/debug`, `/consolidate`, `/intake`, `/pack`, `/models`, `/modes`, `/operations`, `/tools`), implicit approve/deny resume, and the model-turn pipeline. |
|
|
51
|
+
| `types.py` | Transport-neutral `Protocol` callable shapes that `HostRuntime` and `handle_message` depend on. |
|
|
52
|
+
| `runtime_paths.py` | `HostPaths` — frozen, pure value object projecting the host's derived filesystem layout (threads, state, logs, scratch). |
|
|
53
|
+
| `paths.py` | Framework root, venv root, and packs-venv resolution that works both in a repo checkout and a `uv tool install` environment. |
|
|
54
|
+
|
|
55
|
+
### Turn Wiring
|
|
56
|
+
|
|
57
|
+
| Module | Responsibility |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `turn_hooks_builder.py` | Builds the kernel's `TurnHooks` dataclass from a `HostRuntime`, replacing the old closure-based factory. |
|
|
60
|
+
| `turn_hooks/` | Turn-hook factory submodules — each owns one cohesive group of hooks (e.g. `_auto_capture.py`). |
|
|
61
|
+
| `context_assembly.py` | Transport-neutral system prompt and user context assembly. Pure / parameterized functions. |
|
|
62
|
+
| `token_accounting.py` | Token/latency ledger and session usage tracking. |
|
|
63
|
+
| `turn_logging.py` | Structured log-record assembly for the JSONL turn log and runtime event log. |
|
|
64
|
+
| `state_provider.py` | Transport-neutral state provider and slice compaction. |
|
|
65
|
+
| `operator_signal.py` | Typed `OperatorSignal` enum for host↔kernel communication, polled once per iteration. |
|
|
66
|
+
|
|
67
|
+
### Providers & Models
|
|
68
|
+
|
|
69
|
+
| Module | Responsibility |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `providers.py` | `ProviderRegistry` — lazily-populated per-provider SDK client cache (Azure OpenAI, Azure Responses, OpenAI, Anthropic HTTP, Ollama, OpenRouter). |
|
|
72
|
+
| `gateway_provider.py` | Host-side `ProviderGatewayProvider` — the kernel's single live completion path routes through it. |
|
|
73
|
+
| `provider_endpoints.py` | Single source of truth for each provider's direct base URL, used when no proxy route is active. |
|
|
74
|
+
| `model_runtime.py` | Model-runtime resolution helpers. |
|
|
75
|
+
| `model_manifest.py` | Host-side model manifest handling. |
|
|
76
|
+
| `model_discovery/` | Provider capability probing and manifest generation (`probes/` per provider, `classify.py`, `discover.py`, `yaml_emit.py`, `redact.py`, `enrichment`). Backs the `/models discover` command. |
|
|
77
|
+
|
|
78
|
+
### MCP Integration
|
|
79
|
+
|
|
80
|
+
| Module | Responsibility |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| `mcp_pool.py` | Compiles MCP server configurations from the host manifest (`mcp_servers.yaml`) and pack-contributed declarations. |
|
|
83
|
+
| `mcp_servers.yaml` | The host's first-party MCP server manifest (shipped as package data). |
|
|
84
|
+
| `memory_aliases.py` | Registers the generic `memory.*` synthetic aliases on a started MCP pool. |
|
|
85
|
+
|
|
86
|
+
### Approvals, Policy & Recovery
|
|
87
|
+
|
|
88
|
+
| Module | Responsibility |
|
|
89
|
+
| --- | --- |
|
|
90
|
+
| `approval/` | Transport-neutral exact-action approval flow: identity rebuild, affirmative resume, policy auto-continue, post-approval continuation (`presentation.py`, `orchestration.py`). |
|
|
91
|
+
| `approvals.py` | File-backed host implementation of the kernel approval service. |
|
|
92
|
+
| `policy.py` | Host-owned approval policy engine — the only place the "does this action need operator approval?" decision lives (mode dial, allow/ask/deny). |
|
|
93
|
+
| `policy_service.py` | `PolicyApprovalService` — decorates the durable file-backed service with the policy engine. |
|
|
94
|
+
| `execution_policy.py` | Host-side execution policy defaults and resolution. |
|
|
95
|
+
| `recovery.py` | File-backed host implementation of the kernel recovery service. |
|
|
96
|
+
|
|
97
|
+
### Session & Content
|
|
98
|
+
|
|
99
|
+
| Module | Responsibility |
|
|
100
|
+
| --- | --- |
|
|
101
|
+
| `session_context.py` | Resolves a session-context reference into a strict v2 `SessionPlan`. |
|
|
102
|
+
| `session_from_resolver.py` | Host-layer `from:`/`body:` directive resolver for session contexts. |
|
|
103
|
+
| `content_roots.py` | Content root and pack activation discovery (packs venv injection, installed-pack deduplication). |
|
|
104
|
+
| `pack_autoinstall.py` | Startup auto-install of session-required packs not importable at host boot. |
|
|
105
|
+
|
|
106
|
+
### Services, Intake & Introspection
|
|
107
|
+
|
|
108
|
+
| Module | Responsibility |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `services.py` | `HostServices` — the host's durable service handles (approval, recovery, etc.) reachable by any turn or command. |
|
|
111
|
+
| `intake.py` | Intake tick — one-shot signal collection, processing, and state write driven by a systemd timer or cron. |
|
|
112
|
+
| `introspect.py` | Live Python-level introspection: process memory, asyncio task count, MCP pool health, token usage trends. |
|
|
113
|
+
| `code_artifacts.py` | Atomic file-backed storage for pack-neutral WorkProducts. |
|
|
114
|
+
|
|
115
|
+
### Commands & Thread
|
|
116
|
+
|
|
117
|
+
| Module | Responsibility |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| `commands/` | Transport-neutral slash-command handlers that do not require the model (`_mcp.py`, `_packs.py`, `_models.py`, `_policy.py`, `_routing.py`, `_slice.py`, `_lists.py`, `_log.py`, `_render.py`, `_simple.py`). |
|
|
120
|
+
| `host_commands.py` | Dynamic registry of slash-command prefixes that are host control directives, not conversational content. |
|
|
121
|
+
| `thread/` | Per-user segmented thread store (`_store.py` — paths, segment index, zstd compression, sealing; `_excerpt.py`). |
|
|
122
|
+
| `testing/` | `runtime_factory.py` — builds a test `HostRuntime` with injected fakes and a seeded model manifest. |
|
|
123
|
+
|
|
124
|
+
## Data Directory Precedence
|
|
125
|
+
|
|
126
|
+
`HostConfig.from_env` resolves the data root in this order: CLI arg > `LISA_DATA_DIR` > `LISA_PROFILE` > `~/.lisa`. `LISA_PROFILE=name` resolves to `<base>/profiles/<name>` while the packs venv stays the base's. Export only one of the two variables.
|
|
127
|
+
|
|
128
|
+
## Testing
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
uv run pytest runtime/tests runtime/src/runtime/model_discovery/tests -m "not live" -q
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Run from the workspace root; see [testing](../docs/TESTING.md) for full gates.
|
|
135
|
+
|
|
136
|
+
Test through `HostConfig` and `HostRuntime` with injected fakes (via `runtime/testing/runtime_factory.py`) rather than monkeypatching module-level interfaces. A test `HostRuntime` needs a seeded model manifest with `mode_models`, not only a `models` list.
|
|
137
|
+
|
|
138
|
+
Architecture boundaries for this package are defined in [.github/instructions/architecture/runtime.instructions.md](../.github/instructions/architecture/runtime.instructions.md).
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[tool.hatch.build.targets.wheel]
|
|
6
|
+
packages = ["src/runtime"]
|
|
7
|
+
|
|
8
|
+
[project]
|
|
9
|
+
name = "lisa-harness-runtime"
|
|
10
|
+
version = "0.1.0"
|
|
11
|
+
description = "Transport-neutral host runtime for Lisa Harness hosts"
|
|
12
|
+
requires-python = ">=3.11"
|
|
13
|
+
dependencies = [
|
|
14
|
+
"lisa-harness-kernel",
|
|
15
|
+
"lisa-harness-sdk",
|
|
16
|
+
"lisa-harness-mcp-servers",
|
|
17
|
+
"lisa-pack-memory",
|
|
18
|
+
"lisa-pack-core",
|
|
19
|
+
"lisa-pack-introspect",
|
|
20
|
+
"lisa-pack-recovery",
|
|
21
|
+
"cel-python>=0.5.0",
|
|
22
|
+
"openai>=1.30.0",
|
|
23
|
+
"pyyaml>=6.0",
|
|
24
|
+
"httpx>=0.27.0",
|
|
25
|
+
"pydantic>=2.7.0",
|
|
26
|
+
"zstandard>=0.23.0",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
dev = [
|
|
31
|
+
"pytest>=8.0.0",
|
|
32
|
+
"pytest-asyncio>=0.23.0",
|
|
33
|
+
"ruff>=0.8.0",
|
|
34
|
+
"types-PyYAML>=6.0",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[tool.pytest.ini_options]
|
|
38
|
+
pythonpath = ["src"]
|
|
39
|
+
testpaths = ["tests"]
|
|
40
|
+
markers = [
|
|
41
|
+
"live: hits real external signal or provider APIs and prints a tester-visible summary",
|
|
42
|
+
"integration: multi-module in-process test; may require local services",
|
|
43
|
+
"eval: deterministic agent regression evals (no model calls, no I/O)",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# Ruff/pytest/vulture configuration lives in the workspace root pyproject.toml;
|
|
47
|
+
# member-level [tool.ruff] sections would shadow the root per-file-ignores.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""host — transport-neutral host runtime for Lisa Harness hosts.
|
|
2
|
+
|
|
3
|
+
This package owns the shared runtime that ``hosts/cli``
|
|
4
|
+
builds on. It wires the kernel's ``TurnHooks`` with
|
|
5
|
+
manifest-driven model resolution, MCP pool compilation, provider completion,
|
|
6
|
+
context assembly, thread persistence, and host-command dispatch — all without
|
|
7
|
+
importing Rich, Typer, aiohttp, or any transport-specific code.
|
|
8
|
+
|
|
9
|
+
Transport hosts inject a ``TransportCallbacks`` implementation to receive
|
|
10
|
+
stage updates, streamed text, final responses, debug context, and errors.
|
|
11
|
+
The runtime never writes to a console, browser, or editor directly.
|
|
12
|
+
|
|
13
|
+
Public surface::
|
|
14
|
+
|
|
15
|
+
from runtime import HostConfig, HostRuntime, TransportCallbacks, handle_message
|
|
16
|
+
|
|
17
|
+
config = HostConfig.from_env()
|
|
18
|
+
runtime = HostRuntime(config)
|
|
19
|
+
await runtime.start() # starts MCP pool in the host's event loop
|
|
20
|
+
result = await handle_message(runtime, "/search test", transport)
|
|
21
|
+
await runtime.aclose()
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from typing import TYPE_CHECKING, Any
|
|
27
|
+
|
|
28
|
+
from runtime.callbacks import DelegatingTransport, NullTransport, TransportCallbacks
|
|
29
|
+
from runtime.config import HostConfig, SliceConfig, StreamingConfig, default_data_dir
|
|
30
|
+
from runtime.types import (
|
|
31
|
+
CompletionProvider,
|
|
32
|
+
HostCommandResult,
|
|
33
|
+
ModelResolver,
|
|
34
|
+
ToolExecutor,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
# ``runtime.runtime`` is the heaviest submodule (pulls
|
|
39
|
+
# ``kernel.ipsar_fsm`` + ``openai`` via ``session_context``). It is
|
|
40
|
+
# resolved lazily by ``__getattr__`` below so importing
|
|
41
|
+
# ``HostConfig`` / ``callbacks`` / ``types`` from the package does not
|
|
42
|
+
# drag it in. The ``TYPE_CHECKING`` alias keeps these names visible to
|
|
43
|
+
# type checkers for annotation use without an eager runtime import.
|
|
44
|
+
from runtime.runtime import HostRuntime as HostRuntime
|
|
45
|
+
from runtime.runtime import TokenCounters as TokenCounters
|
|
46
|
+
from runtime.runtime import TurnContext as TurnContext
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"CompletionProvider",
|
|
50
|
+
"DelegatingTransport",
|
|
51
|
+
"HostCommandResult",
|
|
52
|
+
"HostConfig",
|
|
53
|
+
"HostRuntime",
|
|
54
|
+
"ModelResolver",
|
|
55
|
+
"NullTransport",
|
|
56
|
+
"SliceConfig",
|
|
57
|
+
"StreamingConfig",
|
|
58
|
+
"TokenCounters",
|
|
59
|
+
"ToolExecutor",
|
|
60
|
+
"TransportCallbacks",
|
|
61
|
+
"TurnContext",
|
|
62
|
+
"default_data_dir",
|
|
63
|
+
"handle_message",
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def __getattr__(name: str) -> Any: # PEP 562 lazy module attribute
|
|
68
|
+
"""Lazy-import the heavy runtime symbols on first attribute access.
|
|
69
|
+
|
|
70
|
+
``runtime.runtime`` is the heaviest submodule in the package (it
|
|
71
|
+
pulls in ``openai``, ``mcp``, and ``kernel.ipsar_fsm`` via
|
|
72
|
+
``session_context``); ``handle_message`` is the heaviest *function*
|
|
73
|
+
(the turn dispatcher). Deferring both keeps ``from runtime import
|
|
74
|
+
HostConfig`` / ``HostRuntime`` / ``TransportCallbacks`` (used by
|
|
75
|
+
``--version``, ``modes``, ``models``, ``verify``) from paying the
|
|
76
|
+
~2s runtime or ~3s turn-execution import cost. Direct submodule
|
|
77
|
+
imports (``from runtime.runtime import HostRuntime``, ``from
|
|
78
|
+
runtime.handle_message import handle_message``) are unaffected and
|
|
79
|
+
remain the fast path for code that actually needs the symbol.
|
|
80
|
+
"""
|
|
81
|
+
if name == "handle_message":
|
|
82
|
+
from runtime.handle_message import handle_message as _handle_message
|
|
83
|
+
|
|
84
|
+
globals()["handle_message"] = _handle_message
|
|
85
|
+
return _handle_message
|
|
86
|
+
if name in {"HostRuntime", "TokenCounters", "TurnContext"}:
|
|
87
|
+
from runtime import runtime as _runtime
|
|
88
|
+
|
|
89
|
+
value = getattr(_runtime, name)
|
|
90
|
+
globals()[name] = value
|
|
91
|
+
return value
|
|
92
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Host approval flow — transport-neutral approval and resume machinery.
|
|
2
|
+
|
|
3
|
+
This package owns the host side of the exact-action approval contract.
|
|
4
|
+
It was extracted from ``handle_message.py`` so the dispatcher shrinks back
|
|
5
|
+
to its documented three-phase pipeline (command dispatch → approval resume
|
|
6
|
+
→ model turn) instead of embedding a 600-line approval subsystem.
|
|
7
|
+
|
|
8
|
+
Dependency direction
|
|
9
|
+
--------------------
|
|
10
|
+
``approval`` ← ``handle_message.py`` / transport hosts (callers import
|
|
11
|
+
from approval; approval never imports handle_message — it receives
|
|
12
|
+
``route_model_turn`` as an injected callable)
|
|
13
|
+
|
|
14
|
+
``approval`` → ``runtime.approval.presentation``, ``runtime.runtime``,
|
|
15
|
+
``runtime.policy``, ``runtime.thread``, ``kernel.approval``,
|
|
16
|
+
``kernel.recovery`` (approval imports these; none of them import approval)
|
|
17
|
+
|
|
18
|
+
The two modules
|
|
19
|
+
---------------
|
|
20
|
+
- :mod:`runtime.approval.presentation` — pure, side-effect-free text and
|
|
21
|
+
payload rendering (:func:`redact_parameters`,
|
|
22
|
+
:func:`unresolved_approval_text`, ...).
|
|
23
|
+
- :mod:`runtime.approval.orchestration` — the durable-state flow: identity
|
|
24
|
+
rebuild, affirmative-resume detection, policy auto-continue, thread
|
|
25
|
+
record + synthesis turn, paired-recovery settlement, the typed core
|
|
26
|
+
:func:`decide_approval`, and its slash-grammar parse adapter
|
|
27
|
+
:func:`handle_approval_command`.
|
|
28
|
+
|
|
29
|
+
Public surface
|
|
30
|
+
--------------
|
|
31
|
+
- :func:`approval_identity`
|
|
32
|
+
- :func:`build_approval_data`
|
|
33
|
+
- :func:`decide_approval`
|
|
34
|
+
- :func:`handle_approval_command`
|
|
35
|
+
- :func:`is_affirmative_resume`
|
|
36
|
+
- :func:`maybe_auto_continue_approval`
|
|
37
|
+
- :func:`try_affirmative_approval_resume`
|
|
38
|
+
- :func:`settle_paired_recovery_record`
|
|
39
|
+
- :func:`redact_parameters`
|
|
40
|
+
- :func:`approval_result_text`
|
|
41
|
+
- :func:`same_session_scope`
|
|
42
|
+
- :func:`unresolved_approval_text`
|
|
43
|
+
- :func:`decision_state_text`
|
|
44
|
+
- :func:`approval_action_receipt`
|
|
45
|
+
|
|
46
|
+
.. note::
|
|
47
|
+
``decide_approval``, ``handle_approval_command``,
|
|
48
|
+
``try_affirmative_approval_resume``, and
|
|
49
|
+
``maybe_auto_continue_approval`` take a ``route_model_turn`` callable.
|
|
50
|
+
``runtime.handle_message`` injects its own ``_route_model_turn`` so the
|
|
51
|
+
post-approval synthesis turn reuses the single-turn machinery without
|
|
52
|
+
a circular import. ``decide_approval`` is the typed seam (values in, no
|
|
53
|
+
command string); ``handle_approval_command`` is its slash-grammar parse
|
|
54
|
+
adapter for the string dispatcher.
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
from __future__ import annotations
|
|
58
|
+
|
|
59
|
+
from runtime.approval.orchestration import (
|
|
60
|
+
approval_identity,
|
|
61
|
+
build_approval_data,
|
|
62
|
+
decide_approval,
|
|
63
|
+
handle_approval_command,
|
|
64
|
+
is_affirmative_resume,
|
|
65
|
+
maybe_auto_continue_approval,
|
|
66
|
+
settle_paired_recovery_record,
|
|
67
|
+
try_affirmative_approval_resume,
|
|
68
|
+
)
|
|
69
|
+
from runtime.approval.presentation import (
|
|
70
|
+
approval_action_receipt,
|
|
71
|
+
approval_result_text,
|
|
72
|
+
decision_state_text,
|
|
73
|
+
redact_parameters,
|
|
74
|
+
same_session_scope,
|
|
75
|
+
unresolved_approval_text,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
__all__ = [
|
|
79
|
+
"approval_action_receipt",
|
|
80
|
+
"approval_identity",
|
|
81
|
+
"approval_result_text",
|
|
82
|
+
"build_approval_data",
|
|
83
|
+
"decide_approval",
|
|
84
|
+
"decision_state_text",
|
|
85
|
+
"handle_approval_command",
|
|
86
|
+
"is_affirmative_resume",
|
|
87
|
+
"maybe_auto_continue_approval",
|
|
88
|
+
"redact_parameters",
|
|
89
|
+
"same_session_scope",
|
|
90
|
+
"settle_paired_recovery_record",
|
|
91
|
+
"try_affirmative_approval_resume",
|
|
92
|
+
"unresolved_approval_text",
|
|
93
|
+
]
|