causaliq-knowledge 0.2.0__py3-none-any.whl → 0.3.0__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.
- causaliq_knowledge/__init__.py +3 -3
- causaliq_knowledge/cache/__init__.py +18 -0
- causaliq_knowledge/cache/encoders/__init__.py +13 -0
- causaliq_knowledge/cache/encoders/base.py +90 -0
- causaliq_knowledge/cache/encoders/json_encoder.py +418 -0
- causaliq_knowledge/cache/token_cache.py +632 -0
- causaliq_knowledge/cli.py +344 -1
- causaliq_knowledge/llm/base_client.py +141 -1
- causaliq_knowledge/llm/cache.py +380 -0
- {causaliq_knowledge-0.2.0.dist-info → causaliq_knowledge-0.3.0.dist-info}/METADATA +2 -2
- {causaliq_knowledge-0.2.0.dist-info → causaliq_knowledge-0.3.0.dist-info}/RECORD +15 -9
- {causaliq_knowledge-0.2.0.dist-info → causaliq_knowledge-0.3.0.dist-info}/WHEEL +1 -1
- {causaliq_knowledge-0.2.0.dist-info → causaliq_knowledge-0.3.0.dist-info}/entry_points.txt +0 -0
- {causaliq_knowledge-0.2.0.dist-info → causaliq_knowledge-0.3.0.dist-info}/licenses/LICENSE +0 -0
- {causaliq_knowledge-0.2.0.dist-info → causaliq_knowledge-0.3.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LLM-specific cache encoder and data structures.
|
|
3
|
+
|
|
4
|
+
This module provides the LLMEntryEncoder for caching LLM requests and
|
|
5
|
+
responses with rich metadata for analysis.
|
|
6
|
+
|
|
7
|
+
Note: This module stays in causaliq-knowledge (LLM-specific).
|
|
8
|
+
The base cache infrastructure will migrate to causaliq-core.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from dataclasses import asdict, dataclass, field
|
|
14
|
+
from datetime import datetime, timezone
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import TYPE_CHECKING, Any
|
|
17
|
+
|
|
18
|
+
from causaliq_knowledge.cache.encoders import JsonEncoder
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING: # pragma: no cover
|
|
21
|
+
from causaliq_knowledge.cache.token_cache import TokenCache
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class LLMTokenUsage:
|
|
26
|
+
"""Token usage statistics for an LLM request.
|
|
27
|
+
|
|
28
|
+
Attributes:
|
|
29
|
+
input: Number of tokens in the prompt.
|
|
30
|
+
output: Number of tokens in the completion.
|
|
31
|
+
total: Total tokens (input + output).
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
input: int = 0
|
|
35
|
+
output: int = 0
|
|
36
|
+
total: int = 0
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass
|
|
40
|
+
class LLMMetadata:
|
|
41
|
+
"""Metadata for a cached LLM response.
|
|
42
|
+
|
|
43
|
+
Attributes:
|
|
44
|
+
provider: LLM provider name (openai, anthropic, etc.).
|
|
45
|
+
timestamp: When the original request was made (ISO format).
|
|
46
|
+
latency_ms: Response time in milliseconds.
|
|
47
|
+
tokens: Token usage statistics.
|
|
48
|
+
cost_usd: Estimated cost of the request in USD.
|
|
49
|
+
cache_hit: Whether this was served from cache.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
provider: str = ""
|
|
53
|
+
timestamp: str = ""
|
|
54
|
+
latency_ms: int = 0
|
|
55
|
+
tokens: LLMTokenUsage = field(default_factory=LLMTokenUsage)
|
|
56
|
+
cost_usd: float = 0.0
|
|
57
|
+
cache_hit: bool = False
|
|
58
|
+
|
|
59
|
+
def to_dict(self) -> dict[str, Any]:
|
|
60
|
+
"""Convert to dictionary for JSON serialisation."""
|
|
61
|
+
return {
|
|
62
|
+
"provider": self.provider,
|
|
63
|
+
"timestamp": self.timestamp,
|
|
64
|
+
"latency_ms": self.latency_ms,
|
|
65
|
+
"tokens": asdict(self.tokens),
|
|
66
|
+
"cost_usd": self.cost_usd,
|
|
67
|
+
"cache_hit": self.cache_hit,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@classmethod
|
|
71
|
+
def from_dict(cls, data: dict[str, Any]) -> LLMMetadata:
|
|
72
|
+
"""Create from dictionary."""
|
|
73
|
+
tokens_data = data.get("tokens", {})
|
|
74
|
+
return cls(
|
|
75
|
+
provider=data.get("provider", ""),
|
|
76
|
+
timestamp=data.get("timestamp", ""),
|
|
77
|
+
latency_ms=data.get("latency_ms", 0),
|
|
78
|
+
tokens=LLMTokenUsage(
|
|
79
|
+
input=tokens_data.get("input", 0),
|
|
80
|
+
output=tokens_data.get("output", 0),
|
|
81
|
+
total=tokens_data.get("total", 0),
|
|
82
|
+
),
|
|
83
|
+
cost_usd=data.get("cost_usd", 0.0),
|
|
84
|
+
cache_hit=data.get("cache_hit", False),
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@dataclass
|
|
89
|
+
class LLMResponse:
|
|
90
|
+
"""LLM response data for caching.
|
|
91
|
+
|
|
92
|
+
Attributes:
|
|
93
|
+
content: The full text response from the LLM.
|
|
94
|
+
finish_reason: Why generation stopped (stop, length, etc.).
|
|
95
|
+
model_version: Actual model version used.
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
content: str = ""
|
|
99
|
+
finish_reason: str = "stop"
|
|
100
|
+
model_version: str = ""
|
|
101
|
+
|
|
102
|
+
def to_dict(self) -> dict[str, Any]:
|
|
103
|
+
"""Convert to dictionary for JSON serialisation."""
|
|
104
|
+
return {
|
|
105
|
+
"content": self.content,
|
|
106
|
+
"finish_reason": self.finish_reason,
|
|
107
|
+
"model_version": self.model_version,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def from_dict(cls, data: dict[str, Any]) -> LLMResponse:
|
|
112
|
+
"""Create from dictionary."""
|
|
113
|
+
return cls(
|
|
114
|
+
content=data.get("content", ""),
|
|
115
|
+
finish_reason=data.get("finish_reason", "stop"),
|
|
116
|
+
model_version=data.get("model_version", ""),
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclass
|
|
121
|
+
class LLMCacheEntry:
|
|
122
|
+
"""Complete LLM cache entry with request, response, and metadata.
|
|
123
|
+
|
|
124
|
+
Attributes:
|
|
125
|
+
model: The model name requested.
|
|
126
|
+
messages: The conversation messages.
|
|
127
|
+
temperature: Sampling temperature.
|
|
128
|
+
max_tokens: Maximum tokens in response.
|
|
129
|
+
response: The LLM response data.
|
|
130
|
+
metadata: Rich metadata for analysis.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
model: str = ""
|
|
134
|
+
messages: list[dict[str, Any]] = field(default_factory=list)
|
|
135
|
+
temperature: float = 0.0
|
|
136
|
+
max_tokens: int | None = None
|
|
137
|
+
response: LLMResponse = field(default_factory=LLMResponse)
|
|
138
|
+
metadata: LLMMetadata = field(default_factory=LLMMetadata)
|
|
139
|
+
|
|
140
|
+
def to_dict(self) -> dict[str, Any]:
|
|
141
|
+
"""Convert to dictionary for JSON serialisation."""
|
|
142
|
+
return {
|
|
143
|
+
"cache_key": {
|
|
144
|
+
"model": self.model,
|
|
145
|
+
"messages": self.messages,
|
|
146
|
+
"temperature": self.temperature,
|
|
147
|
+
"max_tokens": self.max_tokens,
|
|
148
|
+
},
|
|
149
|
+
"response": self.response.to_dict(),
|
|
150
|
+
"metadata": self.metadata.to_dict(),
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
@classmethod
|
|
154
|
+
def from_dict(cls, data: dict[str, Any]) -> LLMCacheEntry:
|
|
155
|
+
"""Create from dictionary."""
|
|
156
|
+
cache_key = data.get("cache_key", {})
|
|
157
|
+
return cls(
|
|
158
|
+
model=cache_key.get("model", ""),
|
|
159
|
+
messages=cache_key.get("messages", []),
|
|
160
|
+
temperature=cache_key.get("temperature", 0.0),
|
|
161
|
+
max_tokens=cache_key.get("max_tokens"),
|
|
162
|
+
response=LLMResponse.from_dict(data.get("response", {})),
|
|
163
|
+
metadata=LLMMetadata.from_dict(data.get("metadata", {})),
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def create(
|
|
168
|
+
cls,
|
|
169
|
+
model: str,
|
|
170
|
+
messages: list[dict[str, Any]],
|
|
171
|
+
content: str,
|
|
172
|
+
*,
|
|
173
|
+
temperature: float = 0.0,
|
|
174
|
+
max_tokens: int | None = None,
|
|
175
|
+
finish_reason: str = "stop",
|
|
176
|
+
model_version: str = "",
|
|
177
|
+
provider: str = "",
|
|
178
|
+
latency_ms: int = 0,
|
|
179
|
+
input_tokens: int = 0,
|
|
180
|
+
output_tokens: int = 0,
|
|
181
|
+
cost_usd: float = 0.0,
|
|
182
|
+
) -> LLMCacheEntry:
|
|
183
|
+
"""Create a cache entry with common parameters.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
model: The model name requested.
|
|
187
|
+
messages: The conversation messages.
|
|
188
|
+
content: The response content.
|
|
189
|
+
temperature: Sampling temperature.
|
|
190
|
+
max_tokens: Maximum tokens in response.
|
|
191
|
+
finish_reason: Why generation stopped.
|
|
192
|
+
model_version: Actual model version.
|
|
193
|
+
provider: LLM provider name.
|
|
194
|
+
latency_ms: Response time in milliseconds.
|
|
195
|
+
input_tokens: Number of input tokens.
|
|
196
|
+
output_tokens: Number of output tokens.
|
|
197
|
+
cost_usd: Estimated cost in USD.
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Configured LLMCacheEntry.
|
|
201
|
+
"""
|
|
202
|
+
return cls(
|
|
203
|
+
model=model,
|
|
204
|
+
messages=messages,
|
|
205
|
+
temperature=temperature,
|
|
206
|
+
max_tokens=max_tokens,
|
|
207
|
+
response=LLMResponse(
|
|
208
|
+
content=content,
|
|
209
|
+
finish_reason=finish_reason,
|
|
210
|
+
model_version=model_version or model,
|
|
211
|
+
),
|
|
212
|
+
metadata=LLMMetadata(
|
|
213
|
+
provider=provider,
|
|
214
|
+
timestamp=datetime.now(timezone.utc).isoformat(),
|
|
215
|
+
latency_ms=latency_ms,
|
|
216
|
+
tokens=LLMTokenUsage(
|
|
217
|
+
input=input_tokens,
|
|
218
|
+
output=output_tokens,
|
|
219
|
+
total=input_tokens + output_tokens,
|
|
220
|
+
),
|
|
221
|
+
cost_usd=cost_usd,
|
|
222
|
+
cache_hit=False,
|
|
223
|
+
),
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class LLMEntryEncoder(JsonEncoder):
|
|
228
|
+
"""Encoder for LLM cache entries.
|
|
229
|
+
|
|
230
|
+
Extends JsonEncoder with LLM-specific convenience methods for
|
|
231
|
+
encoding/decoding LLMCacheEntry objects.
|
|
232
|
+
|
|
233
|
+
The encoder stores data in the standard JSON tokenised format,
|
|
234
|
+
achieving 50-70% compression through the shared token dictionary.
|
|
235
|
+
|
|
236
|
+
Example:
|
|
237
|
+
>>> from causaliq_knowledge.cache import TokenCache
|
|
238
|
+
>>> from causaliq_knowledge.llm.cache import (
|
|
239
|
+
... LLMEntryEncoder, LLMCacheEntry,
|
|
240
|
+
... )
|
|
241
|
+
>>> with TokenCache(":memory:") as cache:
|
|
242
|
+
... encoder = LLMEntryEncoder()
|
|
243
|
+
... entry = LLMCacheEntry.create(
|
|
244
|
+
... model="gpt-4",
|
|
245
|
+
... messages=[{"role": "user", "content": "Hello"}],
|
|
246
|
+
... content="Hi there!",
|
|
247
|
+
... provider="openai",
|
|
248
|
+
... )
|
|
249
|
+
... blob = encoder.encode(entry.to_dict(), cache)
|
|
250
|
+
... data = encoder.decode(blob, cache)
|
|
251
|
+
... restored = LLMCacheEntry.from_dict(data)
|
|
252
|
+
"""
|
|
253
|
+
|
|
254
|
+
def encode_entry(self, entry: LLMCacheEntry, cache: TokenCache) -> bytes:
|
|
255
|
+
"""Encode an LLMCacheEntry to bytes.
|
|
256
|
+
|
|
257
|
+
Convenience method that handles to_dict conversion.
|
|
258
|
+
|
|
259
|
+
Args:
|
|
260
|
+
entry: The cache entry to encode.
|
|
261
|
+
cache: TokenCache for token dictionary.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
Encoded bytes.
|
|
265
|
+
"""
|
|
266
|
+
return self.encode(entry.to_dict(), cache)
|
|
267
|
+
|
|
268
|
+
def decode_entry(self, blob: bytes, cache: TokenCache) -> LLMCacheEntry:
|
|
269
|
+
"""Decode bytes to an LLMCacheEntry.
|
|
270
|
+
|
|
271
|
+
Convenience method that handles from_dict conversion.
|
|
272
|
+
|
|
273
|
+
Args:
|
|
274
|
+
blob: Encoded bytes.
|
|
275
|
+
cache: TokenCache for token dictionary.
|
|
276
|
+
|
|
277
|
+
Returns:
|
|
278
|
+
Decoded LLMCacheEntry.
|
|
279
|
+
"""
|
|
280
|
+
data = self.decode(blob, cache)
|
|
281
|
+
return LLMCacheEntry.from_dict(data)
|
|
282
|
+
|
|
283
|
+
def generate_export_filename(
|
|
284
|
+
self, entry: LLMCacheEntry, cache_key: str
|
|
285
|
+
) -> str:
|
|
286
|
+
"""Generate a human-readable filename for export.
|
|
287
|
+
|
|
288
|
+
Creates a filename from model name and query details, with a
|
|
289
|
+
short hash suffix for uniqueness.
|
|
290
|
+
|
|
291
|
+
For edge queries, extracts node names for format:
|
|
292
|
+
{model}_{node_a}_{node_b}_edge_{hash}.json
|
|
293
|
+
|
|
294
|
+
For other queries, uses prompt excerpt:
|
|
295
|
+
{model}_{prompt_excerpt}_{hash}.json
|
|
296
|
+
|
|
297
|
+
Args:
|
|
298
|
+
entry: The cache entry to generate filename for.
|
|
299
|
+
cache_key: The cache key (hash) for uniqueness suffix.
|
|
300
|
+
|
|
301
|
+
Returns:
|
|
302
|
+
Human-readable filename with .json extension.
|
|
303
|
+
|
|
304
|
+
Example:
|
|
305
|
+
>>> encoder = LLMEntryEncoder()
|
|
306
|
+
>>> entry = LLMCacheEntry.create(
|
|
307
|
+
... model="gpt-4",
|
|
308
|
+
... messages=[{"role": "user", "content": "smoking and lung"}],
|
|
309
|
+
... content="Yes...",
|
|
310
|
+
... )
|
|
311
|
+
>>> encoder.generate_export_filename(entry, "a1b2c3d4e5f6")
|
|
312
|
+
'gpt4_smoking_lung_edge_a1b2.json'
|
|
313
|
+
"""
|
|
314
|
+
import re
|
|
315
|
+
|
|
316
|
+
# Sanitize model name (alphanumeric only, lowercase)
|
|
317
|
+
model = re.sub(r"[^a-z0-9]", "", entry.model.lower())
|
|
318
|
+
if len(model) > 15:
|
|
319
|
+
model = model[:15]
|
|
320
|
+
|
|
321
|
+
# Extract user message content
|
|
322
|
+
prompt = ""
|
|
323
|
+
for msg in entry.messages:
|
|
324
|
+
if msg.get("role") == "user":
|
|
325
|
+
prompt = msg.get("content", "")
|
|
326
|
+
break
|
|
327
|
+
|
|
328
|
+
# Try to extract node names for edge queries
|
|
329
|
+
# Look for patterns like "X and Y", "X cause Y", "between X and Y"
|
|
330
|
+
prompt_lower = prompt.lower()
|
|
331
|
+
slug = ""
|
|
332
|
+
|
|
333
|
+
# Pattern: "between X and Y" or "X and Y"
|
|
334
|
+
match = re.search(r"(?:between\s+)?(\w+)\s+and\s+(\w+)", prompt_lower)
|
|
335
|
+
if match:
|
|
336
|
+
node_a = match.group(1)[:15]
|
|
337
|
+
node_b = match.group(2)[:15]
|
|
338
|
+
slug = f"{node_a}_{node_b}_edge"
|
|
339
|
+
|
|
340
|
+
# Fallback: extract first significant words from prompt
|
|
341
|
+
if not slug:
|
|
342
|
+
# Remove common words, keep alphanumeric
|
|
343
|
+
cleaned = re.sub(r"[^a-z0-9\s]", "", prompt_lower)
|
|
344
|
+
words = [
|
|
345
|
+
w
|
|
346
|
+
for w in cleaned.split()
|
|
347
|
+
if w
|
|
348
|
+
not in ("the", "a", "an", "is", "are", "does", "do", "can")
|
|
349
|
+
]
|
|
350
|
+
slug = "_".join(words[:4])
|
|
351
|
+
if len(slug) > 30:
|
|
352
|
+
slug = slug[:30].rstrip("_")
|
|
353
|
+
|
|
354
|
+
# Short hash suffix for uniqueness (4 chars)
|
|
355
|
+
hash_suffix = cache_key[:4] if cache_key else "0000"
|
|
356
|
+
|
|
357
|
+
# Build filename
|
|
358
|
+
parts = [p for p in [model, slug, hash_suffix] if p]
|
|
359
|
+
return "_".join(parts) + ".json"
|
|
360
|
+
|
|
361
|
+
def export_entry(self, entry: LLMCacheEntry, path: Path) -> None:
|
|
362
|
+
"""Export an LLMCacheEntry to a JSON file.
|
|
363
|
+
|
|
364
|
+
Args:
|
|
365
|
+
entry: The cache entry to export.
|
|
366
|
+
path: Destination file path.
|
|
367
|
+
"""
|
|
368
|
+
self.export(entry.to_dict(), path)
|
|
369
|
+
|
|
370
|
+
def import_entry(self, path: Path) -> LLMCacheEntry:
|
|
371
|
+
"""Import an LLMCacheEntry from a JSON file.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
path: Source file path.
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
Imported LLMCacheEntry.
|
|
378
|
+
"""
|
|
379
|
+
data = self.import_(path)
|
|
380
|
+
return LLMCacheEntry.from_dict(data)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: causaliq-knowledge
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Incorporating LLM and human knowledge into causal discovery
|
|
5
5
|
Author-email: CausalIQ <info@causaliq.com>
|
|
6
6
|
Maintainer-email: CausalIQ <info@causaliq.com>
|
|
@@ -89,10 +89,10 @@ Currently implemented releases:
|
|
|
89
89
|
|
|
90
90
|
- **Release v0.1.0 - Foundation LLM**: Simple LLM queries to 1 or 2 LLMs about edge existence and orientation to support graph averaging
|
|
91
91
|
- **Release v0.2.0 - Additional LLMs**: Support for 7 LLM providers (Groq, Gemini, OpenAI, Anthropic, DeepSeek, Mistral, Ollama)
|
|
92
|
+
- **Release v0.3.0 - LLM Caching** *(in development)*: SQLite-based response caching with CLI tools for cache management
|
|
92
93
|
|
|
93
94
|
Planned:
|
|
94
95
|
|
|
95
|
-
- **Release v0.3.0 - LLM Caching**: Caching of LLM queries and responses
|
|
96
96
|
- **Release v0.4.0 - LLM Context**: Variable/role/literature etc context
|
|
97
97
|
- **Release v0.5.0 - Algorithm integration**: Integration into structure learning algorithms
|
|
98
98
|
- **Release v0.6.0 - Legacy Reference**: Support for legacy approaches of deriving knowledge from reference networks
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
causaliq_knowledge/__init__.py,sha256=
|
|
1
|
+
causaliq_knowledge/__init__.py,sha256=3m-1i0_giGiTzvJj_8lDrMrvpDvnPD3IBOGlU3ZmxfM,843
|
|
2
2
|
causaliq_knowledge/base.py,sha256=GBG-sftOKkmUoQzTpm6anDTjP-2nInRZN_36dxoYhvk,2917
|
|
3
|
-
causaliq_knowledge/cli.py,sha256=
|
|
3
|
+
causaliq_knowledge/cli.py,sha256=FjdlpQ62Mm4SjWGLAaXnPdv8hYh73-IUweLQAhrBw9k,25010
|
|
4
4
|
causaliq_knowledge/models.py,sha256=tWGf186ASwO8NHiN97pEOLuBJmJI6Q9jvpU0mYZNdS0,4058
|
|
5
|
+
causaliq_knowledge/cache/__init__.py,sha256=Av92YdCdVTRt9TmB2edRsIFDxq3f1Qi0daq0sFV1rp0,549
|
|
6
|
+
causaliq_knowledge/cache/token_cache.py,sha256=dURih1jr0csVBxU1pCtmcjV48GnQeCnVGi3j1E0KY7Q,21845
|
|
7
|
+
causaliq_knowledge/cache/encoders/__init__.py,sha256=gZ7gw96paFDbnJuc4v1aJsEJfVinI4zc03tXyFvfZxo,461
|
|
8
|
+
causaliq_knowledge/cache/encoders/base.py,sha256=jK7--Or3lVp1UkKghKYFo_gKJp0HsMxosL_8eYL7RQQ,2679
|
|
9
|
+
causaliq_knowledge/cache/encoders/json_encoder.py,sha256=44mcYpT6vJaJT9ZwtnWwdxCvTXIFyoeolqyiAXrgH1o,15110
|
|
5
10
|
causaliq_knowledge/llm/__init__.py,sha256=30AL0h64zIkXoiqhMY7gjaf7mrtwtwMW38vzhns0My4,1663
|
|
6
11
|
causaliq_knowledge/llm/anthropic_client.py,sha256=dPFHYGWL4xwQCtmQuGwGY4DBKSINOgOS-11ekznaiXo,8719
|
|
7
|
-
causaliq_knowledge/llm/base_client.py,sha256=
|
|
12
|
+
causaliq_knowledge/llm/base_client.py,sha256=o2qWu2_ttKMHT4isdkY4VUjma3B3jtdx1vhOLXVFLX4,12249
|
|
13
|
+
causaliq_knowledge/llm/cache.py,sha256=gBjZaYNJZ8HF54Hk25RWGVOvdBFwVPAv78_GYaanRTc,12723
|
|
8
14
|
causaliq_knowledge/llm/deepseek_client.py,sha256=ZcOpgnYa66XHjiTaF5ekR_BtosRYvVmzlIafp_Gsx_A,3543
|
|
9
15
|
causaliq_knowledge/llm/gemini_client.py,sha256=XJMq9sPo7zExrALSr2rIRHLheSPqKo8ENG0KtdJ1cjw,9924
|
|
10
16
|
causaliq_knowledge/llm/groq_client.py,sha256=PnTXqtMF1Km9DY4HiCZXQ6LeOzdjZtQJaeuGe1GbeME,7531
|
|
@@ -14,9 +20,9 @@ causaliq_knowledge/llm/openai_client.py,sha256=MJmB6P32TZESMlXhn9d0-b3vFWXmf7ojH
|
|
|
14
20
|
causaliq_knowledge/llm/openai_compat_client.py,sha256=L8ZW5csuhUePq4mt3EGOUqhR3tleFmM72UlhPBsgIMQ,9518
|
|
15
21
|
causaliq_knowledge/llm/prompts.py,sha256=bJ9iVGKUfTfLi2eWh-FFM4cNzk5Ux4Z0x8R6Ia27Dbo,6598
|
|
16
22
|
causaliq_knowledge/llm/provider.py,sha256=VDEv-1esT_EgJk_Gwlfl4423ojglOxzPCBCFbOFE4DQ,15184
|
|
17
|
-
causaliq_knowledge-0.
|
|
18
|
-
causaliq_knowledge-0.
|
|
19
|
-
causaliq_knowledge-0.
|
|
20
|
-
causaliq_knowledge-0.
|
|
21
|
-
causaliq_knowledge-0.
|
|
22
|
-
causaliq_knowledge-0.
|
|
23
|
+
causaliq_knowledge-0.3.0.dist-info/licenses/LICENSE,sha256=vUFUzQnti-D-MLSi9NxFlsFYOKwU25sxxH7WgJOQFIs,1084
|
|
24
|
+
causaliq_knowledge-0.3.0.dist-info/METADATA,sha256=MIE-z6VqrnzuhHpU8j0DzxB48zwyDIobseO2SltVe-0,8774
|
|
25
|
+
causaliq_knowledge-0.3.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
26
|
+
causaliq_knowledge-0.3.0.dist-info/entry_points.txt,sha256=8iQjiMgFxZszRWwSTGHvoOBb_OBUkMmwvH3PzgsH-Cc,104
|
|
27
|
+
causaliq_knowledge-0.3.0.dist-info/top_level.txt,sha256=GcxQf4BQAGa38i2-j8ylk2FmnBHtEZ9-8bSt-7Uka7k,19
|
|
28
|
+
causaliq_knowledge-0.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|