aether-context 0.3.1__tar.gz → 0.5.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.
- {aether_context-0.3.1/aether_context.egg-info → aether_context-0.5.0}/PKG-INFO +29 -2
- {aether_context-0.3.1 → aether_context-0.5.0}/README.md +24 -1
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/__init__.py +1 -1
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/cli.py +7 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/config.py +2 -0
- aether_context-0.5.0/aether_context/contracts/__init__.py +534 -0
- aether_context-0.5.0/aether_context/contracts/schema-v1.json +2201 -0
- aether_context-0.5.0/aether_context/crypto.py +105 -0
- aether_context-0.5.0/aether_context/engine.py +1637 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/local_llm.py +90 -16
- aether_context-0.5.0/aether_context/policy/__init__.py +66 -0
- aether_context-0.5.0/aether_context/retention.py +647 -0
- aether_context-0.5.0/aether_context/scale.py +298 -0
- aether_context-0.5.0/aether_context/service/__init__.py +279 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/session.py +61 -8
- aether_context-0.5.0/aether_context/storage_v2/__init__.py +125 -0
- {aether_context-0.3.1 → aether_context-0.5.0/aether_context.egg-info}/PKG-INFO +29 -2
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context.egg-info/SOURCES.txt +14 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context.egg-info/entry_points.txt +1 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context.egg-info/requires.txt +5 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/pyproject.toml +6 -3
- aether_context-0.5.0/tests/test_context_ipc.py +65 -0
- aether_context-0.5.0/tests/test_hosted_context.py +423 -0
- aether_context-0.5.0/tests/test_local_llm_lmstudio.py +189 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_release_parity.py +16 -4
- aether_context-0.5.0/tests/test_retention_scale.py +1601 -0
- aether_context-0.5.0/tests/test_run_recall.py +93 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/LICENSE +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/NOTICE.md +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/_log.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/context_pool.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/encoder.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/errors.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/mpo.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/py.typed +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/quantize.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/slice_loader.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/tokenizer.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/ui.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context/witness.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context.egg-info/dependency_links.txt +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/aether_context.egg-info/top_level.txt +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/setup.cfg +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_aether_agent.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_commands.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_config.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_library.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_profile.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_profile_commands.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_runner.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_runner_define_command.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_runner_lock.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_slash.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_slash_agents_columns.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_slash_cmd.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agent_store.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_agents_view.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_api_eval.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_auth.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_brains.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_bridge.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_cli.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_cli_disk.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_cli_dispatch.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_cli_doctor.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_cli_setup.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_cli_surface.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_config.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_context_pool.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_encoder.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_end_to_end.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_errors.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_hardware.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_install_security.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_local_llm.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_local_llm_openai.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_moat_seal.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_mpo.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_multi_runner.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_ollama_ctl.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_ollama_integration.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_onboarding.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_pool_quantize.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_profiles.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_progress.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_protocol_lockstep.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_quantize.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_repl_agents.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_repl_multi.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_repl_preflight.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_run_agent_events_system.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_safety.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_session.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_session_fallback.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_slash.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_slash_agents.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_slash_custom_invoke.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_slash_ollama.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_slice_loader.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_smoke.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_tokenizer.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_toolparse.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_transport.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_ui.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_web_tools.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_witness.py +0 -0
- {aether_context-0.3.1 → aether_context-0.5.0}/tests/test_workflow_yaml.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aether-context
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Unlimited Context — virtual memory for an LLM's attention. Local-first, numpy-only core.
|
|
5
5
|
Author: Aether AI
|
|
6
6
|
Maintainer: Aether AI
|
|
@@ -34,6 +34,9 @@ Requires-Dist: transformers>=4.40; extra == "hf"
|
|
|
34
34
|
Requires-Dist: torch>=2.2; extra == "hf"
|
|
35
35
|
Provides-Extra: fast
|
|
36
36
|
Requires-Dist: hnswlib>=0.8; extra == "fast"
|
|
37
|
+
Provides-Extra: hosted
|
|
38
|
+
Requires-Dist: pydantic<3,>=2.10; extra == "hosted"
|
|
39
|
+
Requires-Dist: cryptography<51,>=44; extra == "hosted"
|
|
37
40
|
Provides-Extra: all
|
|
38
41
|
Requires-Dist: aether-context[fast,hf,llamacpp]; extra == "all"
|
|
39
42
|
Provides-Extra: dev
|
|
@@ -42,6 +45,7 @@ Requires-Dist: pytest-cov; extra == "dev"
|
|
|
42
45
|
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
43
46
|
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
44
47
|
Requires-Dist: pyyaml>=6; extra == "dev"
|
|
48
|
+
Requires-Dist: aether-context[hosted]; extra == "dev"
|
|
45
49
|
Dynamic: license-file
|
|
46
50
|
|
|
47
51
|
<div align="center">
|
|
@@ -86,6 +90,27 @@ aether-context setup
|
|
|
86
90
|
`setup` sizes the pool, checks for a local model, and verifies the engine end to end. It works
|
|
87
91
|
with no daemon, no network and no model pulled — the check runs against the built-in mock model.
|
|
88
92
|
|
|
93
|
+
Two `run` commands can use the same pool directory. The first task is stored as user-authored
|
|
94
|
+
memory; the second retrieves it before generation, even with the default `separate` pool mode:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
aether-context run "remember: the deploy key rotates on Fridays" --dir ./pool
|
|
98
|
+
aether-context run "when does the deploy key rotate?" --dir ./pool
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
With the default mock model, the status lines from a fresh pool are:
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
[pool 5 GB | slices 2/2275390 | reach 1.17B tok | hit 0% | recalled 0 | mode separate | index flat]
|
|
105
|
+
[pool 5 GB | slices 4/2275390 | reach 1.17B tok | hit 0% | recalled 1 | mode separate | index flat]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The mock prints synthetic text, so use a real local model for an answer to the question.
|
|
109
|
+
`recalled` counts slices supplied before generation; `hit` remains the pager's warm-cache rate.
|
|
110
|
+
Only user and tool memory is supplied by default. `run --include-model-memory` also supplies
|
|
111
|
+
model-authored spill. Retrieved context is capped at 20% of the model window, with room reserved
|
|
112
|
+
for the task and output; a slice too large to fit is skipped.
|
|
113
|
+
|
|
89
114
|
```python
|
|
90
115
|
from aether_context import Session
|
|
91
116
|
|
|
@@ -242,7 +267,9 @@ session its own pool and index — fully isolated and private, but you pay one i
|
|
|
242
267
|
RAM scales with `N × pool` (that's the last column above). `--pool-mode shared` pays for the index
|
|
243
268
|
**once**; each extra session adds only ~30 MB, so 50–70+ sessions fit and CPU becomes the limit
|
|
244
269
|
instead of memory. The trade-off is that sessions can see each other's context. Use shared for
|
|
245
|
-
related work on one project, separate for unrelated tasks.
|
|
270
|
+
related work on one project, separate for unrelated tasks. A `run` invocation is a special case:
|
|
271
|
+
it recalls prior user/tool facts from the same pool directory on reopen, even in separate mode.
|
|
272
|
+
Use different directories when those tasks must not share memory.
|
|
246
273
|
|
|
247
274
|
**How much building is that?** A ~128K window fills after well under an hour of active agent work,
|
|
248
275
|
then starts compacting and forgetting. Assuming a busy coding agent encodes ~300K–1M keep-worthy
|
|
@@ -40,6 +40,27 @@ aether-context setup
|
|
|
40
40
|
`setup` sizes the pool, checks for a local model, and verifies the engine end to end. It works
|
|
41
41
|
with no daemon, no network and no model pulled — the check runs against the built-in mock model.
|
|
42
42
|
|
|
43
|
+
Two `run` commands can use the same pool directory. The first task is stored as user-authored
|
|
44
|
+
memory; the second retrieves it before generation, even with the default `separate` pool mode:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
aether-context run "remember: the deploy key rotates on Fridays" --dir ./pool
|
|
48
|
+
aether-context run "when does the deploy key rotate?" --dir ./pool
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
With the default mock model, the status lines from a fresh pool are:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
[pool 5 GB | slices 2/2275390 | reach 1.17B tok | hit 0% | recalled 0 | mode separate | index flat]
|
|
55
|
+
[pool 5 GB | slices 4/2275390 | reach 1.17B tok | hit 0% | recalled 1 | mode separate | index flat]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The mock prints synthetic text, so use a real local model for an answer to the question.
|
|
59
|
+
`recalled` counts slices supplied before generation; `hit` remains the pager's warm-cache rate.
|
|
60
|
+
Only user and tool memory is supplied by default. `run --include-model-memory` also supplies
|
|
61
|
+
model-authored spill. Retrieved context is capped at 20% of the model window, with room reserved
|
|
62
|
+
for the task and output; a slice too large to fit is skipped.
|
|
63
|
+
|
|
43
64
|
```python
|
|
44
65
|
from aether_context import Session
|
|
45
66
|
|
|
@@ -196,7 +217,9 @@ session its own pool and index — fully isolated and private, but you pay one i
|
|
|
196
217
|
RAM scales with `N × pool` (that's the last column above). `--pool-mode shared` pays for the index
|
|
197
218
|
**once**; each extra session adds only ~30 MB, so 50–70+ sessions fit and CPU becomes the limit
|
|
198
219
|
instead of memory. The trade-off is that sessions can see each other's context. Use shared for
|
|
199
|
-
related work on one project, separate for unrelated tasks.
|
|
220
|
+
related work on one project, separate for unrelated tasks. A `run` invocation is a special case:
|
|
221
|
+
it recalls prior user/tool facts from the same pool directory on reopen, even in separate mode.
|
|
222
|
+
Use different directories when those tasks must not share memory.
|
|
200
223
|
|
|
201
224
|
**How much building is that?** A ~128K window fills after well under an hour of active agent work,
|
|
202
225
|
then starts compacting and forgetting. Assuming a busy coding agent encodes ~300K–1M keep-worthy
|
|
@@ -158,6 +158,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
158
158
|
)
|
|
159
159
|
p_run.add_argument("task", type=str, help="the task/prompt to run.")
|
|
160
160
|
_add_session_flags(p_run)
|
|
161
|
+
p_run.add_argument(
|
|
162
|
+
"--include-model-memory", action="store_true",
|
|
163
|
+
help="also supply model-authored spill as retrieved context (excluded by default).",
|
|
164
|
+
)
|
|
161
165
|
|
|
162
166
|
p_chat = subparsers.add_parser(
|
|
163
167
|
"chat", help="interactive REPL with slash-commands (/clear /new /status /quit ...)."
|
|
@@ -539,6 +543,7 @@ def _build_session(args: argparse.Namespace) -> Session:
|
|
|
539
543
|
pool_index=args.index,
|
|
540
544
|
pool_dir=pool_dir,
|
|
541
545
|
mpo_chain=getattr(args, "mpo_chain", True),
|
|
546
|
+
include_model_memory=getattr(args, "include_model_memory", False),
|
|
542
547
|
fallback_to_mock=True,
|
|
543
548
|
)
|
|
544
549
|
|
|
@@ -564,6 +569,7 @@ def _status_line(s: dict[str, Any]) -> str:
|
|
|
564
569
|
return (
|
|
565
570
|
f"[pool {s['pool_gb']} GB | slices {s['slices_used']}/{s['capacity']} | "
|
|
566
571
|
f"reach {int(s['reach_tokens']) / 1e9:.2f}B tok | hit {float(s['hit_rate']):.0%} | "
|
|
572
|
+
f"recalled {s['recalled']} | "
|
|
567
573
|
f"mode {s['pool_mode']} | index {s['index']}]"
|
|
568
574
|
)
|
|
569
575
|
|
|
@@ -885,6 +891,7 @@ def _status_lines(s: dict[str, Any]) -> list[str]:
|
|
|
885
891
|
f" slices: {s['slices_used']} / {s['capacity']}",
|
|
886
892
|
f" reach: {reach:,} tokens",
|
|
887
893
|
f" hit rate: {float(s['hit_rate']):.0%}",
|
|
894
|
+
f" recalled: {s['recalled']} slices (last run)",
|
|
888
895
|
f" resident RAM ~= {s['resident_ram_mb']} MB (estimate)",
|
|
889
896
|
f" pool-mode: {s['pool_mode']}",
|
|
890
897
|
f" index: {s['index']}",
|
|
@@ -174,12 +174,14 @@ class SessionConfig:
|
|
|
174
174
|
verbatim_fraction: float = VERBATIM_FRACTION
|
|
175
175
|
trigger_fraction: float = TRIGGER_FRACTION
|
|
176
176
|
target_fraction: float = TARGET_FRACTION
|
|
177
|
+
recall_fraction: float = 0.20
|
|
177
178
|
|
|
178
179
|
def __post_init__(self) -> None:
|
|
179
180
|
for name, value in (
|
|
180
181
|
("verbatim_fraction", self.verbatim_fraction),
|
|
181
182
|
("trigger_fraction", self.trigger_fraction),
|
|
182
183
|
("target_fraction", self.target_fraction),
|
|
184
|
+
("recall_fraction", self.recall_fraction),
|
|
183
185
|
):
|
|
184
186
|
if not (0.0 <= float(value) <= 1.0):
|
|
185
187
|
raise PoolBudgetError(
|