python-infrakit-dev 0.1.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.
Files changed (51) hide show
  1. infrakit/__init__.py +0 -0
  2. infrakit/cli/__init__.py +1 -0
  3. infrakit/cli/commands/__init__.py +1 -0
  4. infrakit/cli/commands/deps.py +530 -0
  5. infrakit/cli/commands/init.py +129 -0
  6. infrakit/cli/commands/llm.py +295 -0
  7. infrakit/cli/commands/logger.py +160 -0
  8. infrakit/cli/commands/module.py +342 -0
  9. infrakit/cli/commands/time.py +81 -0
  10. infrakit/cli/main.py +65 -0
  11. infrakit/core/__init__.py +0 -0
  12. infrakit/core/config/__init__.py +0 -0
  13. infrakit/core/config/converter.py +480 -0
  14. infrakit/core/config/exporter.py +304 -0
  15. infrakit/core/config/loader.py +713 -0
  16. infrakit/core/config/validator.py +389 -0
  17. infrakit/core/logger/__init__.py +21 -0
  18. infrakit/core/logger/formatters.py +143 -0
  19. infrakit/core/logger/handlers.py +322 -0
  20. infrakit/core/logger/retention.py +176 -0
  21. infrakit/core/logger/setup.py +314 -0
  22. infrakit/deps/__init__.py +239 -0
  23. infrakit/deps/clean.py +141 -0
  24. infrakit/deps/depfile.py +405 -0
  25. infrakit/deps/health.py +357 -0
  26. infrakit/deps/optimizer.py +642 -0
  27. infrakit/deps/scanner.py +550 -0
  28. infrakit/llm/__init__.py +35 -0
  29. infrakit/llm/batch.py +165 -0
  30. infrakit/llm/client.py +575 -0
  31. infrakit/llm/key_manager.py +728 -0
  32. infrakit/llm/llm_readme.md +306 -0
  33. infrakit/llm/models.py +148 -0
  34. infrakit/llm/providers/__init__.py +5 -0
  35. infrakit/llm/providers/base.py +112 -0
  36. infrakit/llm/providers/gemini.py +164 -0
  37. infrakit/llm/providers/openai.py +168 -0
  38. infrakit/llm/rate_limiter.py +54 -0
  39. infrakit/scaffolder/__init__.py +31 -0
  40. infrakit/scaffolder/ai.py +508 -0
  41. infrakit/scaffolder/backend.py +555 -0
  42. infrakit/scaffolder/cli_tool.py +386 -0
  43. infrakit/scaffolder/generator.py +338 -0
  44. infrakit/scaffolder/pipeline.py +562 -0
  45. infrakit/scaffolder/registry.py +121 -0
  46. infrakit/time/__init__.py +60 -0
  47. infrakit/time/profiler.py +511 -0
  48. python_infrakit_dev-0.1.0.dist-info/METADATA +124 -0
  49. python_infrakit_dev-0.1.0.dist-info/RECORD +51 -0
  50. python_infrakit_dev-0.1.0.dist-info/WHEEL +4 -0
  51. python_infrakit_dev-0.1.0.dist-info/entry_points.txt +3 -0
