Skip to content

Commit 8b764da

Browse files
committed
V2.1.0
1 parent 31bdb10 commit 8b764da

46 files changed

Lines changed: 10860 additions & 103 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,17 @@ venv.bak/
5151
secrets.json
5252
credentials.json
5353

54-
# Engram specific
54+
# Dhee specific
5555
# SQLite databases
5656
*.db
5757
*.db-journal
5858
*.db-wal
5959
*.db-shm
6060

6161
# History and cache directories
62-
.engram/
62+
.dhee/
6363
history.db
64-
engram_history.db
64+
dhee_history.db
6565
fadem_history.db
6666

6767
# Temporary test files
@@ -129,9 +129,9 @@ target/
129129
# Excluded from public repo — internal/experimental only
130130
# ============================================================
131131

132-
# Experimental engram sub-packages
132+
# Experimental sub-packages
133133
engram-bridge/
134-
engram-bus/
134+
dhee-bus/
135135
engram-enterprise/
136136
engram-failure/
137137
engram-heartbeat/

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,31 @@ All notable changes to this project will be documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
66

7+
## [2.1.0] - 2026-03-30 — Production Cognition
8+
9+
Dhee V2.1: All 10 cognition capabilities at production A-grade. Every self-improvement loop is closed and verified with 60 tests.
10+
11+
### Added — Production Cognition Systems
12+
13+
- **Episode System** (`dhee/core/episode.py`): First-class temporal unit of agent experience. Lifecycle: open→active→closed→archived→forgotten. Automatic boundary detection via time gap (>30min) and topic shift (Jaccard <20%). Utility-based selective forgetting with exponential recency decay (7-day half-life), access frequency, outcome value, and connection density scoring. Hard cap at 500 episodes/user.
14+
- **Task State** (`dhee/core/task_state.py`): Structured task tracking with goal/plan/progress/blockers/outcome. Full lifecycle: created→in_progress→blocked→completed/failed. Step-level tracking with `advance_step()`. Blocker management (soft/hard severity). Plan success rate analysis for policy learning.
15+
- **Policy Cases** (`dhee/core/policy.py`): Outcome-linked condition→action rules (not text reflections). Wilson score confidence at 95% interval. Laplace-smoothed win rate. Auto-promotion to VALIDATED (confidence≥0.5, win_rate≥0.6) and auto-deprecation (apply≥5, win_rate<0.4). Policy extraction from completed task patterns.
16+
- **Belief Tracking** (`dhee/core/belief.py`): Bayesian-inspired confidence updates (lr=0.15×evidence_strength). Contradiction detection via keyword Jaccard overlap >0.4 + negation patterns. Revision history with stability metric. Status lifecycle: proposed→held→challenged→revised|retracted. Auto-creation from factual assertions in stored memories.
17+
- **Trigger System** (`dhee/core/trigger.py`): 5 trigger types all returning `TriggerResult(fired, confidence, reason)`. Keyword (overlap scoring + required keywords), Time (after/before/recurring/window modes), Event (type + regex pattern), Composite (AND/OR/NOT with min/max confidence), Sequence (ordered events within time window, tightness-based confidence). Backwards-compatible bridge from legacy Intention format.
18+
- **Test Suite** (`tests/test_cognition_v3.py`): 60 tests across 10 classes covering all capabilities + full pipeline integration.
19+
20+
### Changed — Closed Self-Improvement Loops
21+
22+
- **Contrastive Pairs**: Upgraded from scaffolded to production. Retrieval-time integration in HyperContext, MaTTS scoring, DPO export for training.
23+
- **Heuristic Distillation**: Upgraded from scaffolded to production. Outcome validation loop closed — `reflect()` validates heuristics used in the session and updates confidence.
24+
- **Meta-Learning Gate**: Upgraded from scaffolded to production. Real evaluation via propose/evaluate/promote/rollback cycle verified.
25+
- **Progressive Training**: Upgraded from theoretical to production. Real data flow from Samskara → SFT → DPO → RL pipeline.
26+
- **Buddhi** (`dhee/core/buddhi.py`): HyperContext expanded with `episodes`, `task_states`, `policies`, `beliefs`. `reflect()` now creates contrastive pairs + distills heuristics + validates used heuristics + extracts policies + updates beliefs. `on_memory_stored()` auto-creates beliefs for factual assertions.
27+
- **DheePlugin** (`dhee/adapters/base.py`): `checkpoint()` handles episode closure, task state lifecycle, selective forgetting. System prompt renderer includes Proven Strategies, Established Beliefs, Active Tasks, Recent Experience. New convenience methods: `add_belief()`, `challenge_belief()`, `create_task()`, `advance_task()`.
28+
- **Version**: 2.0.0 → 2.1.0
29+
30+
---
31+
732
## [2.0.0] - 2026-03-30
833

