pdm-memory 0.1.2__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.
@@ -0,0 +1,179 @@
1
+ """
2
+ Anthropic Adapter — Task 4.1
3
+
4
+ Wraps an Anthropic client for automatic PDM memory injection and saving.
5
+
6
+ Usage:
7
+ from pdm_memory.integrations import wrap_anthropic
8
+ from pdm_memory import Memory
9
+
10
+ mem = Memory(store="./my_app.db")
11
+ client = wrap_anthropic(api_key="sk-ant-...", memory=mem)
12
+ reply = client.chat("What units should I use?")
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import logging
18
+ from typing import Any, Optional
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ class PDMAnthropicClient:
24
+ """
25
+ Memory-augmented Anthropic client.
26
+
27
+ All chat() calls automatically:
28
+ - Recall relevant memories before the API call.
29
+ - Inject them via the system prompt.
30
+ - Save both turns as new memories.
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ anthropic_client: Any,
36
+ memory: Any,
37
+ model: str = "claude-3-haiku-20240307",
38
+ max_memory_tokens: int = 1500,
39
+ recall_k: int = 5,
40
+ auto_save: bool = True,
41
+ system_prompt: str = "You are a helpful AI assistant.",
42
+ ) -> None:
43
+ self._client = anthropic_client
44
+ self._memory = memory
45
+ self._model = model
46
+ self._max_memory_tokens = max_memory_tokens
47
+ self._recall_k = recall_k
48
+ self._auto_save = auto_save
49
+ self._system_prompt = system_prompt
50
+
51
+ from pdm_memory.integrations.context_manager import ContextWindowManager
52
+ self._ctx_manager = ContextWindowManager(
53
+ max_tokens=max_memory_tokens,
54
+ model="gpt-4o-mini", # Use cl100k_base approximation for Anthropic
55
+ )
56
+
57
+ def chat(
58
+ self,
59
+ message: str,
60
+ model: Optional[str] = None,
61
+ system_prompt: Optional[str] = None,
62
+ recall_k: Optional[int] = None,
63
+ save_reply: Optional[bool] = None,
64
+ max_tokens: int = 1024,
65
+ **anthropic_kwargs: Any,
66
+ ) -> str:
67
+ """
68
+ Send a message to Anthropic Claude with automatic PDM memory injection.
69
+
70
+ Args:
71
+ message: The user's message.
72
+ model: Override the default model.
73
+ system_prompt: Override the base system prompt.
74
+ recall_k: Override the number of memories to recall.
75
+ save_reply: Override whether to save this exchange to memory.
76
+ max_tokens: Max tokens for Claude's response.
77
+ **anthropic_kwargs: Passed to anthropic.messages.create().
78
+
79
+ Returns:
80
+ The assistant's reply text.
81
+ """
82
+ k = recall_k if recall_k is not None else self._recall_k
83
+ should_save = save_reply if save_reply is not None else self._auto_save
84
+ base_system = system_prompt or self._system_prompt
85
+
86
+ # Step 1: Recall relevant memories
87
+ hits = self._memory.recall(query=message, k=k)
88
+ trimmed = self._ctx_manager.fit(hits)
89
+
90
+ # Step 2: Build system message with memory block
91
+ memory_block = self._ctx_manager.format_for_prompt(trimmed)
92
+ full_system = base_system
93
+ if memory_block:
94
+ full_system = f"{base_system}\n\n{memory_block}"
95
+
96
+ # Step 3: Call Anthropic
97
+ response = self._client.messages.create(
98
+ model=model or self._model,
99
+ max_tokens=max_tokens,
100
+ system=full_system,
101
+ messages=[{"role": "user", "content": message}],
102
+ **anthropic_kwargs,
103
+ )
104
+ reply_text = response.content[0].text if response.content else ""
105
+
106
+ # Step 4: Save this turn to memory
107
+ if should_save:
108
+ self._save_turn(message, reply_text)
109
+
110
+ logger.debug(
111
+ "[PDM-Anthropic] chat() | recalled=%d injected=%d model=%s",
112
+ len(hits), len(trimmed), model or self._model,
113
+ )
114
+ return reply_text
115
+
116
+ def _save_turn(self, user_msg: str, assistant_reply: str) -> None:
117
+ try:
118
+ if user_msg.strip():
119
+ self._memory.save(
120
+ text=user_msg[:500],
121
+ source="anthropic_chat",
122
+ tags=["conversation", "user_input"],
123
+ p_magnitude=40.0,
124
+ )
125
+ except Exception as e:
126
+ logger.warning("[PDM-Anthropic] Failed to save user message: %s", e)
127
+
128
+ try:
129
+ if assistant_reply.strip():
130
+ self._memory.save(
131
+ text=assistant_reply[:500],
132
+ source="anthropic_chat",
133
+ tags=["conversation", "ai_reply"],
134
+ p_magnitude=35.0,
135
+ )
136
+ except Exception as e:
137
+ logger.warning("[PDM-Anthropic] Failed to save assistant reply: %s", e)
138
+
139
+
140
+ def wrap_anthropic(
141
+ api_key: str,
142
+ memory: Any,
143
+ model: str = "claude-3-haiku-20240307",
144
+ max_memory_tokens: int = 1500,
145
+ recall_k: int = 5,
146
+ system_prompt: str = "You are a helpful AI assistant.",
147
+ **anthropic_init_kwargs: Any,
148
+ ) -> PDMAnthropicClient:
149
+ """
150
+ Create a memory-augmented Anthropic client.
151
+
152
+ Args:
153
+ api_key: Your Anthropic API key.
154
+ memory: pdm_memory.Memory instance.
155
+ model: Default Claude model.
156
+ max_memory_tokens: Token budget for injected memories.
157
+ recall_k: Memories to recall per turn.
158
+ system_prompt: Base system prompt.
159
+ **anthropic_init_kwargs: Passed to anthropic.Anthropic().
160
+
161
+ Returns:
162
+ PDMAnthropicClient wrapping an anthropic.Anthropic client.
163
+ """
164
+ try:
165
+ import anthropic
166
+ except ImportError:
167
+ raise ImportError(
168
+ "anthropic package is required. Install it: pip install pdm-memory[anthropic]"
169
+ )
170
+
171
+ client = anthropic.Anthropic(api_key=api_key, **anthropic_init_kwargs)
172
+ return PDMAnthropicClient(
173
+ anthropic_client=client,
174
+ memory=memory,
175
+ model=model,
176
+ max_memory_tokens=max_memory_tokens,
177
+ recall_k=recall_k,
178
+ system_prompt=system_prompt,
179
+ )
@@ -0,0 +1,134 @@
1
+ """
2
+ Context Window Manager — Task 4.2
3
+
4
+ Trims recalled memories to fit within a model's token budget.
5
+
6
+ Usage:
7
+ manager = ContextWindowManager(max_tokens=1500, model="gpt-4o")
8
+ trimmed_hits = manager.fit(hits)
9
+ system_block = manager.format_for_prompt(trimmed_hits)
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import logging
15
+ from typing import List, Optional
16
+
17
+ from pdm_memory.core.signature import MemoryHit
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ class ContextWindowManager:
23
+ """
24
+ Manages the token budget for PDM memories injected into LLM context.
25
+
26
+ Trimming strategy: drop memories with the lowest p_effective first,
27
+ until the remaining set fits within max_tokens.
28
+
29
+ Args:
30
+ max_tokens: Maximum tokens the memory block may consume.
31
+ model: Model name (used to load the correct tokeniser).
32
+ chars_per_token: Approximation fallback if tiktoken is unavailable (default 4).
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ max_tokens: int = 1500,
38
+ model: str = "gpt-4o-mini",
39
+ chars_per_token: float = 4.0,
40
+ ) -> None:
41
+ self.max_tokens = max_tokens
42
+ self.model = model
43
+ self._chars_per_token = chars_per_token
44
+ self._encoder = self._load_encoder(model)
45
+
46
+ # ------------------------------------------------------------------
47
+ # Public API
48
+ # ------------------------------------------------------------------
49
+
50
+ def fit(self, hits: List[MemoryHit]) -> List[MemoryHit]:
51
+ """
52
+ Return the highest-pressure subset of hits that fits within max_tokens.
53
+
54
+ Memories are sorted by p_effective descending. The lowest-p ones
55
+ are dropped first to respect the token budget.
56
+
57
+ Args:
58
+ hits: List of MemoryHit objects from mem.recall().
59
+
60
+ Returns:
61
+ Trimmed list of MemoryHit, still sorted by p_effective desc.
62
+ """
63
+ if not hits:
64
+ return hits
65
+
66
+ # Sort highest pressure first (most important memories stay)
67
+ sorted_hits = sorted(hits, key=lambda h: h.p_effective, reverse=True)
68
+
69
+ kept: List[MemoryHit] = []
70
+ used_tokens = 0
71
+
72
+ for hit in sorted_hits:
73
+ tokens = self.count_tokens(hit.text)
74
+ if used_tokens + tokens <= self.max_tokens:
75
+ kept.append(hit)
76
+ used_tokens += tokens
77
+ else:
78
+ logger.debug(
79
+ "[CTX] Trimmed memory %s (P=%.1f, tokens=%d): budget exhausted",
80
+ hit.id[:8], hit.p_effective, tokens,
81
+ )
82
+
83
+ if len(kept) < len(hits):
84
+ logger.info(
85
+ "[CTX] Token budget %d: kept %d/%d memories (used %d tokens)",
86
+ self.max_tokens, len(kept), len(hits), used_tokens,
87
+ )
88
+
89
+ return kept
90
+
91
+ def format_for_prompt(self, hits: List[MemoryHit]) -> str:
92
+ """
93
+ Format a list of MemoryHit objects into a system prompt block.
94
+
95
+ Returns an empty string if no hits.
96
+ """
97
+ if not hits:
98
+ return ""
99
+
100
+ lines = ["[MEMORY CONTEXT — Pressure-Driven Memory]"]
101
+ for i, hit in enumerate(hits, 1):
102
+ tags = ", ".join(hit.intent_tags) if hit.intent_tags else hit.domain
103
+ lines.append(
104
+ f"{i}. [{hit.drawer}] {hit.text} "
105
+ f"(relevance: {hit.p_effective:.0f}/100, tags: {tags})"
106
+ )
107
+ lines.append("[END MEMORY CONTEXT]")
108
+ return "\n".join(lines)
109
+
110
+ def count_tokens(self, text: str) -> int:
111
+ """Estimate token count for a string."""
112
+ if self._encoder is not None:
113
+ try:
114
+ return len(self._encoder.encode(text))
115
+ except Exception:
116
+ pass
117
+ # Fallback: character approximation
118
+ return max(1, int(len(text) / self._chars_per_token))
119
+
120
+ # ------------------------------------------------------------------
121
+ # Private
122
+ # ------------------------------------------------------------------
123
+
124
+ @staticmethod
125
+ def _load_encoder(model: str) -> Optional[object]:
126
+ try:
127
+ import tiktoken
128
+ try:
129
+ return tiktoken.encoding_for_model(model)
130
+ except KeyError:
131
+ return tiktoken.get_encoding("cl100k_base")
132
+ except ImportError:
133
+ logger.debug("[CTX] tiktoken not installed; using char approximation")
134
+ return None
@@ -0,0 +1,215 @@
1
+ """
2
+ Gemini Adapter
3
+
4
+ Wraps Google Gemini client for automatic PDM memory injection and saving.
5
+ Supports both the new google-genai Client and legacy google-generativeai GenerativeModel.
6
+
7
+ Usage:
8
+ from pdm_memory.integrations import wrap_gemini
9
+ from pdm_memory import Memory
10
+ from google import genai
11
+
12
+ mem = Memory(store="./my_app.db")
13
+ client = genai.Client(api_key="...")
14
+ wrapped_client = wrap_gemini(client, memory=mem)
15
+ reply = wrapped_client.chat("What are my preferences?")
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import logging
21
+ from typing import Any, Optional
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ class PDMGeminiClient:
27
+ """
28
+ Memory-augmented Gemini client.
29
+
30
+ All chat() calls automatically:
31
+ - Recall relevant memories before the API call.
32
+ - Inject them into the system instruction/prompt.
33
+ - Save both user message and AI reply as new memories.
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ gemini_client: Any,
39
+ memory: Any, # pdm_memory.Memory instance
40
+ model: str = "gemini-2.5-flash",
41
+ max_memory_tokens: int = 1500,
42
+ recall_k: int = 5,
43
+ auto_save: bool = True,
44
+ system_prompt: str = "You are a helpful AI assistant.",
45
+ ) -> None:
46
+ self._client = gemini_client
47
+ self._memory = memory
48
+ self._model = model
49
+ self._max_memory_tokens = max_memory_tokens
50
+ self._recall_k = recall_k
51
+ self._auto_save = auto_save
52
+ self._system_prompt = system_prompt
53
+
54
+ from pdm_memory.integrations.context_manager import ContextWindowManager
55
+ self._ctx_manager = ContextWindowManager(
56
+ max_tokens=max_memory_tokens,
57
+ model="gpt-4o-mini", # Use cl100k_base approximation
58
+ )
59
+
60
+ def chat(
61
+ self,
62
+ message: str,
63
+ model: Optional[str] = None,
64
+ system_prompt: Optional[str] = None,
65
+ recall_k: Optional[int] = None,
66
+ save_reply: Optional[bool] = None,
67
+ **gemini_kwargs: Any,
68
+ ) -> str:
69
+ """
70
+ Send a message to Gemini with automatic PDM memory injection.
71
+
72
+ Args:
73
+ message: The user's message.
74
+ model: Override the default model name.
75
+ system_prompt: Override the base system prompt.
76
+ recall_k: Override the number of memories to recall.
77
+ save_reply: Override whether to save this exchange to memory.
78
+ **gemini_kwargs: Passed through to generate_content API calls.
79
+
80
+ Returns:
81
+ The assistant's reply text.
82
+ """
83
+ k = recall_k if recall_k is not None else self._recall_k
84
+ should_save = save_reply if save_reply is not None else self._auto_save
85
+ base_system = system_prompt or self._system_prompt
86
+
87
+ # Step 1: Recall relevant memories
88
+ hits = self._memory.recall(query=message, k=k)
89
+ trimmed = self._ctx_manager.fit(hits)
90
+
91
+ # Step 2: Build system message with memory block
92
+ memory_block = self._ctx_manager.format_for_prompt(trimmed)
93
+ full_system = base_system
94
+ if memory_block:
95
+ full_system = f"{base_system}\n\n{memory_block}"
96
+
97
+ model_name = model or self._model
98
+
99
+ # Step 3: Call Gemini API
100
+ if hasattr(self._client, "models") and hasattr(self._client.models, "generate_content"):
101
+ # New google-genai Client SDK
102
+ config = gemini_kwargs.pop("config", None)
103
+ if config is None:
104
+ try:
105
+ from google.genai import types
106
+ config = types.GenerateContentConfig(system_instruction=full_system)
107
+ except ImportError:
108
+ config = {"system_instruction": full_system}
109
+ else:
110
+ if hasattr(config, "system_instruction"):
111
+ config.system_instruction = full_system
112
+ elif isinstance(config, dict):
113
+ config["system_instruction"] = full_system
114
+
115
+ response = self._client.models.generate_content(
116
+ model=model_name,
117
+ contents=message,
118
+ config=config,
119
+ **gemini_kwargs,
120
+ )
121
+ reply_text = response.text or ""
122
+ elif hasattr(self._client, "generate_content"):
123
+ # Legacy google-generativeai SDK (GenerativeModel object)
124
+ # Recreate model with dynamic system_instruction or prepend to content
125
+ try:
126
+ import google.generativeai as genai
127
+ temp_model = genai.GenerativeModel(
128
+ model_name=getattr(self._client, "model_name", model_name),
129
+ system_instruction=full_system,
130
+ )
131
+ response = temp_model.generate_content(
132
+ contents=message,
133
+ **gemini_kwargs,
134
+ )
135
+ reply_text = response.text or ""
136
+ except ImportError:
137
+ # Fallback: prepend system prompt as context if package is not importable
138
+ # (unlikely if legacy client was passed)
139
+ contents_with_ctx = f"System Instruction:\n{full_system}\n\nUser Input:\n{message}"
140
+ response = self._client.generate_content(
141
+ contents=contents_with_ctx,
142
+ **gemini_kwargs,
143
+ )
144
+ reply_text = response.text or ""
145
+ else:
146
+ raise TypeError(
147
+ "Unsupported Gemini client type. Expected a Client from google-genai "
148
+ "or GenerativeModel from google-generativeai."
149
+ )
150
+
151
+ # Step 4: Save this turn to memory
152
+ if should_save:
153
+ self._save_turn(message, reply_text)
154
+
155
+ logger.debug(
156
+ "[PDM-Gemini] chat() | recalled=%d injected=%d model=%s",
157
+ len(hits), len(trimmed), model_name,
158
+ )
159
+ return reply_text
160
+
161
+ def _save_turn(self, user_msg: str, assistant_reply: str) -> None:
162
+ """Save user message and assistant reply as memories."""
163
+ try:
164
+ if user_msg.strip():
165
+ self._memory.save(
166
+ text=user_msg[:500],
167
+ source="gemini_chat",
168
+ tags=["conversation", "user_input"],
169
+ p_magnitude=40.0,
170
+ )
171
+ except Exception as e:
172
+ logger.warning("[PDM-Gemini] Failed to save user message: %s", e)
173
+
174
+ try:
175
+ if assistant_reply.strip():
176
+ self._memory.save(
177
+ text=assistant_reply[:500],
178
+ source="gemini_chat",
179
+ tags=["conversation", "ai_reply"],
180
+ p_magnitude=35.0,
181
+ )
182
+ except Exception as e:
183
+ logger.warning("[PDM-Gemini] Failed to save assistant reply: %s", e)
184
+
185
+
186
+ def wrap_gemini(
187
+ client: Any,
188
+ memory: Any,
189
+ model: str = "gemini-2.5-flash",
190
+ max_memory_tokens: int = 1500,
191
+ recall_k: int = 5,
192
+ system_prompt: str = "You are a helpful AI assistant.",
193
+ ) -> PDMGeminiClient:
194
+ """
195
+ Create a memory-augmented Gemini client.
196
+
197
+ Args:
198
+ client: google-genai Client or google-generativeai GenerativeModel instance.
199
+ memory: pdm_memory.Memory instance.
200
+ model: Default model (default: gemini-2.5-flash).
201
+ max_memory_tokens: Token budget for injected memories.
202
+ recall_k: Number of memories to recall per turn.
203
+ system_prompt: Base system prompt.
204
+
205
+ Returns:
206
+ PDMGeminiClient wrapping the provided client.
207
+ """
208
+ return PDMGeminiClient(
209
+ gemini_client=client,
210
+ memory=memory,
211
+ model=model,
212
+ max_memory_tokens=max_memory_tokens,
213
+ recall_k=recall_k,
214
+ system_prompt=system_prompt,
215
+ )
@@ -0,0 +1,171 @@
1
+ """
2
+ Groq Adapter
3
+
4
+ Wraps Groq client for automatic PDM memory injection and saving.
5
+
6
+ Usage:
7
+ from pdm_memory.integrations import wrap_groq
8
+ from pdm_memory import Memory
9
+ from groq import Groq
10
+
11
+ mem = Memory(store="./my_app.db")
12
+ client = Groq(api_key="gsk_...")
13
+ wrapped_client = wrap_groq(client, memory=mem)
14
+ reply = wrapped_client.chat("What are my preferences?")
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import logging
20
+ from typing import Any, Optional
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ class PDMGroqClient:
26
+ """
27
+ Memory-augmented Groq client.
28
+
29
+ All chat() calls automatically:
30
+ - Recall relevant memories before the API call.
31
+ - Inject them into the system prompt.
32
+ - Save both user message and AI reply as new memories.
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ groq_client: Any,
38
+ memory: Any, # pdm_memory.Memory instance
39
+ model: str = "llama-3.1-70b-versatile",
40
+ max_memory_tokens: int = 1500,
41
+ recall_k: int = 5,
42
+ auto_save: bool = True,
43
+ system_prompt: str = "You are a helpful AI assistant.",
44
+ ) -> None:
45
+ self._client = groq_client
46
+ self._memory = memory
47
+ self._model = model
48
+ self._max_memory_tokens = max_memory_tokens
49
+ self._recall_k = recall_k
50
+ self._auto_save = auto_save
51
+ self._system_prompt = system_prompt
52
+
53
+ from pdm_memory.integrations.context_manager import ContextWindowManager
54
+ self._ctx_manager = ContextWindowManager(
55
+ max_tokens=max_memory_tokens,
56
+ model="gpt-4o-mini", # Use cl100k_base approximation
57
+ )
58
+
59
+ def chat(
60
+ self,
61
+ message: str,
62
+ model: Optional[str] = None,
63
+ system_prompt: Optional[str] = None,
64
+ recall_k: Optional[int] = None,
65
+ save_reply: Optional[bool] = None,
66
+ **groq_kwargs: Any,
67
+ ) -> str:
68
+ """
69
+ Send a message to Groq with automatic PDM memory injection.
70
+
71
+ Args:
72
+ message: The user's message.
73
+ model: Override the default model.
74
+ system_prompt: Override the base system prompt.
75
+ recall_k: Override the number of memories to recall.
76
+ save_reply: Override whether to save this exchange to memory.
77
+ **groq_kwargs: Passed through to groq.chat.completions.create().
78
+
79
+ Returns:
80
+ The assistant's reply text.
81
+ """
82
+ k = recall_k if recall_k is not None else self._recall_k
83
+ should_save = save_reply if save_reply is not None else self._auto_save
84
+ base_system = system_prompt or self._system_prompt
85
+
86
+ # Step 1: Recall relevant memories
87
+ hits = self._memory.recall(query=message, k=k)
88
+ trimmed = self._ctx_manager.fit(hits)
89
+
90
+ # Step 2: Build system message with memory block
91
+ memory_block = self._ctx_manager.format_for_prompt(trimmed)
92
+ full_system = base_system
93
+ if memory_block:
94
+ full_system = f"{base_system}\n\n{memory_block}"
95
+
96
+ # Step 3: Call Groq
97
+ response = self._client.chat.completions.create(
98
+ model=model or self._model,
99
+ messages=[
100
+ {"role": "system", "content": full_system},
101
+ {"role": "user", "content": message},
102
+ ],
103
+ **groq_kwargs,
104
+ )
105
+ reply_text = response.choices[0].message.content or ""
106
+
107
+ # Step 4: Save this turn to memory
108
+ if should_save:
109
+ self._save_turn(message, reply_text)
110
+
111
+ logger.debug(
112
+ "[PDM-Groq] chat() | recalled=%d injected=%d model=%s",
113
+ len(hits), len(trimmed), model or self._model,
114
+ )
115
+ return reply_text
116
+
117
+ def _save_turn(self, user_msg: str, assistant_reply: str) -> None:
118
+ """Save user message and assistant reply as memories."""
119
+ try:
120
+ if user_msg.strip():
121
+ self._memory.save(
122
+ text=user_msg[:500],
123
+ source="groq_chat",
124
+ tags=["conversation", "user_input"],
125
+ p_magnitude=40.0,
126
+ )
127
+ except Exception as e:
128
+ logger.warning("[PDM-Groq] Failed to save user message: %s", e)
129
+
130
+ try:
131
+ if assistant_reply.strip():
132
+ self._memory.save(
133
+ text=assistant_reply[:500],
134
+ source="groq_chat",
135
+ tags=["conversation", "ai_reply"],
136
+ p_magnitude=35.0,
137
+ )
138
+ except Exception as e:
139
+ logger.warning("[PDM-Groq] Failed to save assistant reply: %s", e)
140
+
141
+
142
+ def wrap_groq(
143
+ client: Any,
144
+ memory: Any,
145
+ model: str = "llama-3.1-70b-versatile",
146
+ max_memory_tokens: int = 1500,
147
+ recall_k: int = 5,
148
+ system_prompt: str = "You are a helpful AI assistant.",
149
+ ) -> PDMGroqClient:
150
+ """
151
+ Create a memory-augmented Groq client.
152
+
153
+ Args:
154
+ client: groq.Groq client instance.
155
+ memory: pdm_memory.Memory instance.
156
+ model: Default model (default: llama-3.1-70b-versatile).
157
+ max_memory_tokens: Token budget for injected memories.
158
+ recall_k: Number of memories to recall per turn.
159
+ system_prompt: Base system prompt.
160
+
161
+ Returns:
162
+ PDMGroqClient wrapping the provided groq client.
163
+ """
164
+ return PDMGroqClient(
165
+ groq_client=client,
166
+ memory=memory,
167
+ model=model,
168
+ max_memory_tokens=max_memory_tokens,
169
+ recall_k=recall_k,
170
+ system_prompt=system_prompt,
171
+ )