main
py 88 lines 2.94 KB
Raw
1 from __future__ import annotations
2
3 import re
4 from typing import Iterable
5
6
7 _DURABLE_SUBJECT_RE = re.compile(
8 r"\b(user|project|repo|repository|workspace|runtime|service|server|"
9 r"plugin|agent zero|a0|profile|team|organization|company)\b",
10 re.IGNORECASE,
11 )
12 _DURABLE_RELATION_RE = re.compile(
13 r"\b(prefers?|requires?|uses?|runs?|lives?|located|configured|default|"
14 r"current(?:ly)?|must|should|always|never|constraint|path|endpoint|port)\b",
15 re.IGNORECASE,
16 )
17 _TRANSIENT_RE = re.compile(
18 r"(/tmp\b|\btmp/|\btemporary\b|\btemp\b|\bworkdir\b|"
19 r"\bcontainer-local\b|\bmachine-local\b|\bpersonal absolute path\b|"
20 r"\blocal endpoint\b|\blocal port\b|"
21 r"\btest marker\b|\bmemory test\b|\bcleanup token\b|\bthrowaway\b|"
22 r"\bsample file\b|\bdemo file\b|\bvalidation directory\b|\blive-test\b|"
23 r"\bone-off\b|\bsession-only\b)",
24 re.IGNORECASE,
25 )
26 _LOCAL_COORDINATE_RE = re.compile(
27 r"\b(localhost|127\.0\.0\.1|0\.0\.0\.0|::1)\b|"
28 r"https?://(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::1\])(?::\d+)?|"
29 r"/(?:home|Users)/[^/\s]+/|"
30 r"\b[A-Za-z]:\\Users\\",
31 re.IGNORECASE,
32 )
33 _AGENT_ACTION_RE = re.compile(
34 r"\b(agent|assistant|codex|a0)\b.{0,80}\b("
35 r"created|implemented|built|ran|tested|verified|fixed|wrote|generated|"
36 r"saved|cleaned|inspected|synced|restarted|committed|staged|opened|"
37 r"reported|showed)\b",
38 re.IGNORECASE,
39 )
40 _USER_REQUEST_RE = re.compile(
41 r"\b(user|the user)\s+(asked|requested|wanted|told|prompted|instructed)\b",
42 re.IGNORECASE,
43 )
44 _COMMAND_HISTORY_RE = re.compile(
45 r"\b(ran|executed)\s+[`'\"]?[\w./-]+|\bterminal command\b|"
46 r"\bcommand output\b|\bexit code\b|\bstdout\b|\bstderr\b",
47 re.IGNORECASE,
48 )
49 _LOW_VALUE_RE = re.compile(
50 r"^(hello|hi|greeting|conversation start|task completed|file created|"
51 r"implementation completed|test passed|memory search)$",
52 re.IGNORECASE,
53 )
54
55
56 def normalize_memory_candidate(value: object) -> str:
57 return str(value).strip()
58
59
60 def is_auto_fragment_worth_saving(text: str) -> bool:
61 """Return True only for durable facts suitable for automatic fragments."""
62
63 text = normalize_memory_candidate(text)
64 has_durable_relation = bool(_DURABLE_RELATION_RE.search(text))
65 if len(text) < 24:
66 return False
67 if _LOW_VALUE_RE.match(text):
68 return False
69 if _TRANSIENT_RE.search(text):
70 return False
71 if _LOCAL_COORDINATE_RE.search(text):
72 return False
73 if _COMMAND_HISTORY_RE.search(text):
74 return False
75 if _AGENT_ACTION_RE.search(text) and not has_durable_relation:
76 return False
77 if _USER_REQUEST_RE.search(text) and not has_durable_relation:
78 return False
79
80 return bool(_DURABLE_SUBJECT_RE.search(text) and has_durable_relation)
81
82
83 def filter_auto_memory_fragments(memories: Iterable[object]) -> list[str]:
84 return [
85 text
86 for text in (normalize_memory_candidate(memory) for memory in memories)
87 if is_auto_fragment_worth_saving(text)
88 ]