kader 0.1.1__tar.gz → 0.1.3__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.
- {kader-0.1.1 → kader-0.1.3}/PKG-INFO +2 -1
- {kader-0.1.1 → kader-0.1.3}/cli/app.py +124 -2
- {kader-0.1.1 → kader-0.1.3}/cli/app.tcss +17 -0
- {kader-0.1.1 → kader-0.1.3}/cli/utils.py +1 -0
- {kader-0.1.1 → kader-0.1.3}/kader/agent/base.py +8 -6
- {kader-0.1.1 → kader-0.1.3}/kader/agent/logger.py +1 -19
- {kader-0.1.1 → kader-0.1.3}/pyproject.toml +2 -1
- {kader-0.1.1 → kader-0.1.3}/tests/test_agent_logger.py +2 -99
- {kader-0.1.1 → kader-0.1.3}/uv.lock +132 -1
- {kader-0.1.1 → kader-0.1.3}/.github/workflows/ci.yml +0 -0
- {kader-0.1.1 → kader-0.1.3}/.github/workflows/release.yml +0 -0
- {kader-0.1.1 → kader-0.1.3}/.gitignore +0 -0
- {kader-0.1.1 → kader-0.1.3}/.python-version +0 -0
- {kader-0.1.1 → kader-0.1.3}/.qwen/QWEN.md +0 -0
- {kader-0.1.1 → kader-0.1.3}/.qwen/agents/technical-writer.md +0 -0
- {kader-0.1.1 → kader-0.1.3}/.qwen/agents/test-automation-specialist.md +0 -0
- {kader-0.1.1 → kader-0.1.3}/README.md +0 -0
- {kader-0.1.1 → kader-0.1.3}/cli/README.md +0 -0
- {kader-0.1.1 → kader-0.1.3}/cli/__init__.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/cli/__main__.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/cli/widgets/__init__.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/cli/widgets/confirmation.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/cli/widgets/conversation.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/cli/widgets/loading.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/.gitignore +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/README.md +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/memory_example.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/ollama_example.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/planning_agent_example.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/python_developer/main.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/python_developer/template.yaml +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/react_agent_example.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/simple_agent.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/todo_agent/main.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/examples/tools_example.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/__init__.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/agent/__init__.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/agent/agents.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/config.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/memory/__init__.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/memory/conversation.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/memory/session.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/memory/state.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/memory/types.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/prompts/__init__.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/prompts/agent_prompts.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/prompts/base.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/prompts/templates/planning_agent.j2 +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/prompts/templates/react_agent.j2 +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/providers/__init__.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/providers/base.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/providers/mock.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/providers/ollama.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/README.md +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/__init__.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/base.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/exec_commands.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/filesys.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/filesystem.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/protocol.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/rag.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/todo.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/utils.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/kader/tools/web.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/conftest.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/providers/test_mock.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/providers/test_ollama.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/providers/test_providers_base.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/test_agent_logger_integration.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/test_base_agent.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/test_file_memory.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/test_todo_tool.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/tools/test_exec_commands.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/tools/test_filesys_tools.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/tools/test_filesystem_tools.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/tools/test_rag.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/tools/test_tools_base.py +0 -0
- {kader-0.1.1 → kader-0.1.3}/tests/tools/test_web.py +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kader
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: kader coding agent
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Requires-Dist: faiss-cpu>=1.9.0
|
|
7
7
|
Requires-Dist: jinja2>=3.1.6
|
|
8
8
|
Requires-Dist: loguru>=0.7.3
|
|
9
9
|
Requires-Dist: ollama>=0.6.1
|
|
10
|
+
Requires-Dist: outdated>=0.2.2
|
|
10
11
|
Requires-Dist: pyyaml>=6.0.3
|
|
11
12
|
Requires-Dist: tenacity>=9.1.2
|
|
12
13
|
Requires-Dist: textual[syntax]>=6.8.0
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import threading
|
|
5
|
+
from importlib.metadata import version as get_version
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Optional
|
|
7
8
|
|
|
@@ -32,9 +33,19 @@ from .utils import (
|
|
|
32
33
|
)
|
|
33
34
|
from .widgets import ConversationView, InlineSelector, LoadingSpinner, ModelSelector
|
|
34
35
|
|
|
35
|
-
WELCOME_MESSAGE = """
|
|
36
|
+
WELCOME_MESSAGE = """
|
|
37
|
+
<div align="center">
|
|
36
38
|
|
|
37
|
-
|
|
39
|
+
```
|
|
40
|
+
██╗ ██╗ ██╗ █████╗ ██████╗ ███████╗██████╗
|
|
41
|
+
██╔╝ ██║ ██╔╝██╔══██╗██╔══██╗██╔════╝██╔══██╗
|
|
42
|
+
██╔╝ █████╔╝ ███████║██║ ██║█████╗ ██████╔╝
|
|
43
|
+
██╔╝ ██╔═██╗ ██╔══██║██║ ██║██╔══╝ ██╔══██╗
|
|
44
|
+
██╔╝ ██║ ██╗██║ ██║██████╔╝███████╗██║ ██║
|
|
45
|
+
╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
</div>
|
|
38
49
|
|
|
39
50
|
Type a message below to start chatting, or use one of the commands:
|
|
40
51
|
|
|
@@ -45,10 +56,16 @@ Type a message below to start chatting, or use one of the commands:
|
|
|
45
56
|
- `/save` - Save current session
|
|
46
57
|
- `/load` - Load a saved session
|
|
47
58
|
- `/sessions` - List saved sessions
|
|
59
|
+
- `/cost` - Show the cost of the conversation
|
|
48
60
|
- `/exit` - Exit the application
|
|
49
61
|
"""
|
|
50
62
|
|
|
51
63
|
|
|
64
|
+
# Minimum terminal size to prevent UI breakage
|
|
65
|
+
MIN_WIDTH = 89
|
|
66
|
+
MIN_HEIGHT = 29
|
|
67
|
+
|
|
68
|
+
|
|
52
69
|
class KaderApp(App):
|
|
53
70
|
"""Main Kader CLI application."""
|
|
54
71
|
|
|
@@ -81,6 +98,7 @@ class KaderApp(App):
|
|
|
81
98
|
self._confirmation_result: tuple[bool, Optional[str]] = (True, None)
|
|
82
99
|
self._inline_selector: Optional[InlineSelector] = None
|
|
83
100
|
self._model_selector: Optional[ModelSelector] = None
|
|
101
|
+
self._update_info: Optional[str] = None # Latest version if update available
|
|
84
102
|
|
|
85
103
|
self._agent = self._create_agent(self._current_model)
|
|
86
104
|
|
|
@@ -291,6 +309,71 @@ class KaderApp(App):
|
|
|
291
309
|
# Focus the input
|
|
292
310
|
self.query_one("#prompt-input", Input).focus()
|
|
293
311
|
|
|
312
|
+
# Check initial size
|
|
313
|
+
self._check_terminal_size()
|
|
314
|
+
|
|
315
|
+
# Start background update check
|
|
316
|
+
threading.Thread(target=self._check_for_updates, daemon=True).start()
|
|
317
|
+
|
|
318
|
+
def _check_for_updates(self) -> None:
|
|
319
|
+
"""Check for package updates in background thread."""
|
|
320
|
+
try:
|
|
321
|
+
from outdated import check_outdated
|
|
322
|
+
|
|
323
|
+
current_version = get_version("kader")
|
|
324
|
+
is_outdated, latest_version = check_outdated("kader", current_version)
|
|
325
|
+
|
|
326
|
+
if is_outdated:
|
|
327
|
+
self._update_info = latest_version
|
|
328
|
+
# Schedule UI update on main thread
|
|
329
|
+
self.call_from_thread(self._show_update_notification)
|
|
330
|
+
except Exception:
|
|
331
|
+
# Silently ignore update check failures
|
|
332
|
+
pass
|
|
333
|
+
|
|
334
|
+
def _show_update_notification(self) -> None:
|
|
335
|
+
"""Show update notification as a toast."""
|
|
336
|
+
if not self._update_info:
|
|
337
|
+
return
|
|
338
|
+
|
|
339
|
+
try:
|
|
340
|
+
current = get_version("kader")
|
|
341
|
+
message = (
|
|
342
|
+
f">> Update available! v{current} → v{self._update_info} "
|
|
343
|
+
f"Run: uv tool upgrade kader"
|
|
344
|
+
)
|
|
345
|
+
self.notify(message, severity="information", timeout=10)
|
|
346
|
+
except Exception:
|
|
347
|
+
pass
|
|
348
|
+
|
|
349
|
+
def on_resize(self) -> None:
|
|
350
|
+
"""Handle terminal resize events."""
|
|
351
|
+
self._check_terminal_size()
|
|
352
|
+
|
|
353
|
+
def _check_terminal_size(self) -> None:
|
|
354
|
+
"""Check if terminal is large enough and show warning if not."""
|
|
355
|
+
width = self.console.size.width
|
|
356
|
+
height = self.console.size.height
|
|
357
|
+
|
|
358
|
+
# Check if we need to show/hide the size warning
|
|
359
|
+
too_small = width < MIN_WIDTH or height < MIN_HEIGHT
|
|
360
|
+
|
|
361
|
+
try:
|
|
362
|
+
warning = self.query_one("#size-warning", Static)
|
|
363
|
+
if not too_small:
|
|
364
|
+
warning.remove()
|
|
365
|
+
except Exception:
|
|
366
|
+
if too_small:
|
|
367
|
+
# Show warning overlay
|
|
368
|
+
warning_text = f"""⚠️ Terminal Too Small
|
|
369
|
+
|
|
370
|
+
Current: {width}x{height}
|
|
371
|
+
Minimum: {MIN_WIDTH}x{MIN_HEIGHT}
|
|
372
|
+
|
|
373
|
+
Please resize your terminal."""
|
|
374
|
+
warning = Static(warning_text, id="size-warning")
|
|
375
|
+
self.mount(warning)
|
|
376
|
+
|
|
294
377
|
async def on_input_submitted(self, event: Input.Submitted) -> None:
|
|
295
378
|
"""Handle user input submission."""
|
|
296
379
|
user_input = event.value.strip()
|
|
@@ -324,6 +407,7 @@ class KaderApp(App):
|
|
|
324
407
|
elif cmd == "/clear":
|
|
325
408
|
conversation.clear_messages()
|
|
326
409
|
self._agent.memory.clear()
|
|
410
|
+
self._agent.provider.reset_tracking() # Reset usage/cost tracking
|
|
327
411
|
self._current_session_id = None
|
|
328
412
|
self.notify("Conversation cleared!", severity="information")
|
|
329
413
|
elif cmd == "/save":
|
|
@@ -342,6 +426,8 @@ class KaderApp(App):
|
|
|
342
426
|
elif cmd == "/refresh":
|
|
343
427
|
self._refresh_directory_tree()
|
|
344
428
|
self.notify("Directory tree refreshed!", severity="information")
|
|
429
|
+
elif cmd == "/cost":
|
|
430
|
+
self._handle_cost(conversation)
|
|
345
431
|
elif cmd == "/exit":
|
|
346
432
|
self.exit()
|
|
347
433
|
else:
|
|
@@ -536,6 +622,42 @@ class KaderApp(App):
|
|
|
536
622
|
conversation.add_message(f"❌ Error listing sessions: {e}", "assistant")
|
|
537
623
|
self.notify(f"Error: {e}", severity="error")
|
|
538
624
|
|
|
625
|
+
def _handle_cost(self, conversation: ConversationView) -> None:
|
|
626
|
+
"""Display LLM usage costs."""
|
|
627
|
+
try:
|
|
628
|
+
# Get cost and usage from the provider
|
|
629
|
+
cost = self._agent.provider.total_cost
|
|
630
|
+
usage = self._agent.provider.total_usage
|
|
631
|
+
model = self._agent.provider.model
|
|
632
|
+
|
|
633
|
+
lines = [
|
|
634
|
+
"## Usage Costs 💰\n",
|
|
635
|
+
f"**Model:** `{model}`\n",
|
|
636
|
+
"### Cost Breakdown",
|
|
637
|
+
"| Type | Amount |",
|
|
638
|
+
"|------|--------|",
|
|
639
|
+
f"| Input Cost | ${cost.input_cost:.6f} |",
|
|
640
|
+
f"| Output Cost | ${cost.output_cost:.6f} |",
|
|
641
|
+
f"| **Total Cost** | **${cost.total_cost:.6f}** |",
|
|
642
|
+
"",
|
|
643
|
+
"### Token Usage",
|
|
644
|
+
"| Type | Tokens |",
|
|
645
|
+
"|------|--------|",
|
|
646
|
+
f"| Prompt Tokens | {usage.prompt_tokens:,} |",
|
|
647
|
+
f"| Completion Tokens | {usage.completion_tokens:,} |",
|
|
648
|
+
f"| **Total Tokens** | **{usage.total_tokens:,}** |",
|
|
649
|
+
]
|
|
650
|
+
|
|
651
|
+
if cost.total_cost == 0.0:
|
|
652
|
+
lines.append(
|
|
653
|
+
"\n> 💡 *Note: Ollama runs locally, so there are no API costs.*"
|
|
654
|
+
)
|
|
655
|
+
|
|
656
|
+
conversation.add_message("\n".join(lines), "assistant")
|
|
657
|
+
except Exception as e:
|
|
658
|
+
conversation.add_message(f"❌ Error getting costs: {e}", "assistant")
|
|
659
|
+
self.notify(f"Error: {e}", severity="error")
|
|
660
|
+
|
|
539
661
|
|
|
540
662
|
def main() -> None:
|
|
541
663
|
"""Run the Kader CLI application."""
|
|
@@ -17,6 +17,23 @@ $text-muted: #6c7086;
|
|
|
17
17
|
|
|
18
18
|
Screen {
|
|
19
19
|
background: $background;
|
|
20
|
+
min-width: 89;
|
|
21
|
+
min-height: 29;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* ===== Size Warning Overlay ===== */
|
|
25
|
+
|
|
26
|
+
#size-warning {
|
|
27
|
+
dock: top;
|
|
28
|
+
width: 100%;
|
|
29
|
+
height: 100%;
|
|
30
|
+
background: $background 95%;
|
|
31
|
+
color: $warning;
|
|
32
|
+
text-align: center;
|
|
33
|
+
content-align: center middle;
|
|
34
|
+
text-style: bold;
|
|
35
|
+
padding: 2;
|
|
36
|
+
layer: overlay;
|
|
20
37
|
}
|
|
21
38
|
|
|
22
39
|
/* ===== Header ===== */
|
|
@@ -19,6 +19,7 @@ HELP_TEXT = """## Kader CLI Commands 📖
|
|
|
19
19
|
| `/save` | Save current session |
|
|
20
20
|
| `/load <id>` | Load a saved session |
|
|
21
21
|
| `/sessions` | List saved sessions |
|
|
22
|
+
| `/cost` | Show usage costs |
|
|
22
23
|
| `/refresh` | Refresh file tree |
|
|
23
24
|
| `/exit` | Exit the CLI |
|
|
24
25
|
|
|
@@ -559,12 +559,13 @@ class BaseAgent:
|
|
|
559
559
|
token_usage["total_tokens"],
|
|
560
560
|
)
|
|
561
561
|
|
|
562
|
+
# estimate the cost...
|
|
563
|
+
estimated_cost = self.provider.estimate_cost(token_usage)
|
|
564
|
+
|
|
562
565
|
# Calculate and log cost
|
|
563
566
|
agent_logger.calculate_cost(
|
|
564
567
|
self.logger_id,
|
|
565
|
-
|
|
566
|
-
token_usage["completion_tokens"],
|
|
567
|
-
getattr(self.provider, "model", ""),
|
|
568
|
+
estimated_cost.total_cost,
|
|
568
569
|
)
|
|
569
570
|
|
|
570
571
|
# Save session update
|
|
@@ -726,12 +727,13 @@ class BaseAgent:
|
|
|
726
727
|
token_usage["total_tokens"],
|
|
727
728
|
)
|
|
728
729
|
|
|
730
|
+
# estimate the cost...
|
|
731
|
+
estimated_cost = self.provider.estimate_cost(token_usage)
|
|
732
|
+
|
|
729
733
|
# Calculate and log cost
|
|
730
734
|
agent_logger.calculate_cost(
|
|
731
735
|
self.logger_id,
|
|
732
|
-
|
|
733
|
-
token_usage["completion_tokens"],
|
|
734
|
-
getattr(self.provider, "model", ""),
|
|
736
|
+
estimated_cost.total_cost,
|
|
735
737
|
)
|
|
736
738
|
|
|
737
739
|
# Save session update
|
|
@@ -99,27 +99,9 @@ class AgentLogger:
|
|
|
99
99
|
def calculate_cost(
|
|
100
100
|
self,
|
|
101
101
|
logger_id: str,
|
|
102
|
-
|
|
103
|
-
completion_tokens: int,
|
|
104
|
-
model_name: str = "",
|
|
105
|
-
pricing_data: Optional[Dict[str, float]] = None,
|
|
102
|
+
total_cost: float,
|
|
106
103
|
):
|
|
107
104
|
"""Calculate and log cost based on token usage."""
|
|
108
|
-
# Use provided pricing data or defaults
|
|
109
|
-
if pricing_data is None:
|
|
110
|
-
# Default pricing (these would come from a model registry in practice)
|
|
111
|
-
pricing_data = {
|
|
112
|
-
"input_cost_per_million": 0.5, # $0.50 per million input tokens
|
|
113
|
-
"output_cost_per_million": 1.5, # $1.50 per million output tokens
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
input_cost = (prompt_tokens / 1_000_000) * pricing_data.get(
|
|
117
|
-
"input_cost_per_million", 0.5
|
|
118
|
-
)
|
|
119
|
-
output_cost = (completion_tokens / 1_000_000) * pricing_data.get(
|
|
120
|
-
"output_cost_per_million", 1.5
|
|
121
|
-
)
|
|
122
|
-
total_cost = input_cost + output_cost
|
|
123
105
|
|
|
124
106
|
self.log_cost(logger_id, total_cost)
|
|
125
107
|
return total_cost
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "kader"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.3"
|
|
4
4
|
description = "kader coding agent"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -14,6 +14,7 @@ dependencies = [
|
|
|
14
14
|
"wcmatch>=10.1",
|
|
15
15
|
"typing-extensions>=4.15.0",
|
|
16
16
|
"jinja2>=3.1.6",
|
|
17
|
+
"outdated>=0.2.2",
|
|
17
18
|
]
|
|
18
19
|
|
|
19
20
|
[project.scripts]
|
|
@@ -183,107 +183,10 @@ class TestAgentLogger:
|
|
|
183
183
|
self.agent_logger.setup_logger("test_agent", "test_session")
|
|
184
184
|
|
|
185
185
|
# Test with default pricing
|
|
186
|
-
cost = self.agent_logger.calculate_cost(
|
|
187
|
-
logger_id,
|
|
188
|
-
prompt_tokens=1_000_000, # 1 million tokens
|
|
189
|
-
completion_tokens=500_000, # 0.5 million tokens
|
|
190
|
-
model_name="",
|
|
191
|
-
pricing_data=None,
|
|
192
|
-
)
|
|
186
|
+
cost = self.agent_logger.calculate_cost(logger_id, total_cost=0.5)
|
|
193
187
|
|
|
194
188
|
# Default pricing: input_cost_per_million = 0.5, output_cost_per_million = 1.5
|
|
195
|
-
expected_cost =
|
|
196
|
-
assert cost == expected_cost
|
|
197
|
-
|
|
198
|
-
def test_calculate_cost_with_custom_pricing(self):
|
|
199
|
-
"""Test cost calculation with custom pricing data."""
|
|
200
|
-
logger_id = "test_agent_test_session"
|
|
201
|
-
|
|
202
|
-
# Setup logger first
|
|
203
|
-
with patch("kader.agent.logger.Path") as mock_path:
|
|
204
|
-
mock_logs_dir = MagicMock()
|
|
205
|
-
mock_path.return_value = mock_logs_dir
|
|
206
|
-
mock_logs_dir.__truediv__.return_value = mock_logs_dir
|
|
207
|
-
mock_logs_dir.mkdir.return_value = None
|
|
208
|
-
mock_log_file_path = MagicMock()
|
|
209
|
-
mock_logs_dir.__truediv__.return_value = mock_log_file_path
|
|
210
|
-
|
|
211
|
-
with patch("kader.agent.logger.logger") as mock_logger:
|
|
212
|
-
mock_bound_logger = MagicMock()
|
|
213
|
-
mock_logger.bind.return_value = mock_bound_logger
|
|
214
|
-
mock_bound_logger.add.return_value = 1 # handler ID
|
|
215
|
-
|
|
216
|
-
# Setup the logger
|
|
217
|
-
self.agent_logger.setup_logger("test_agent", "test_session")
|
|
218
|
-
|
|
219
|
-
# Test with custom pricing
|
|
220
|
-
custom_pricing = {
|
|
221
|
-
"input_cost_per_million": 0.1, # $0.10 per million input tokens
|
|
222
|
-
"output_cost_per_million": 0.2, # $0.20 per million output tokens
|
|
223
|
-
}
|
|
224
|
-
cost = self.agent_logger.calculate_cost(
|
|
225
|
-
logger_id,
|
|
226
|
-
prompt_tokens=1_000_000,
|
|
227
|
-
completion_tokens=1_000_000,
|
|
228
|
-
model_name="",
|
|
229
|
-
pricing_data=custom_pricing,
|
|
230
|
-
)
|
|
231
|
-
|
|
232
|
-
expected_cost = (1.0 * 0.1) + (1.0 * 0.2) # 0.1 + 0.2 = 0.3
|
|
233
|
-
assert cost == expected_cost
|
|
234
|
-
|
|
235
|
-
def test_calculate_cost_edge_cases(self):
|
|
236
|
-
"""Test cost calculation with edge cases."""
|
|
237
|
-
logger_id = "test_agent_test_session"
|
|
238
|
-
|
|
239
|
-
# Setup logger first
|
|
240
|
-
with patch("kader.agent.logger.Path") as mock_path:
|
|
241
|
-
mock_logs_dir = MagicMock()
|
|
242
|
-
mock_path.return_value = mock_logs_dir
|
|
243
|
-
mock_logs_dir.__truediv__.return_value = mock_logs_dir
|
|
244
|
-
mock_logs_dir.mkdir.return_value = None
|
|
245
|
-
mock_log_file_path = MagicMock()
|
|
246
|
-
mock_logs_dir.__truediv__.return_value = mock_log_file_path
|
|
247
|
-
|
|
248
|
-
with patch("kader.agent.logger.logger") as mock_logger:
|
|
249
|
-
mock_bound_logger = MagicMock()
|
|
250
|
-
mock_logger.bind.return_value = mock_bound_logger
|
|
251
|
-
mock_bound_logger.add.return_value = 1 # handler ID
|
|
252
|
-
|
|
253
|
-
# Setup the logger
|
|
254
|
-
self.agent_logger.setup_logger("test_agent", "test_session")
|
|
255
|
-
|
|
256
|
-
# Test with zero tokens
|
|
257
|
-
cost = self.agent_logger.calculate_cost(
|
|
258
|
-
logger_id,
|
|
259
|
-
prompt_tokens=0,
|
|
260
|
-
completion_tokens=0,
|
|
261
|
-
model_name="",
|
|
262
|
-
pricing_data=None,
|
|
263
|
-
)
|
|
264
|
-
assert cost == 0.0
|
|
265
|
-
|
|
266
|
-
# Test with very large token counts
|
|
267
|
-
cost = self.agent_logger.calculate_cost(
|
|
268
|
-
logger_id,
|
|
269
|
-
prompt_tokens=1_000_000_000, # 1B tokens
|
|
270
|
-
completion_tokens=500_000_000, # 500M tokens
|
|
271
|
-
model_name="",
|
|
272
|
-
pricing_data=None,
|
|
273
|
-
)
|
|
274
|
-
expected_cost = (1000.0 * 0.5) + (500.0 * 1.5) # 500 + 750 = 1250.0
|
|
275
|
-
assert cost == expected_cost
|
|
276
|
-
|
|
277
|
-
# Test with negative tokens (should be treated as negative cost)
|
|
278
|
-
cost = self.agent_logger.calculate_cost(
|
|
279
|
-
logger_id,
|
|
280
|
-
prompt_tokens=-100_000,
|
|
281
|
-
completion_tokens=-50_000,
|
|
282
|
-
model_name="",
|
|
283
|
-
pricing_data=None,
|
|
284
|
-
)
|
|
285
|
-
# For negative values, the calculation would give negative cost
|
|
286
|
-
expected_cost = (-0.1 * 0.5) + (-0.05 * 1.5) # -0.05 + -0.075 = -0.125
|
|
189
|
+
expected_cost = 0.5
|
|
287
190
|
assert cost == expected_cost
|
|
288
191
|
|
|
289
192
|
def test_log_llm_response(self):
|
|
@@ -194,6 +194,79 @@ wheels = [
|
|
|
194
194
|
{ url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" },
|
|
195
195
|
]
|
|
196
196
|
|
|
197
|
+
[[package]]
|
|
198
|
+
name = "charset-normalizer"
|
|
199
|
+
version = "3.4.4"
|
|
200
|
+
source = { registry = "https://pypi.org/simple" }
|
|
201
|
+
sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" }
|
|
202
|
+
wheels = [
|
|
203
|
+
{ url = "https://files.pythonhosted.org/packages/ed/27/c6491ff4954e58a10f69ad90aca8a1b6fe9c5d3c6f380907af3c37435b59/charset_normalizer-3.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e1fcf0720908f200cd21aa4e6750a48ff6ce4afe7ff5a79a90d5ed8a08296f8", size = 206988, upload-time = "2025-10-14T04:40:33.79Z" },
|
|
204
|
+
{ url = "https://files.pythonhosted.org/packages/94/59/2e87300fe67ab820b5428580a53cad894272dbb97f38a7a814a2a1ac1011/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f819d5fe9234f9f82d75bdfa9aef3a3d72c4d24a6e57aeaebba32a704553aa0", size = 147324, upload-time = "2025-10-14T04:40:34.961Z" },
|
|
205
|
+
{ url = "https://files.pythonhosted.org/packages/07/fb/0cf61dc84b2b088391830f6274cb57c82e4da8bbc2efeac8c025edb88772/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a59cb51917aa591b1c4e6a43c132f0cdc3c76dbad6155df4e28ee626cc77a0a3", size = 142742, upload-time = "2025-10-14T04:40:36.105Z" },
|
|
206
|
+
{ url = "https://files.pythonhosted.org/packages/62/8b/171935adf2312cd745d290ed93cf16cf0dfe320863ab7cbeeae1dcd6535f/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8ef3c867360f88ac904fd3f5e1f902f13307af9052646963ee08ff4f131adafc", size = 160863, upload-time = "2025-10-14T04:40:37.188Z" },
|
|
207
|
+
{ url = "https://files.pythonhosted.org/packages/09/73/ad875b192bda14f2173bfc1bc9a55e009808484a4b256748d931b6948442/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d9e45d7faa48ee908174d8fe84854479ef838fc6a705c9315372eacbc2f02897", size = 157837, upload-time = "2025-10-14T04:40:38.435Z" },
|
|
208
|
+
{ url = "https://files.pythonhosted.org/packages/6d/fc/de9cce525b2c5b94b47c70a4b4fb19f871b24995c728e957ee68ab1671ea/charset_normalizer-3.4.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:840c25fb618a231545cbab0564a799f101b63b9901f2569faecd6b222ac72381", size = 151550, upload-time = "2025-10-14T04:40:40.053Z" },
|
|
209
|
+
{ url = "https://files.pythonhosted.org/packages/55/c2/43edd615fdfba8c6f2dfbd459b25a6b3b551f24ea21981e23fb768503ce1/charset_normalizer-3.4.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ca5862d5b3928c4940729dacc329aa9102900382fea192fc5e52eb69d6093815", size = 149162, upload-time = "2025-10-14T04:40:41.163Z" },
|
|
210
|
+
{ url = "https://files.pythonhosted.org/packages/03/86/bde4ad8b4d0e9429a4e82c1e8f5c659993a9a863ad62c7df05cf7b678d75/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9c7f57c3d666a53421049053eaacdd14bbd0a528e2186fcb2e672effd053bb0", size = 150019, upload-time = "2025-10-14T04:40:42.276Z" },
|
|
211
|
+
{ url = "https://files.pythonhosted.org/packages/1f/86/a151eb2af293a7e7bac3a739b81072585ce36ccfb4493039f49f1d3cae8c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:277e970e750505ed74c832b4bf75dac7476262ee2a013f5574dd49075879e161", size = 143310, upload-time = "2025-10-14T04:40:43.439Z" },
|
|
212
|
+
{ url = "https://files.pythonhosted.org/packages/b5/fe/43dae6144a7e07b87478fdfc4dbe9efd5defb0e7ec29f5f58a55aeef7bf7/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:31fd66405eaf47bb62e8cd575dc621c56c668f27d46a61d975a249930dd5e2a4", size = 162022, upload-time = "2025-10-14T04:40:44.547Z" },
|
|
213
|
+
{ url = "https://files.pythonhosted.org/packages/80/e6/7aab83774f5d2bca81f42ac58d04caf44f0cc2b65fc6db2b3b2e8a05f3b3/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:0d3d8f15c07f86e9ff82319b3d9ef6f4bf907608f53fe9d92b28ea9ae3d1fd89", size = 149383, upload-time = "2025-10-14T04:40:46.018Z" },
|
|
214
|
+
{ url = "https://files.pythonhosted.org/packages/4f/e8/b289173b4edae05c0dde07f69f8db476a0b511eac556dfe0d6bda3c43384/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9f7fcd74d410a36883701fafa2482a6af2ff5ba96b9a620e9e0721e28ead5569", size = 159098, upload-time = "2025-10-14T04:40:47.081Z" },
|
|
215
|
+
{ url = "https://files.pythonhosted.org/packages/d8/df/fe699727754cae3f8478493c7f45f777b17c3ef0600e28abfec8619eb49c/charset_normalizer-3.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ebf3e58c7ec8a8bed6d66a75d7fb37b55e5015b03ceae72a8e7c74495551e224", size = 152991, upload-time = "2025-10-14T04:40:48.246Z" },
|
|
216
|
+
{ url = "https://files.pythonhosted.org/packages/1a/86/584869fe4ddb6ffa3bd9f491b87a01568797fb9bd8933f557dba9771beaf/charset_normalizer-3.4.4-cp311-cp311-win32.whl", hash = "sha256:eecbc200c7fd5ddb9a7f16c7decb07b566c29fa2161a16cf67b8d068bd21690a", size = 99456, upload-time = "2025-10-14T04:40:49.376Z" },
|
|
217
|
+
{ url = "https://files.pythonhosted.org/packages/65/f6/62fdd5feb60530f50f7e38b4f6a1d5203f4d16ff4f9f0952962c044e919a/charset_normalizer-3.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:5ae497466c7901d54b639cf42d5b8c1b6a4fead55215500d2f486d34db48d016", size = 106978, upload-time = "2025-10-14T04:40:50.844Z" },
|
|
218
|
+
{ url = "https://files.pythonhosted.org/packages/7a/9d/0710916e6c82948b3be62d9d398cb4fcf4e97b56d6a6aeccd66c4b2f2bd5/charset_normalizer-3.4.4-cp311-cp311-win_arm64.whl", hash = "sha256:65e2befcd84bc6f37095f5961e68a6f077bf44946771354a28ad434c2cce0ae1", size = 99969, upload-time = "2025-10-14T04:40:52.272Z" },
|
|
219
|
+
{ url = "https://files.pythonhosted.org/packages/f3/85/1637cd4af66fa687396e757dec650f28025f2a2f5a5531a3208dc0ec43f2/charset_normalizer-3.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0a98e6759f854bd25a58a73fa88833fba3b7c491169f86ce1180c948ab3fd394", size = 208425, upload-time = "2025-10-14T04:40:53.353Z" },
|
|
220
|
+
{ url = "https://files.pythonhosted.org/packages/9d/6a/04130023fef2a0d9c62d0bae2649b69f7b7d8d24ea5536feef50551029df/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b5b290ccc2a263e8d185130284f8501e3e36c5e02750fc6b6bdeb2e9e96f1e25", size = 148162, upload-time = "2025-10-14T04:40:54.558Z" },
|
|
221
|
+
{ url = "https://files.pythonhosted.org/packages/78/29/62328d79aa60da22c9e0b9a66539feae06ca0f5a4171ac4f7dc285b83688/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74bb723680f9f7a6234dcf67aea57e708ec1fbdf5699fb91dfd6f511b0a320ef", size = 144558, upload-time = "2025-10-14T04:40:55.677Z" },
|
|
222
|
+
{ url = "https://files.pythonhosted.org/packages/86/bb/b32194a4bf15b88403537c2e120b817c61cd4ecffa9b6876e941c3ee38fe/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f1e34719c6ed0b92f418c7c780480b26b5d9c50349e9a9af7d76bf757530350d", size = 161497, upload-time = "2025-10-14T04:40:57.217Z" },
|
|
223
|
+
{ url = "https://files.pythonhosted.org/packages/19/89/a54c82b253d5b9b111dc74aca196ba5ccfcca8242d0fb64146d4d3183ff1/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2437418e20515acec67d86e12bf70056a33abdacb5cb1655042f6538d6b085a8", size = 159240, upload-time = "2025-10-14T04:40:58.358Z" },
|
|
224
|
+
{ url = "https://files.pythonhosted.org/packages/c0/10/d20b513afe03acc89ec33948320a5544d31f21b05368436d580dec4e234d/charset_normalizer-3.4.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:11d694519d7f29d6cd09f6ac70028dba10f92f6cdd059096db198c283794ac86", size = 153471, upload-time = "2025-10-14T04:40:59.468Z" },
|
|
225
|
+
{ url = "https://files.pythonhosted.org/packages/61/fa/fbf177b55bdd727010f9c0a3c49eefa1d10f960e5f09d1d887bf93c2e698/charset_normalizer-3.4.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ac1c4a689edcc530fc9d9aa11f5774b9e2f33f9a0c6a57864e90908f5208d30a", size = 150864, upload-time = "2025-10-14T04:41:00.623Z" },
|
|
226
|
+
{ url = "https://files.pythonhosted.org/packages/05/12/9fbc6a4d39c0198adeebbde20b619790e9236557ca59fc40e0e3cebe6f40/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:21d142cc6c0ec30d2efee5068ca36c128a30b0f2c53c1c07bd78cb6bc1d3be5f", size = 150647, upload-time = "2025-10-14T04:41:01.754Z" },
|
|
227
|
+
{ url = "https://files.pythonhosted.org/packages/ad/1f/6a9a593d52e3e8c5d2b167daf8c6b968808efb57ef4c210acb907c365bc4/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:5dbe56a36425d26d6cfb40ce79c314a2e4dd6211d51d6d2191c00bed34f354cc", size = 145110, upload-time = "2025-10-14T04:41:03.231Z" },
|
|
228
|
+
{ url = "https://files.pythonhosted.org/packages/30/42/9a52c609e72471b0fc54386dc63c3781a387bb4fe61c20231a4ebcd58bdd/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5bfbb1b9acf3334612667b61bd3002196fe2a1eb4dd74d247e0f2a4d50ec9bbf", size = 162839, upload-time = "2025-10-14T04:41:04.715Z" },
|
|
229
|
+
{ url = "https://files.pythonhosted.org/packages/c4/5b/c0682bbf9f11597073052628ddd38344a3d673fda35a36773f7d19344b23/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d055ec1e26e441f6187acf818b73564e6e6282709e9bcb5b63f5b23068356a15", size = 150667, upload-time = "2025-10-14T04:41:05.827Z" },
|
|
230
|
+
{ url = "https://files.pythonhosted.org/packages/e4/24/a41afeab6f990cf2daf6cb8c67419b63b48cf518e4f56022230840c9bfb2/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:af2d8c67d8e573d6de5bc30cdb27e9b95e49115cd9baad5ddbd1a6207aaa82a9", size = 160535, upload-time = "2025-10-14T04:41:06.938Z" },
|
|
231
|
+
{ url = "https://files.pythonhosted.org/packages/2a/e5/6a4ce77ed243c4a50a1fecca6aaaab419628c818a49434be428fe24c9957/charset_normalizer-3.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:780236ac706e66881f3b7f2f32dfe90507a09e67d1d454c762cf642e6e1586e0", size = 154816, upload-time = "2025-10-14T04:41:08.101Z" },
|
|
232
|
+
{ url = "https://files.pythonhosted.org/packages/a8/ef/89297262b8092b312d29cdb2517cb1237e51db8ecef2e9af5edbe7b683b1/charset_normalizer-3.4.4-cp312-cp312-win32.whl", hash = "sha256:5833d2c39d8896e4e19b689ffc198f08ea58116bee26dea51e362ecc7cd3ed26", size = 99694, upload-time = "2025-10-14T04:41:09.23Z" },
|
|
233
|
+
{ url = "https://files.pythonhosted.org/packages/3d/2d/1e5ed9dd3b3803994c155cd9aacb60c82c331bad84daf75bcb9c91b3295e/charset_normalizer-3.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:a79cfe37875f822425b89a82333404539ae63dbdddf97f84dcbc3d339aae9525", size = 107131, upload-time = "2025-10-14T04:41:10.467Z" },
|
|
234
|
+
{ url = "https://files.pythonhosted.org/packages/d0/d9/0ed4c7098a861482a7b6a95603edce4c0d9db2311af23da1fb2b75ec26fc/charset_normalizer-3.4.4-cp312-cp312-win_arm64.whl", hash = "sha256:376bec83a63b8021bb5c8ea75e21c4ccb86e7e45ca4eb81146091b56599b80c3", size = 100390, upload-time = "2025-10-14T04:41:11.915Z" },
|
|
235
|
+
{ url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" },
|
|
236
|
+
{ url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" },
|
|
237
|
+
{ url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" },
|
|
238
|
+
{ url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" },
|
|
239
|
+
{ url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" },
|
|
240
|
+
{ url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" },
|
|
241
|
+
{ url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" },
|
|
242
|
+
{ url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" },
|
|
243
|
+
{ url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" },
|
|
244
|
+
{ url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" },
|
|
245
|
+
{ url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" },
|
|
246
|
+
{ url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" },
|
|
247
|
+
{ url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" },
|
|
248
|
+
{ url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" },
|
|
249
|
+
{ url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" },
|
|
250
|
+
{ url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" },
|
|
251
|
+
{ url = "https://files.pythonhosted.org/packages/2a/35/7051599bd493e62411d6ede36fd5af83a38f37c4767b92884df7301db25d/charset_normalizer-3.4.4-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:da3326d9e65ef63a817ecbcc0df6e94463713b754fe293eaa03da99befb9a5bd", size = 207746, upload-time = "2025-10-14T04:41:33.773Z" },
|
|
252
|
+
{ url = "https://files.pythonhosted.org/packages/10/9a/97c8d48ef10d6cd4fcead2415523221624bf58bcf68a802721a6bc807c8f/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8af65f14dc14a79b924524b1e7fffe304517b2bff5a58bf64f30b98bbc5079eb", size = 147889, upload-time = "2025-10-14T04:41:34.897Z" },
|
|
253
|
+
{ url = "https://files.pythonhosted.org/packages/10/bf/979224a919a1b606c82bd2c5fa49b5c6d5727aa47b4312bb27b1734f53cd/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:74664978bb272435107de04e36db5a9735e78232b85b77d45cfb38f758efd33e", size = 143641, upload-time = "2025-10-14T04:41:36.116Z" },
|
|
254
|
+
{ url = "https://files.pythonhosted.org/packages/ba/33/0ad65587441fc730dc7bd90e9716b30b4702dc7b617e6ba4997dc8651495/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:752944c7ffbfdd10c074dc58ec2d5a8a4cd9493b314d367c14d24c17684ddd14", size = 160779, upload-time = "2025-10-14T04:41:37.229Z" },
|
|
255
|
+
{ url = "https://files.pythonhosted.org/packages/67/ed/331d6b249259ee71ddea93f6f2f0a56cfebd46938bde6fcc6f7b9a3d0e09/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d1f13550535ad8cff21b8d757a3257963e951d96e20ec82ab44bc64aeb62a191", size = 159035, upload-time = "2025-10-14T04:41:38.368Z" },
|
|
256
|
+
{ url = "https://files.pythonhosted.org/packages/67/ff/f6b948ca32e4f2a4576aa129d8bed61f2e0543bf9f5f2b7fc3758ed005c9/charset_normalizer-3.4.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecaae4149d99b1c9e7b88bb03e3221956f68fd6d50be2ef061b2381b61d20838", size = 152542, upload-time = "2025-10-14T04:41:39.862Z" },
|
|
257
|
+
{ url = "https://files.pythonhosted.org/packages/16/85/276033dcbcc369eb176594de22728541a925b2632f9716428c851b149e83/charset_normalizer-3.4.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb6254dc36b47a990e59e1068afacdcd02958bdcce30bb50cc1700a8b9d624a6", size = 149524, upload-time = "2025-10-14T04:41:41.319Z" },
|
|
258
|
+
{ url = "https://files.pythonhosted.org/packages/9e/f2/6a2a1f722b6aba37050e626530a46a68f74e63683947a8acff92569f979a/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c8ae8a0f02f57a6e61203a31428fa1d677cbe50c93622b4149d5c0f319c1d19e", size = 150395, upload-time = "2025-10-14T04:41:42.539Z" },
|
|
259
|
+
{ url = "https://files.pythonhosted.org/packages/60/bb/2186cb2f2bbaea6338cad15ce23a67f9b0672929744381e28b0592676824/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:47cc91b2f4dd2833fddaedd2893006b0106129d4b94fdb6af1f4ce5a9965577c", size = 143680, upload-time = "2025-10-14T04:41:43.661Z" },
|
|
260
|
+
{ url = "https://files.pythonhosted.org/packages/7d/a5/bf6f13b772fbb2a90360eb620d52ed8f796f3c5caee8398c3b2eb7b1c60d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:82004af6c302b5d3ab2cfc4cc5f29db16123b1a8417f2e25f9066f91d4411090", size = 162045, upload-time = "2025-10-14T04:41:44.821Z" },
|
|
261
|
+
{ url = "https://files.pythonhosted.org/packages/df/c5/d1be898bf0dc3ef9030c3825e5d3b83f2c528d207d246cbabe245966808d/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7d8f6c26245217bd2ad053761201e9f9680f8ce52f0fcd8d0755aeae5b2152", size = 149687, upload-time = "2025-10-14T04:41:46.442Z" },
|
|
262
|
+
{ url = "https://files.pythonhosted.org/packages/a5/42/90c1f7b9341eef50c8a1cb3f098ac43b0508413f33affd762855f67a410e/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:799a7a5e4fb2d5898c60b640fd4981d6a25f1c11790935a44ce38c54e985f828", size = 160014, upload-time = "2025-10-14T04:41:47.631Z" },
|
|
263
|
+
{ url = "https://files.pythonhosted.org/packages/76/be/4d3ee471e8145d12795ab655ece37baed0929462a86e72372fd25859047c/charset_normalizer-3.4.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:99ae2cffebb06e6c22bdc25801d7b30f503cc87dbd283479e7b606f70aff57ec", size = 154044, upload-time = "2025-10-14T04:41:48.81Z" },
|
|
264
|
+
{ url = "https://files.pythonhosted.org/packages/b0/6f/8f7af07237c34a1defe7defc565a9bc1807762f672c0fde711a4b22bf9c0/charset_normalizer-3.4.4-cp314-cp314-win32.whl", hash = "sha256:f9d332f8c2a2fcbffe1378594431458ddbef721c1769d78e2cbc06280d8155f9", size = 99940, upload-time = "2025-10-14T04:41:49.946Z" },
|
|
265
|
+
{ url = "https://files.pythonhosted.org/packages/4b/51/8ade005e5ca5b0d80fb4aff72a3775b325bdc3d27408c8113811a7cbe640/charset_normalizer-3.4.4-cp314-cp314-win_amd64.whl", hash = "sha256:8a6562c3700cce886c5be75ade4a5db4214fda19fede41d9792d100288d8f94c", size = 107104, upload-time = "2025-10-14T04:41:51.051Z" },
|
|
266
|
+
{ url = "https://files.pythonhosted.org/packages/da/5f/6b8f83a55bb8278772c5ae54a577f3099025f9ade59d0136ac24a0df4bde/charset_normalizer-3.4.4-cp314-cp314-win_arm64.whl", hash = "sha256:de00632ca48df9daf77a2c65a484531649261ec9f25489917f09e455cb09ddb2", size = 100743, upload-time = "2025-10-14T04:41:52.122Z" },
|
|
267
|
+
{ url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" },
|
|
268
|
+
]
|
|
269
|
+
|
|
197
270
|
[[package]]
|
|
198
271
|
name = "click"
|
|
199
272
|
version = "8.3.1"
|
|
@@ -414,13 +487,14 @@ wheels = [
|
|
|
414
487
|
|
|
415
488
|
[[package]]
|
|
416
489
|
name = "kader"
|
|
417
|
-
version = "0.1.
|
|
490
|
+
version = "0.1.3"
|
|
418
491
|
source = { editable = "." }
|
|
419
492
|
dependencies = [
|
|
420
493
|
{ name = "faiss-cpu" },
|
|
421
494
|
{ name = "jinja2" },
|
|
422
495
|
{ name = "loguru" },
|
|
423
496
|
{ name = "ollama" },
|
|
497
|
+
{ name = "outdated" },
|
|
424
498
|
{ name = "pyyaml" },
|
|
425
499
|
{ name = "tenacity" },
|
|
426
500
|
{ name = "textual", extra = ["syntax"] },
|
|
@@ -442,6 +516,7 @@ requires-dist = [
|
|
|
442
516
|
{ name = "jinja2", specifier = ">=3.1.6" },
|
|
443
517
|
{ name = "loguru", specifier = ">=0.7.3" },
|
|
444
518
|
{ name = "ollama", specifier = ">=0.6.1" },
|
|
519
|
+
{ name = "outdated", specifier = ">=0.2.2" },
|
|
445
520
|
{ name = "pyyaml", specifier = ">=6.0.3" },
|
|
446
521
|
{ name = "tenacity", specifier = ">=9.1.2" },
|
|
447
522
|
{ name = "textual", extras = ["syntax"], specifier = ">=6.8.0" },
|
|
@@ -469,6 +544,15 @@ wheels = [
|
|
|
469
544
|
{ url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79", size = 19820, upload-time = "2024-02-04T14:48:02.496Z" },
|
|
470
545
|
]
|
|
471
546
|
|
|
547
|
+
[[package]]
|
|
548
|
+
name = "littleutils"
|
|
549
|
+
version = "0.2.4"
|
|
550
|
+
source = { registry = "https://pypi.org/simple" }
|
|
551
|
+
sdist = { url = "https://files.pythonhosted.org/packages/01/f0/ddc72338ed9365ced4b109d8b6233b6689d28f41f1e2a4d97fd8c1eb3da9/littleutils-0.2.4.tar.gz", hash = "sha256:c7835b01020ced42e291118b7d78fb16bc2d9a1b4f3f42f3cb3787bb4da53d19", size = 9526, upload-time = "2024-07-07T22:04:35.844Z" }
|
|
552
|
+
wheels = [
|
|
553
|
+
{ url = "https://files.pythonhosted.org/packages/19/ac/a89d28d7421fffc028d68cdfde5e3e056e690cb4b1bbef4a5fea661e16f5/littleutils-0.2.4-py3-none-any.whl", hash = "sha256:d10d5fe2e107c49fe2fc2904a08d6e5a302b41f8405921835ffcc323782d5dbc", size = 8145, upload-time = "2024-07-07T22:04:34.24Z" },
|
|
554
|
+
]
|
|
555
|
+
|
|
472
556
|
[[package]]
|
|
473
557
|
name = "loguru"
|
|
474
558
|
version = "0.7.3"
|
|
@@ -856,6 +940,20 @@ wheels = [
|
|
|
856
940
|
{ url = "https://files.pythonhosted.org/packages/47/4f/4a617ee93d8208d2bcf26b2d8b9402ceaed03e3853c754940e2290fed063/ollama-0.6.1-py3-none-any.whl", hash = "sha256:fc4c984b345735c5486faeee67d8a265214a31cbb828167782dc642ce0a2bf8c", size = 14354, upload-time = "2025-11-13T23:02:16.292Z" },
|
|
857
941
|
]
|
|
858
942
|
|
|
943
|
+
[[package]]
|
|
944
|
+
name = "outdated"
|
|
945
|
+
version = "0.2.2"
|
|
946
|
+
source = { registry = "https://pypi.org/simple" }
|
|
947
|
+
dependencies = [
|
|
948
|
+
{ name = "littleutils" },
|
|
949
|
+
{ name = "requests" },
|
|
950
|
+
{ name = "setuptools" },
|
|
951
|
+
]
|
|
952
|
+
sdist = { url = "https://files.pythonhosted.org/packages/e9/43/ac45b6c53fc62c99f02dbc310939d8693aa76cdf9900afe74a60febc8266/outdated-0.2.2.tar.gz", hash = "sha256:4b7fdec88e36711120d096d485fc4d5035e4e5ffbd907cf3a6ce2af43058b970", size = 9325, upload-time = "2022-10-29T10:14:01.847Z" }
|
|
953
|
+
wheels = [
|
|
954
|
+
{ url = "https://files.pythonhosted.org/packages/d3/04/7d2b9a0d1b81e30f39e6f358bac01f4f18b585f35b0ffc5c83fc274f146b/outdated-0.2.2-py2.py3-none-any.whl", hash = "sha256:3e9c2ee6d17e86ae8cc7bb71d70c4172690121cda367155a30994742172678c8", size = 7543, upload-time = "2022-10-29T10:13:59.919Z" },
|
|
955
|
+
]
|
|
956
|
+
|
|
859
957
|
[[package]]
|
|
860
958
|
name = "packaging"
|
|
861
959
|
version = "25.0"
|
|
@@ -1187,6 +1285,21 @@ wheels = [
|
|
|
1187
1285
|
{ url = "https://files.pythonhosted.org/packages/f1/12/de94a39c2ef588c7e6455cfbe7343d3b2dc9d6b6b2f40c4c6565744c873d/pyyaml-6.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ebc55a14a21cb14062aa4162f906cd962b28e2e9ea38f9b4391244cd8de4ae0b", size = 149341, upload-time = "2025-09-25T21:32:56.828Z" },
|
|
1188
1286
|
]
|
|
1189
1287
|
|
|
1288
|
+
[[package]]
|
|
1289
|
+
name = "requests"
|
|
1290
|
+
version = "2.32.5"
|
|
1291
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1292
|
+
dependencies = [
|
|
1293
|
+
{ name = "certifi" },
|
|
1294
|
+
{ name = "charset-normalizer" },
|
|
1295
|
+
{ name = "idna" },
|
|
1296
|
+
{ name = "urllib3" },
|
|
1297
|
+
]
|
|
1298
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" }
|
|
1299
|
+
wheels = [
|
|
1300
|
+
{ url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" },
|
|
1301
|
+
]
|
|
1302
|
+
|
|
1190
1303
|
[[package]]
|
|
1191
1304
|
name = "rich"
|
|
1192
1305
|
version = "14.2.0"
|
|
@@ -1226,6 +1339,15 @@ wheels = [
|
|
|
1226
1339
|
{ url = "https://files.pythonhosted.org/packages/74/31/b0e29d572670dca3674eeee78e418f20bdf97fa8aa9ea71380885e175ca0/ruff-0.14.10-py3-none-win_arm64.whl", hash = "sha256:e51d046cf6dda98a4633b8a8a771451107413b0f07183b2bef03f075599e44e6", size = 13729839, upload-time = "2025-12-18T19:28:48.636Z" },
|
|
1227
1340
|
]
|
|
1228
1341
|
|
|
1342
|
+
[[package]]
|
|
1343
|
+
name = "setuptools"
|
|
1344
|
+
version = "80.9.0"
|
|
1345
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1346
|
+
sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" }
|
|
1347
|
+
wheels = [
|
|
1348
|
+
{ url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" },
|
|
1349
|
+
]
|
|
1350
|
+
|
|
1229
1351
|
[[package]]
|
|
1230
1352
|
name = "tenacity"
|
|
1231
1353
|
version = "9.1.2"
|
|
@@ -1605,6 +1727,15 @@ wheels = [
|
|
|
1605
1727
|
{ url = "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5", size = 6229, upload-time = "2024-02-09T16:52:00.371Z" },
|
|
1606
1728
|
]
|
|
1607
1729
|
|
|
1730
|
+
[[package]]
|
|
1731
|
+
name = "urllib3"
|
|
1732
|
+
version = "2.6.3"
|
|
1733
|
+
source = { registry = "https://pypi.org/simple" }
|
|
1734
|
+
sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" }
|
|
1735
|
+
wheels = [
|
|
1736
|
+
{ url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" },
|
|
1737
|
+
]
|
|
1738
|
+
|
|
1608
1739
|
[[package]]
|
|
1609
1740
|
name = "wcmatch"
|
|
1610
1741
|
version = "10.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|