934
Dhee V2: Self-Evolving Cognition Plugin. This release transforms Dhee from a memory layer into a **self-improving cognition plugin** that can make any agent — local or cloud, software or embodied — a HyperAgent that gets better with every interaction.

dhee-accel/Cargo.lock

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dhee/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
# Default: CoreMemory (lightest, zero-config)
3333
Memory = CoreMemory
3434

35-
__version__ = "2.0.0"
35+
__version__ = "2.1.0"
3636
__all__ = [
3737
# Tiered memory classes
3838
"CoreMemory",

dhee/adapters/base.py

Lines changed: 228 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,17 @@ def remember(
123123
result = self._engram.add(content, user_id=uid, infer=False, metadata=metadata)
124124

125125
response: Dict[str, Any] = {"stored": True}
126+
memory_id = None
126127
if isinstance(result, dict):
127128
rs = result.get("results", [])
128129
if rs:
129-
response["id"] = rs[0].get("id")
130+
memory_id = rs[0].get("id")
131+
response["id"] = memory_id
130132

131-
# Buddhi: detect intentions in the content
132-
intention = self._buddhi.on_memory_stored(content=content, user_id=uid)
133+
# Buddhi: detect intentions, record episode event, create beliefs
134+
intention = self._buddhi.on_memory_stored(
135+
content=content, user_id=uid, memory_id=memory_id,
136+
)
133137
if intention:
134138
response["detected_intention"] = intention.to_dict()
135139

@@ -196,6 +200,12 @@ def checkpoint(
196200
repo: Optional[str] = None,
197201
user_id: Optional[str] = None,
198202
agent_id: str = "dhee",
203+
# Structured task state (Phase 3)
204+
goal: Optional[str] = None,
205+
plan: Optional[List[str]] = None,
206+
plan_rationale: Optional[str] = None,
207+
blockers: Optional[List[str]] = None,
208+
outcome_evidence: Optional[List[str]] = None,
199209
) -> Dict[str, Any]:
200210
"""Save session state. Where the cognition happens.
201211
@@ -204,6 +214,9 @@ def checkpoint(
204214
3. Outcome recording → performance tracking
205215
4. Insight synthesis → transferable learnings
206216
5. Intention storage → prospective memory
217+
6. Episode closure → temporal experience unit
218+
7. Task state update → structured progress tracking
219+
8. Selective forgetting → utility-based cleanup
207220
"""
208221
uid = user_id or self._user_id
209222
result: Dict[str, Any] = {}
@@ -262,6 +275,73 @@ def checkpoint(
262275
)
263276
result["intention_stored"] = intention.to_dict()
264277

278+
# 6. Episode closure
279+
try:
280+
ep_store = self._buddhi._get_episode_store()
281+
ep_store.record_event(
282+
user_id=uid,
283+
event_type="checkpoint",
284+
content=summary[:500],
285+
metadata={"status": status, "outcome_score": outcome_score},
286+
)
287+
if status == "completed":
288+
episode = ep_store.end_episode(uid, outcome_score, summary)
289+
if episode:
290+
result["episode_closed"] = episode.id
291+
except Exception:
292+
pass
293+
294+
# 7. Task state update
295+
try:
296+
ts_store = self._buddhi._get_task_state_store()
297+
active_task = ts_store.get_active_task(uid)
298+
299+
if goal or plan:
300+
# Create or update task state
301+
if not active_task or active_task.goal != (goal or active_task.goal):
302+
active_task = ts_store.create_task(
303+
user_id=uid,
304+
goal=goal or summary,
305+
task_type=task_type or "general",
306+
plan=plan,
307+
plan_rationale=plan_rationale,
308+
)
309+
active_task.start()
310+
result["task_created"] = active_task.id
311+
elif plan:
312+
active_task.set_plan(plan, plan_rationale)
313+
314+
if active_task:
315+
# Add blockers
316+
if blockers:
317+
for b in blockers:
318+
active_task.add_blocker(b, severity="soft")
319+
320+
# Complete task if outcome provided
321+
if status == "completed" and outcome_score is not None:
322+
if outcome_score >= 0.5:
323+
active_task.complete(
324+
score=outcome_score,
325+
summary=summary,
326+
evidence=outcome_evidence,
327+
)
328+
else:
329+
active_task.fail(summary, evidence=outcome_evidence)
330+
result["task_completed"] = active_task.id
331+
332+
ts_store.update_task(active_task)
333+
except Exception:
334+
pass
335+
336+
# 8. Selective forgetting (periodic cleanup)
337+
try:
338+
ep_store = self._buddhi._get_episode_store()
339+
archived = ep_store.selective_forget(uid)
340+
if archived > 0:
341+
result["episodes_archived"] = archived
342+
except Exception:
343+
pass
344+
265345
return result
266346

267347
# ------------------------------------------------------------------
@@ -272,18 +352,32 @@ def session_start(
272352
self,
273353
task_description: Optional[str] = None,
274354
user_id: Optional[str] = None,
355+
task_type: Optional[str] = None,
275356
) -> str:
276357
"""Start a session and return a frozen system prompt block.
277358
278359
The system prompt contains the full HyperContext rendered as text.
279360
Inject it into your agent's system prompt at session start.
280361
The snapshot is frozen — writes during the session update storage
281362
but don't change this prompt, preserving LLM prefix caches.
363+
364+
Also begins an Episode and creates/resumes a TaskState.
282365
"""
283366
uid = user_id or self._user_id
284367
self._session_id = str(uuid.uuid4())
285368
self._session_start_time = time.time()
286369

370+
# Begin episode
371+
try:
372+
ep_store = self._buddhi._get_episode_store()
373+
ep_store.begin_episode(
374+
user_id=uid,
375+
task_description=task_description or "session",
376+
task_type=task_type or "general",
377+
)
378+
except Exception:
379+
pass
380+
287381
ctx = self.context(task_description=task_description, user_id=uid)
288382
return self._render_system_prompt(ctx, task_description)
289383

@@ -306,6 +400,81 @@ def session_end(
306400
self._session_start_time = None
307401
return result
308402

403+
# ------------------------------------------------------------------
404+
# Phase 3: Belief management
405+
# ------------------------------------------------------------------
406+
407+
def add_belief(
408+
self,
409+
claim: str,
410+
domain: str = "general",
411+
confidence: float = 0.5,
412+
user_id: Optional[str] = None,
413+
) -> Dict[str, Any]:
414+
"""Explicitly add a belief with confidence tracking."""
415+
uid = user_id or self._user_id
416+
b_store = self._buddhi._get_belief_store()
417+
belief, contradictions = b_store.add_belief(
418+
user_id=uid, claim=claim, domain=domain,
419+
confidence=confidence, source="user",
420+
)
421+
result = {"belief_id": belief.id, "confidence": belief.confidence}
422+
if contradictions:
423+
result["contradictions"] = [
424+
{"claim": c.claim[:200], "confidence": c.confidence}
425+
for c in contradictions
426+
]
427+
return result
428+
429+
def challenge_belief(
430+
self,
431+
belief_id: str,
432+
evidence: str,
433+
user_id: Optional[str] = None,
434+
) -> Optional[Dict[str, Any]]:
435+
"""Present contradicting evidence to a belief."""
436+
b_store = self._buddhi._get_belief_store()
437+
belief = b_store.challenge_belief(belief_id, evidence)
438+
if belief:
439+
return belief.to_compact()
440+
return None
441+
442+
# ------------------------------------------------------------------
443+
# Phase 3: Task state management
444+
# ------------------------------------------------------------------
445+
446+
def create_task(
447+
self,
448+
goal: str,
449+
task_type: str = "general",
450+
plan: Optional[List[str]] = None,
451+
user_id: Optional[str] = None,
452+
) -> Dict[str, Any]:
453+
"""Create a structured task with optional plan."""
454+
uid = user_id or self._user_id
455+
ts_store = self._buddhi._get_task_state_store()
456+
task = ts_store.create_task(
457+
user_id=uid, goal=goal, task_type=task_type, plan=plan,
458+
)
459+
task.start()
460+
ts_store.update_task(task)
461+
return task.to_compact()
462+
463+
def advance_task(
464+
self,
465+
note: Optional[str] = None,
466+
user_id: Optional[str] = None,
467+
) -> Optional[Dict[str, Any]]:
468+
"""Advance the active task to the next step."""
469+
uid = user_id or self._user_id
470+
ts_store = self._buddhi._get_task_state_store()
471+
task = ts_store.get_active_task(uid)
472+
if not task:
473+
return None
474+
task.advance_step(note)
475+
ts_store.update_task(task)
476+
return task.to_compact()
477+
309478
# ------------------------------------------------------------------
310479
# Trajectory recording (for skill mining + self-evolution)
311480
# ------------------------------------------------------------------
@@ -571,6 +740,62 @@ def _render_system_prompt(
571740
f"- [{h.get('level', 'domain')}] {h.get('heuristic', '')[:200]}"
572741
)
573742

743+
# Policies (Phase 3)
744+
policies = ctx.get("policies", [])
745+
if policies:
746+
parts.append("\n### Proven Strategies")
747+
for p in policies[:3]:
748+
parts.append(
749+
f"- **{p.get('name', 'policy')}** (win rate: {p.get('win_rate', 0):.0%}): "
750+
f"{p.get('do', '')[:150]}"
751+
)
752+
avoid = p.get("avoid", [])
753+
if avoid:
754+
parts.append(f" Avoid: {', '.join(avoid[:3])}")
755+
756+
# Beliefs (Phase 3)
757+
beliefs = ctx.get("beliefs", [])
758+
if beliefs:
759+
challenged = [b for b in beliefs if b.get("has_contradictions")]
760+
confident = [b for b in beliefs if not b.get("has_contradictions") and b.get("confidence", 0) >= 0.7]
761+
if confident:
762+
parts.append("\n### Established Beliefs")
763+
for b in confident[:5]:
764+
parts.append(f"- {b['claim']} (confidence: {b['confidence']:.0%})")
765+
if challenged:
766+
parts.append("\n### Beliefs Under Review")
767+
for b in challenged[:3]:
768+
parts.append(f"- {b['claim']} (confidence: {b['confidence']:.0%}, contradicted)")
769+
770+
# Task State (Phase 3)
771+
task_states = ctx.get("task_states", [])
772+
if task_states:
773+
active = [t for t in task_states if t.get("status") in ("in_progress", "blocked")]
774+
if active:
775+
parts.append("\n### Active Tasks")
776+
for t in active[:2]:
777+
parts.append(
778+
f"- **{t['goal'][:100]}** ({t['status']}, "
779+
f"progress: {t.get('progress', 0):.0%})"
780+
)
781+
if t.get("current_step"):
782+
parts.append(f" Current step: {t['current_step'][:100]}")
783+
if t.get("blockers"):
784+
parts.append(f" Blockers: {', '.join(t['blockers'][:2])}")
785+
786+
# Episodes (Phase 3)
787+
episodes = ctx.get("episodes", [])
788+
if episodes:
789+
relevant = [e for e in episodes if e.get("outcome") is not None]
790+
if relevant:
791+
parts.append("\n### Recent Experience")
792+
for e in relevant[:3]:
793+
outcome_str = f"score={e['outcome']:.2f}" if e['outcome'] is not None else "no outcome"
794+
parts.append(
795+
f"- {e.get('task', '')[:100]} ({outcome_str}, "
796+
f"{e.get('events', 0)} events, {e.get('duration_min', 0):.0f}min)"
797+
)
798+
574799
# Memories
575800
memories = ctx.get("memories", [])
576801
if memories:

0 commit comments

Comments
 (0)