memtrails 0.4.1__py3-none-any.whl

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.
Files changed (48) hide show
  1. memtrails/__init__.py +74 -0
  2. memtrails/_aio.py +23 -0
  3. memtrails/_fs.py +44 -0
  4. memtrails/_http.py +25 -0
  5. memtrails/_js.py +830 -0
  6. memtrails/core/__init__.py +1 -0
  7. memtrails/core/consolidate.py +977 -0
  8. memtrails/core/embedder.py +214 -0
  9. memtrails/core/episodes.py +78 -0
  10. memtrails/core/extract.py +665 -0
  11. memtrails/core/gather.py +209 -0
  12. memtrails/core/graph.py +239 -0
  13. memtrails/core/local_embedder.py +178 -0
  14. memtrails/core/model.py +105 -0
  15. memtrails/core/paths.py +15 -0
  16. memtrails/core/profiles.py +218 -0
  17. memtrails/core/qdrant_binary.py +359 -0
  18. memtrails/core/qdrant_client.py +421 -0
  19. memtrails/core/qdrant_process.py +457 -0
  20. memtrails/core/rebuild.py +201 -0
  21. memtrails/core/recall.py +352 -0
  22. memtrails/core/recall_log.py +142 -0
  23. memtrails/core/redact.py +176 -0
  24. memtrails/core/reranker.py +116 -0
  25. memtrails/core/room.py +93 -0
  26. memtrails/core/segment.py +57 -0
  27. memtrails/core/sleep.py +267 -0
  28. memtrails/core/store.py +424 -0
  29. memtrails/core/text.py +162 -0
  30. memtrails/core/words.py +187 -0
  31. memtrails/core/writer.py +291 -0
  32. memtrails/importers/__init__.py +60 -0
  33. memtrails/importers/files.py +333 -0
  34. memtrails/importers/git.py +193 -0
  35. memtrails/importers/jsonl.py +94 -0
  36. memtrails/importers/mbox.py +494 -0
  37. memtrails/importers/slack.py +236 -0
  38. memtrails/importers/text.py +651 -0
  39. memtrails/llm.py +192 -0
  40. memtrails/memory.py +794 -0
  41. memtrails/py.typed +0 -0
  42. memtrails/records.py +269 -0
  43. memtrails/tools/__init__.py +1 -0
  44. memtrails/tools/agent_tools.py +409 -0
  45. memtrails-0.4.1.dist-info/METADATA +237 -0
  46. memtrails-0.4.1.dist-info/RECORD +48 -0
  47. memtrails-0.4.1.dist-info/WHEEL +4 -0
  48. memtrails-0.4.1.dist-info/licenses/LICENSE +21 -0