infrakit/llm/batch.py ADDED
@@ -0,0 +1,165 @@
1
+ """
2
+ infrakit.llm.batch
3
+ ------------------
4
+ Batch processing engine for multiple prompts.
5
+
6
+ Two modes (chosen at LLMClient init):
7
+ - async : asyncio with a semaphore-based concurrency cap
8
+ - threaded: concurrent.futures.ThreadPoolExecutor
9
+
10
+ Results are always returned in input order.
11
+ Progress bar via tqdm (optional — gracefully degrades if not installed).
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import asyncio
17
+ import time
18
+ from concurrent.futures import ThreadPoolExecutor, as_completed
19
+ from typing import Any, Callable, Optional, Type
20
+
21
+ from pydantic import BaseModel
22
+
23
+ from .models import BatchResult, LLMResponse, Prompt
24
+
25
+ try:
26
+ from tqdm import tqdm as _tqdm
27
+ from tqdm.asyncio import tqdm as _async_tqdm
28
+ _HAS_TQDM = True
29
+ except ImportError:
30
+ _HAS_TQDM = False
31
+
32
+
33
+ # ── async batch ────────────────────────────────────────────────────────────
34
+
35
+ async def async_batch(
36
+ generate_fn: Callable[..., Any], # LLMClient._async_single_generate
37
+ prompts: list[Prompt],
38
+ response_model: Optional[Type[BaseModel]],
39
+ schema_retries: int,
40
+ provider: str,
41
+ max_concurrent: int,
42
+ show_progress: bool,
43
+ extra_kwargs: dict,
44
+ ) -> BatchResult:
45
+ """
46
+ Run *generate_fn* over all prompts with bounded concurrency.
47
+ Returns results in the same order as prompts.
48
+ """
49
+ semaphore = asyncio.Semaphore(max_concurrent)
50
+ results: list[Optional[LLMResponse]] = [None] * len(prompts)
51
+
52
+ async def _run(idx: int, prompt: Prompt) -> None:
53
+ async with semaphore:
54
+ try:
55
+ result = await generate_fn(
56
+ prompt=prompt,
57
+ response_model=response_model,
58
+ schema_retries=schema_retries,
59
+ provider=provider,
60
+ **extra_kwargs,
61
+ )
62
+ except Exception as exc:
63
+ result = _error_response(prompt, provider, str(exc))
64
+ results[idx] = result
65
+
66
+ tasks = [_run(i, p) for i, p in enumerate(prompts)]
67
+
68
+ if show_progress and _HAS_TQDM:
69
+ await _async_tqdm.gather(*tasks, desc="Batch", total=len(tasks), unit="prompt")
70
+ else:
71
+ if show_progress and not _HAS_TQDM:
72
+ print("[infrakit.llm] tqdm not installed — install it for progress bars.")
73
+ await asyncio.gather(*tasks)
74
+
75
+ return _aggregate(results)
76
+
77
+
78
+ # ── threaded batch ─────────────────────────────────────────────────────────
79
+
80
+ def threaded_batch(
81
+ generate_fn: Callable[..., Any], # LLMClient._sync_single_generate
82
+ prompts: list[Prompt],
83
+ response_model: Optional[Type[BaseModel]],
84
+ schema_retries: int,
85
+ provider: str,
86
+ max_concurrent: int,
87
+ show_progress: bool,
88
+ extra_kwargs: dict,
89
+ ) -> BatchResult:
90
+ """
91
+ Run *generate_fn* over all prompts using a thread pool.
92
+ Returns results in the same order as prompts.
93
+ """
94
+ results: list[Optional[LLMResponse]] = [None] * len(prompts)
95
+ futures_map: dict[Any, int] = {}
96
+
97
+ bar = None
98
+ if show_progress:
99
+ if _HAS_TQDM:
100
+ bar = _tqdm(total=len(prompts), desc="Batch", unit="prompt")
101
+ else:
102
+ print("[infrakit.llm] tqdm not installed — install it for progress bars.")
103
+
104
+ with ThreadPoolExecutor(max_workers=max_concurrent) as executor:
105
+ for idx, prompt in enumerate(prompts):
106
+ future = executor.submit(
107
+ generate_fn,
108
+ prompt=prompt,
109
+ response_model=response_model,
110
+ schema_retries=schema_retries,
111
+ provider=provider,
112
+ **extra_kwargs,
113
+ )
114
+ futures_map[future] = idx
115
+
116
+ for future in as_completed(futures_map):
117
+ idx = futures_map[future]
118
+ try:
119
+ results[idx] = future.result()
120
+ except Exception as exc:
121
+ results[idx] = _error_response(prompts[idx], provider, str(exc))
122
+ if bar:
123
+ bar.update(1)
124
+
125
+ if bar:
126
+ bar.close()
127
+
128
+ return _aggregate(results)
129
+
130
+
131
+ # ── helpers ────────────────────────────────────────────────────────────────
132
+
133
+ def _error_response(prompt: Prompt, provider: str, error: str) -> LLMResponse:
134
+ return LLMResponse(
135
+ content="",
136
+ parsed=None,
137
+ schema_matched=False,
138
+ provider=provider,
139
+ model="",
140
+ key_id="",
141
+ input_tokens=0,
142
+ output_tokens=0,
143
+ total_tokens=0,
144
+ latency_ms=0.0,
145
+ error=error,
146
+ )
147
+
148
+
149
+ def _aggregate(results: list[Optional[LLMResponse]]) -> BatchResult:
150
+ total_in = sum(r.input_tokens for r in results if r)
151
+ total_out = sum(r.output_tokens for r in results if r)
152
+ total_tok = sum(r.total_tokens for r in results if r)
153
+ total_lat = sum(r.latency_ms for r in results if r)
154
+ success = sum(1 for r in results if r and not r.error)
155
+ failure = sum(1 for r in results if r and r.error)
156
+
157
+ return BatchResult(
158
+ results=results,
159
+ total_input_tokens=total_in,
160
+ total_output_tokens=total_out,
161
+ total_tokens=total_tok,
162
+ total_latency_ms=total_lat,
163
+ success_count=success,
164
+ failure_count=failure,
165
+ )