Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 25 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ Runtime memory is intentionally lightweight, but it is no longer passive storage
- Memory is injected into the brain prompt as trusted runtime context.
- It is mirrored in the right sidebar through `runtime_memory_update` and `runtime_session_memory_update` WebSocket events.
- Each L1/L2 update is captured as a session snapshot with an index, raw memory text, parsed key/value lines, and diff metadata.
- The UI can navigate previous snapshots and replay visual highlights for new or changed memory fields.
- Runtime-owned `active_memory` suffixes track creation/elapsed time and turns; they are stored and displayed, but stripped before L1 receives memory again.
- The UI can navigate previous snapshots, replay visual highlights for new or changed memory fields, and show full memory suffixes line-by-line on hover.
- Conversation activity and no-signal alerts can suppress overly soft default behavior when the exchange is clearly stuck.
- Truncated or obviously incomplete summarizer output is rejected so it does not overwrite the previous memory.

Expand All @@ -114,16 +115,13 @@ JIN memory is stored as plain `key: value` lines so it can be shown in the UI, i

### L1 memory snapshot (facts)

L1 is the live factual layer. It keeps the current state needed for the next answer: user request, active topic, latest user message, unresolved contracts, stored recall values, and the latest response gist. It is not a transcript and it should not infer long-term personality traits.
L1 is the live factual layer. It keeps the current state needed for the next answer: user request, active topic, latest user message, unresolved active contracts, recall values, and the latest response gist. It is not a transcript and it should not infer long-term personality traits.

```text
session status: Session shifted from an ASCII art request to a poetry/haiku side task while a recall contract remains open.
user_message: "у тебя хорошо получается"
current request: Acknowledge the compliment while preserving the active recall contract.
active topic: Word Recall Test (Secret word).
stored_memory: "Небо" (purpose: secret word for future recall test; status: pending)
countdown_contract: Recall the secret word "Небо"; created_at: 2026-06-13T18:31:57.142147; created_user_message_count: 1; count_from: 1; count_to: 4; due_user_message_count: 4; current: 5; remaining: 0; status: due; trigger: Ask the user to recall the secret word directly.
last_jin_response: Acknowledged the compliment and prompted the user to recall the stored word without revealing it.
user_message: "thanks"
last_jin_response: Acknowledged the user and kept the pending recall contract active.
primary_goal: Play a memory test game where JIN prompts the user to guess the secret word.
active_memory: Secret word: Sun [ purpose: Ask user to guess this exact word ] [ conditions: Do not reveal or change the word ] [ creation_time: 2026-06-20T10:00:00 ] [ creation_turn_number: 3 ] [ elapsed_time: 00:02:39 ] [ elapsed_turns: 2 ] [ status: pending ]
```

A rendered runtime snapshot also carries metadata used by the right-side timeline panel:
Expand All @@ -135,25 +133,25 @@ A rendered runtime snapshot also carries metadata used by the right-side timelin
"raw_memory": "session status: ...\nuser_message: ...",
"lines": [
{
"key": "stored_memory",
"value": "\"Небо\" (purpose: secret word for future recall test; status: pending)",
"key": "active_memory",
"value": "Secret word: Sun [ purpose: Ask user to guess this exact word ] [ conditions: Do not reveal or change the word ] [ creation_time: 2026-06-20T10:00:00 ] [ creation_turn_number: 3 ] [ elapsed_time: 00:02:39 ] [ elapsed_turns: 2 ] [ status: pending ]",
"key_status": "same",
"value_status": "same",
"key_change_ratio": 0.0,
"value_change_ratio": 0.0
}
],
"patch": {
"stored_memory": {
"active_memory": {
"status": "same",
"value": "\"Небо\" (purpose: secret word for future recall test; status: pending)"
"value": "Secret word: Sun [ purpose: Ask user to guess this exact word ] [ status: pending ]"
}
},
"total_diff": 87.3
}
```

The UI may show temporary trace strength such as `(trace: 0.50)` or inject `user_idle: 9s` into the displayed context. Those are runtime metadata signals, not durable memory facts.
`active_memory` lifecycle suffixes are owned by runtime, not L1. L1 sees the contract value and `[ status: ... ]`; runtime reattaches `[ creation_time ]`, `[ creation_turn_number ]`, `[ elapsed_time ]`, and `[ elapsed_turns ]` after each update. Memory lines may also have temporary trace strength such as `[ trace: 0.50 ]` or inject `user_idle: 9s` into the displayed context. Those are runtime metadata signals, not durable memory facts.

### L2 memory snapshot (patterns)

Expand Down Expand Up @@ -511,6 +509,19 @@ Runtime memory update:
}
```