memtrails/__init__.py ADDED
@@ -0,0 +1,74 @@
1
+ """
2
+ memtrails — retrieval and exploration for any text: e-mail, chat, notes, documents, news, commits, conversations.
3
+
4
+ add records, conversations, or a stream from an importer — searchable at once, no model asked
5
+ search dense + keyword, fused; reordered word by word on this machine; dates first when asked
6
+ room the best sentences of what was found, for a small context
7
+ open one item whole, with the records it was learned from
8
+ explore the concept graph from a topic or items to what search does not find
9
+ consolidate (with a language model) typed knowledge, dated observations, kept episodes
10
+ sleep (with a language model) merge, supersede, link, profiles
11
+ gather (with a language model) every instance a counting or listing question needs
12
+ tools memory_search / memory_open / memory_explore for an agent
13
+
14
+ A native port of the TypeScript library (npm ``memtrails``): the same algorithms, prompts and files.
15
+ """
16
+
17
+ from .core.embedder import EmbedRoute
18
+ from .core.gather import Gathered
19
+ from .core.model import MODEL_REPO, MODEL_REVISION, default_model_dir, ensure_model
20
+ from .core.paths import cache_dir
21
+ from .core.qdrant_binary import QDRANT_VERSION, ensure_qdrant
22
+ from .core.recall import Explored, RecalledItem, RecordRef
23
+ from .core.reranker import RerankRoute
24
+ from .core.room import sentence_room, sentence_spans
25
+ from .core.words import WORD_LIMIT, PackedWords, WordStore, WordVectors, max_sim, pack_words
26
+ from .llm import Ask, LlmRequest, LlmUsage, OpenAiAsk, openai_ask
27
+ from .memory import EmbeddingOptions, Memory, QdrantOptions, SearchOptions, open_memory
28
+ from .records import DEFAULT_COLLECTION, Conversation, MemoryRecord, record_uid, time_of
29
+ from .tools.agent_tools import AgentTool, build_agent_tools, search_text
30
+
31
+ __version__ = "0.4.1"
32
+
33
+ __all__ = [
34
+ "DEFAULT_COLLECTION",
35
+ "MODEL_REPO",
36
+ "MODEL_REVISION",
37
+ "QDRANT_VERSION",
38
+ "WORD_LIMIT",
39
+ "AgentTool",
40
+ "Ask",
41
+ "Conversation",
42
+ "EmbedRoute",
43
+ "EmbeddingOptions",
44
+ "Explored",
45
+ "Gathered",
46
+ "LlmRequest",
47
+ "LlmUsage",
48
+ "Memory",
49
+ "MemoryRecord",
50
+ "OpenAiAsk",
51
+ "PackedWords",
52
+ "QdrantOptions",
53
+ "RecalledItem",
54
+ "RecordRef",
55
+ "RerankRoute",
56
+ "SearchOptions",
57
+ "WordStore",
58
+ "WordVectors",
59
+ "__version__",
60
+ "build_agent_tools",
61
+ "cache_dir",
62
+ "default_model_dir",
63
+ "ensure_model",
64
+ "ensure_qdrant",
65
+ "max_sim",
66
+ "open_memory",
67
+ "openai_ask",
68
+ "pack_words",
69
+ "record_uid",
70
+ "search_text",
71
+ "sentence_room",
72
+ "sentence_spans",
73
+ "time_of",
74
+ ]
memtrails/_aio.py ADDED
@@ -0,0 +1,23 @@
1
+ """asyncio pieces the port needs on every Python it supports (3.10 has neither TaskGroup nor asyncio.timeout)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from collections.abc import Awaitable
7
+ from typing import TypeVar
8
+
9
+ T = TypeVar("T")
10
+
11
+
12
+ async def gather_or_cancel(*aws: Awaitable[T]) -> list[T]:
13
+ """``asyncio.gather``, but the first that raises cancels the others before it is raised, and they have ended when it
14
+ is: asks the model is paid for are not left running for an answer no one reads (a cancelled caller cancels them
15
+ too, as gather does)."""
16
+ tasks: list[asyncio.Future[T]] = [asyncio.ensure_future(a) for a in aws]
17
+ try:
18
+ return list(await asyncio.gather(*tasks))
19
+ except BaseException:
20
+ for t in tasks:
21
+ t.cancel()
22
+ await asyncio.gather(*tasks, return_exceptions=True)
23
+ raise
memtrails/_fs.py ADDED
@@ -0,0 +1,44 @@
1
+ """Writes that land whole or raise: ``os.write`` may write fewer bytes than it was given (a full disk, a signal), and a
2
+ short write left unnoticed tears a line, or leaves the offsets an index holds pointing past the file's end."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import errno
7
+ import os
8
+
9
+
10
+ def write_all(fd: int, data: bytes) -> None:
11
+ """Every byte of ``data`` to ``fd``, or OSError."""
12
+ view = memoryview(data)
13
+ while view:
14
+ n = os.write(fd, view)
15
+ if n <= 0:
16
+ raise OSError(errno.EIO, "nothing was written")
17
+ view = view[n:]
18
+
19
+
20
+ def append_all(path: str, data: bytes) -> None:
21
+ """``data`` appended to ``path`` (made private when it is new), whole — or OSError, and the file cut back to where
22
+ it ended before, so what is appended next starts on a line of its own."""
23
+ fd = os.open(path, os.O_WRONLY | os.O_APPEND | os.O_CREAT, 0o600)
24
+ try:
25
+ start = os.fstat(fd).st_size
26
+ try:
27
+ write_all(fd, data)
28
+ except OSError:
29
+ try:
30
+ os.ftruncate(fd, start)
31
+ except OSError:
32
+ pass # what was cut short stays: a load ends or drops a torn last line
33
+ raise
34
+ finally:
35
+ os.close(fd)
36
+
37
+
38
+ def write_file(path: str, data: bytes) -> None:
39
+ """``path`` replaced by ``data`` (private), whole, or OSError."""
40
+ fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
41
+ try:
42
+ write_all(fd, data)
43
+ finally:
44
+ os.close(fd)
memtrails/_http.py ADDED
@@ -0,0 +1,25 @@
1
+ """One HTTP client for everything a memory talks to (Qdrant, the embedding and rerank servers, the language model, the
2
+ downloads): the caller's, or one made for the call and closed after it when there is none. Never the environment's
3
+ proxies — memory's own Qdrant is on loopback, and a key meant for a server must reach that server."""
4
+
5
+ from __future__ import annotations
6
+
7
+ from collections.abc import AsyncIterator
8
+ from contextlib import asynccontextmanager
9
+
10
+ import httpx
11
+
12
+
13
+ def new_client() -> httpx.AsyncClient:
14
+ """The client a memory makes for itself when it is given none."""
15
+ return httpx.AsyncClient(trust_env=False, timeout=httpx.Timeout(30.0))
16
+
17
+
18
+ @asynccontextmanager
19
+ async def using(http: httpx.AsyncClient | None) -> AsyncIterator[httpx.AsyncClient]:
20
+ """``http`` when given; else a client of its own for this call."""
21
+ if http is not None:
22
+ yield http
23
+ return
24
+ async with new_client() as own:
25
+ yield own