unique-user-memory 2026.34.0.dev2__tar.gz → 2026.34.0.dev4__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.
- {unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/PKG-INFO +3 -3
- {unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/pyproject.toml +3 -3
- {unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/unique_user_memory/tests/test_user_memory.py +115 -1
- {unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/README.md +0 -0
- {unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/unique_user_memory/__init__.py +0 -0
- {unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/unique_user_memory/config.py +0 -0
- {unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/unique_user_memory/user_memory.py +0 -0
- {unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/unique_user_memory/user_memory_message_log.py +0 -0
- {unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/unique_user_memory/user_memory_postprocessor.py +0 -0
- {unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/unique_user_memory/user_memory_prompts.py +0 -0
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-user-memory
|
|
3
|
-
Version: 2026.34.0.
|
|
3
|
+
Version: 2026.34.0.dev4
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Fabian Schläpfer
|
|
6
6
|
Author-email: Fabian Schläpfer <fabian@unique.ch>
|
|
7
7
|
License: Proprietary
|
|
8
8
|
Requires-Dist: jinja2>=3.1.6
|
|
9
9
|
Requires-Dist: pydantic>=2.8.2
|
|
10
|
-
Requires-Dist: unique-sdk>=2026.34.0.
|
|
11
|
-
Requires-Dist: unique-toolkit>=2026.34.0.
|
|
10
|
+
Requires-Dist: unique-sdk>=2026.34.0.dev5,<2026.34.0rc0
|
|
11
|
+
Requires-Dist: unique-toolkit>=2026.34.0.dev11,<2026.34.0rc0
|
|
12
12
|
Requires-Python: >=3.12, <4
|
|
13
13
|
Description-Content-Type: text/markdown
|
|
14
14
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_user_memory"
|
|
3
|
-
version = "2026.34.0.
|
|
3
|
+
version = "2026.34.0.dev4"
|
|
4
4
|
description = ""
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Fabian Schläpfer", email = "fabian@unique.ch" },
|
|
@@ -11,8 +11,8 @@ requires-python = ">=3.12,<4"
|
|
|
11
11
|
dependencies = [
|
|
12
12
|
"jinja2>=3.1.6",
|
|
13
13
|
"pydantic>=2.8.2",
|
|
14
|
-
"unique-sdk>=2026.34.0.
|
|
15
|
-
"unique-toolkit>=2026.34.0.
|
|
14
|
+
"unique-sdk>=2026.34.0.dev5,<2026.34.0rc0",
|
|
15
|
+
"unique-toolkit>=2026.34.0.dev11,<2026.34.0rc0",
|
|
16
16
|
]
|
|
17
17
|
|
|
18
18
|
[dependency-groups]
|
|
@@ -2,13 +2,25 @@ import asyncio
|
|
|
2
2
|
from unittest.mock import AsyncMock, MagicMock
|
|
3
3
|
|
|
4
4
|
import pytest
|
|
5
|
+
from unique_toolkit.app.schemas import (
|
|
6
|
+
ChatEvent,
|
|
7
|
+
ChatEventAssistantMessage,
|
|
8
|
+
ChatEventPayload,
|
|
9
|
+
ChatEventUserMessage,
|
|
10
|
+
EventName,
|
|
11
|
+
)
|
|
5
12
|
from unique_toolkit.chat.schemas import MessageLogStatus
|
|
6
13
|
from unique_toolkit.language_model.default_language_model import (
|
|
7
14
|
DEFAULT_LANGUAGE_MODEL,
|
|
8
15
|
)
|
|
9
16
|
from unique_toolkit.language_model.infos import LanguageModelInfo
|
|
10
17
|
from unique_toolkit.language_model.invocation_stats import LanguageModelInvocationStats
|
|
11
|
-
from unique_toolkit.language_model.schemas import
|
|
18
|
+
from unique_toolkit.language_model.schemas import (
|
|
19
|
+
LanguageModelAssistantMessage,
|
|
20
|
+
LanguageModelCompletionChoice,
|
|
21
|
+
LanguageModelResponse,
|
|
22
|
+
LanguageModelTokenUsage,
|
|
23
|
+
)
|
|
12
24
|
|
|
13
25
|
from unique_user_memory.config import UserMemoryConfig
|
|
14
26
|
from unique_user_memory.user_memory import (
|
|
@@ -36,6 +48,45 @@ from unique_user_memory.user_memory_prompts import (
|
|
|
36
48
|
_TEST_LANGUAGE_MODEL = LanguageModelInfo.from_name(DEFAULT_LANGUAGE_MODEL)
|
|
37
49
|
|
|
38
50
|
|
|
51
|
+
def _chat_event() -> ChatEvent:
|
|
52
|
+
return ChatEvent(
|
|
53
|
+
id="event_1",
|
|
54
|
+
event=EventName.EXTERNAL_MODULE_CHOSEN,
|
|
55
|
+
user_id="user_1",
|
|
56
|
+
company_id="company_1",
|
|
57
|
+
payload=ChatEventPayload(
|
|
58
|
+
assistant_id="assistant_1",
|
|
59
|
+
chat_id="chat_1",
|
|
60
|
+
name="module",
|
|
61
|
+
description="module_description",
|
|
62
|
+
configuration={},
|
|
63
|
+
user_message=ChatEventUserMessage(
|
|
64
|
+
id="user_message_1",
|
|
65
|
+
text="Remember this",
|
|
66
|
+
created_at="2021-01-01T00:00:00Z",
|
|
67
|
+
language="EN",
|
|
68
|
+
original_text="Remember this",
|
|
69
|
+
),
|
|
70
|
+
assistant_message=ChatEventAssistantMessage(
|
|
71
|
+
id="assistant_message_1",
|
|
72
|
+
created_at="2021-01-01T00:00:00Z",
|
|
73
|
+
),
|
|
74
|
+
),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _completion_response(content: str) -> LanguageModelResponse:
|
|
79
|
+
return LanguageModelResponse(
|
|
80
|
+
choices=[
|
|
81
|
+
LanguageModelCompletionChoice(
|
|
82
|
+
index=0,
|
|
83
|
+
message=LanguageModelAssistantMessage(content=content),
|
|
84
|
+
finish_reason="stop",
|
|
85
|
+
)
|
|
86
|
+
]
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
39
90
|
def test_memory_profile_keeps_follow_up_tasks_but_excludes_open_questions() -> None:
|
|
40
91
|
profile = empty_profile("user_1")
|
|
41
92
|
consolidation_prompt = consolidation_system_prompt(2000)
|
|
@@ -223,6 +274,69 @@ async def test_condense_user_memory_accepts_frontmatter_output(
|
|
|
223
274
|
assert result == condensed
|
|
224
275
|
|
|
225
276
|
|
|
277
|
+
@pytest.mark.ai
|
|
278
|
+
@pytest.mark.asyncio
|
|
279
|
+
async def test_user_memory_llm_paths_forward_event_attribution(
|
|
280
|
+
monkeypatch: pytest.MonkeyPatch,
|
|
281
|
+
) -> None:
|
|
282
|
+
"""Purpose: Verify gate, rewrite, and condense use event-attributed completions.
|
|
283
|
+
Why this matters: Every user-memory ModelUsage row must link to its chat.
|
|
284
|
+
Setup summary: Exercise all shared service paths and inspect toolkit calls.
|
|
285
|
+
"""
|
|
286
|
+
rewritten = "# User Memory\n\n## Identity\n- Prefers concise answers"
|
|
287
|
+
condensed = "# User Memory\n\n## Identity\n- Concise"
|
|
288
|
+
complete_async = AsyncMock(
|
|
289
|
+
side_effect=[
|
|
290
|
+
_completion_response("UPDATE"),
|
|
291
|
+
_completion_response(rewritten),
|
|
292
|
+
_completion_response(condensed),
|
|
293
|
+
]
|
|
294
|
+
)
|
|
295
|
+
monkeypatch.setattr(
|
|
296
|
+
"unique_toolkit.language_model.service.complete_async",
|
|
297
|
+
complete_async,
|
|
298
|
+
)
|
|
299
|
+
event = _chat_event()
|
|
300
|
+
logger = MagicMock()
|
|
301
|
+
|
|
302
|
+
gate_result = await should_consolidate_memory(
|
|
303
|
+
current_memory=empty_profile("user_1"),
|
|
304
|
+
user_id="user_1",
|
|
305
|
+
user_message="Remember concise answers",
|
|
306
|
+
assistant_message="Noted",
|
|
307
|
+
language_model=_TEST_LANGUAGE_MODEL,
|
|
308
|
+
event=event,
|
|
309
|
+
logger=logger,
|
|
310
|
+
)
|
|
311
|
+
rewrite_result = await consolidate_user_memory(
|
|
312
|
+
current_memory=empty_profile("user_1"),
|
|
313
|
+
user_id="user_1",
|
|
314
|
+
user_message="Remember concise answers",
|
|
315
|
+
assistant_message="Noted",
|
|
316
|
+
config=UserMemoryConfig(consolidation_gate_enabled=False),
|
|
317
|
+
language_model=_TEST_LANGUAGE_MODEL,
|
|
318
|
+
event=event,
|
|
319
|
+
logger=logger,
|
|
320
|
+
)
|
|
321
|
+
condense_result = await condense_user_memory(
|
|
322
|
+
content=empty_profile("user_1"),
|
|
323
|
+
max_tokens=2000,
|
|
324
|
+
language_model=_TEST_LANGUAGE_MODEL,
|
|
325
|
+
event=event,
|
|
326
|
+
logger=logger,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
assert gate_result is True
|
|
330
|
+
assert rewritten in rewrite_result
|
|
331
|
+
assert condense_result == condensed
|
|
332
|
+
assert complete_async.await_count == 3
|
|
333
|
+
assert all(
|
|
334
|
+
call.kwargs["chat_id"] == "chat_1"
|
|
335
|
+
and call.kwargs["assistant_id"] == "assistant_1"
|
|
336
|
+
for call in complete_async.await_args_list
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
|
|
226
340
|
def test_count_tokens_uses_language_model_encoder() -> None:
|
|
227
341
|
language_model = MagicMock()
|
|
228
342
|
language_model.get_encoder.return_value = lambda content: content.split()
|
|
File without changes
|
|
File without changes
|
{unique_user_memory-2026.34.0.dev2 → unique_user_memory-2026.34.0.dev4}/unique_user_memory/config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|