Active memory collapse log:

```json
{
"type": "log",
"tag": "[ACTIVE_MEMORY]",
"message": "active_memory duplicate collapsed",
"details": "{\n \"stage\": \"after durable merge\",\n \"events\": [...],\n \"result_memory\": \"active_memory: ... [ status: pending, Reminder given in Turn 1 ]\"\n}",
"channel": "active_memory",
"active_memory_event": "collapse"
}
```

Runtime L1 diff update (incremental key-level change history):

```json
Expand Down
59 changes: 0 additions & 59 deletions clients/brain_client_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,25 +92,6 @@
)


COUNTDOWN_CONTRACT_RULES = (
"Runtime countdown_contract is active.\n"
"Treat countdown_contract and countdown_contract_N lines in RUNTIME_MEMORY "
"as active user-facing obligations from creation until completed or cancelled.\n"
"Countdown contracts are turn-based or time-based obligations; use bracket "
"suffixes in RUNTIME_MEMORY as trusted state. Do not require or trust status text.\n"
"For turn-based contracts, if [remaining: N] is greater than 0, do not execute "
"the trigger early; if [remaining: 0], execute [trigger] in this answer as an "
"actual direct user-facing action or question.\n"
"For time-based contracts, if runtime brought the contract into context and "
"[current_time] has reached or passed [due_at], execute [trigger] in this answer.\n"
"After executing the trigger, make the fulfillment explicit in your answer so L1 "
"can append [completed: jin] and deterministic cleanup can remove the contract.\n"
"For due recall triggers, ask the user for the remembered value without "
"revealing, quoting, paraphrasing, or restating the stored value first.\n"
)



def normalize_previous_think_section_title(
title: str,
) -> str:
Expand Down Expand Up @@ -1103,39 +1084,6 @@ def _contains_any_marker(
for marker in markers
)

def has_countdown_contract(
context=None,
) -> bool:

if context is None:
return False

runtime_memory = str(
getattr(
context,
"runtime_memory",
"",
)
or ""
)

for raw_line in runtime_memory.splitlines():
line = raw_line.strip()

while line.startswith("-"):
line = line[1:].strip()

key = line.split(
":",
1,
)[0].strip().casefold()

if re.fullmatch(r"countdown_contract(?:_\d+)?", key):
return True

return False


def has_memory_rule_request(
context=None,
) -> bool:
Expand Down Expand Up @@ -1255,13 +1203,6 @@ def build_conditional_prompt_rules(
""
]

if has_countdown_contract(
context
):
rules.append(
COUNTDOWN_CONTRACT_RULES
)

if has_loop_rule_signal(
context
):
Expand Down
3 changes: 1 addition & 2 deletions rules/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@
"- L1 for current session facts\n"
"- L2 for repeated patterns\n"
"- L3 for saved session continuity\n"
"\n"
"</Allocation>"
"\n"
"<github_link>https://github.com/makeitdouble/jin_core</github_link>"
"<runtime_github_link>https://github.com/makeitdouble/jin_core</runtime_github_link>"
"\n"
"</Core_Identity_Rules>"
"\n"
Expand Down
9 changes: 7 additions & 2 deletions rules/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,14 @@ def _format_action_guard_triggers(
)

RUNTIME = (
"A visible suffix like `[ relevance: 0.50 ]` marks how applicable this memory item is to the current runtime context."
"A visible suffix like `[ trace: 0.50 ]` marks how applicable this memory item is to the current runtime context."
"Use last_jin_response from trusted runtime memory as the primary anchor "
"for short, elliptical feedback about JIN's immediately previous output.\n"

"If any active_memory or active_memory_N line has pending for fulfill [ status: pending ], treat it as higher priority than active_topic, current_task, or the apparent current topic.\n"
"All active_memory suffix [ status: pending ] is chronological status log. Example of completed status: [ status: pending, asked once, completed ].\n"

"A pending active_memory contract remains behaviorally active across thanks, topic shifts, and casual requests until its status is completed, cancelled, or recalled.\n"
"For brief negative feedback, do not ask what exactly is wrong by default; "
"answer by challenging yourself and changing the previous output into a "
"concrete alternative, preferably from an unexpected angle.\n"
Expand Down Expand Up @@ -50,4 +55,4 @@ def _format_action_guard_triggers(
"Do not invent, reset, or update internal state values yourself. Trust only values from trusted runtime context.\n"
"Never mention timestamps, internal function names, or counters in chat unless the user explicitly asks.\n"
"\n"
)
)
Loading