codexa 0.4.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 (189) hide show
  1. codexa-0.4.0.dist-info/METADATA +650 -0
  2. codexa-0.4.0.dist-info/RECORD +189 -0
  3. codexa-0.4.0.dist-info/WHEEL +5 -0
  4. codexa-0.4.0.dist-info/entry_points.txt +2 -0
  5. codexa-0.4.0.dist-info/licenses/LICENSE +21 -0
  6. codexa-0.4.0.dist-info/top_level.txt +1 -0
  7. semantic_code_intelligence/__init__.py +5 -0
  8. semantic_code_intelligence/analysis/__init__.py +21 -0
  9. semantic_code_intelligence/analysis/ai_features.py +351 -0
  10. semantic_code_intelligence/bridge/__init__.py +28 -0
  11. semantic_code_intelligence/bridge/context_provider.py +245 -0
  12. semantic_code_intelligence/bridge/protocol.py +167 -0
  13. semantic_code_intelligence/bridge/server.py +348 -0
  14. semantic_code_intelligence/bridge/vscode.py +271 -0
  15. semantic_code_intelligence/ci/__init__.py +13 -0
  16. semantic_code_intelligence/ci/hooks.py +98 -0
  17. semantic_code_intelligence/ci/hotspots.py +272 -0
  18. semantic_code_intelligence/ci/impact.py +246 -0
  19. semantic_code_intelligence/ci/metrics.py +591 -0
  20. semantic_code_intelligence/ci/pr.py +412 -0
  21. semantic_code_intelligence/ci/quality.py +557 -0
  22. semantic_code_intelligence/ci/templates.py +164 -0
  23. semantic_code_intelligence/ci/trace.py +224 -0
  24. semantic_code_intelligence/cli/__init__.py +0 -0
  25. semantic_code_intelligence/cli/commands/__init__.py +0 -0
  26. semantic_code_intelligence/cli/commands/ask_cmd.py +153 -0
  27. semantic_code_intelligence/cli/commands/benchmark_cmd.py +303 -0
  28. semantic_code_intelligence/cli/commands/chat_cmd.py +252 -0
  29. semantic_code_intelligence/cli/commands/ci_gen_cmd.py +74 -0
  30. semantic_code_intelligence/cli/commands/context_cmd.py +120 -0
  31. semantic_code_intelligence/cli/commands/cross_refactor_cmd.py +113 -0
  32. semantic_code_intelligence/cli/commands/deps_cmd.py +91 -0
  33. semantic_code_intelligence/cli/commands/docs_cmd.py +101 -0
  34. semantic_code_intelligence/cli/commands/doctor_cmd.py +147 -0
  35. semantic_code_intelligence/cli/commands/evolve_cmd.py +171 -0
  36. semantic_code_intelligence/cli/commands/explain_cmd.py +112 -0
  37. semantic_code_intelligence/cli/commands/gate_cmd.py +135 -0
  38. semantic_code_intelligence/cli/commands/grep_cmd.py +234 -0
  39. semantic_code_intelligence/cli/commands/hotspots_cmd.py +119 -0
  40. semantic_code_intelligence/cli/commands/impact_cmd.py +131 -0
  41. semantic_code_intelligence/cli/commands/index_cmd.py +138 -0
  42. semantic_code_intelligence/cli/commands/init_cmd.py +152 -0
  43. semantic_code_intelligence/cli/commands/investigate_cmd.py +163 -0
  44. semantic_code_intelligence/cli/commands/languages_cmd.py +101 -0
  45. semantic_code_intelligence/cli/commands/lsp_cmd.py +49 -0
  46. semantic_code_intelligence/cli/commands/mcp_cmd.py +50 -0
  47. semantic_code_intelligence/cli/commands/metrics_cmd.py +264 -0
  48. semantic_code_intelligence/cli/commands/models_cmd.py +157 -0
  49. semantic_code_intelligence/cli/commands/plugin_cmd.py +275 -0
  50. semantic_code_intelligence/cli/commands/pr_summary_cmd.py +178 -0
  51. semantic_code_intelligence/cli/commands/quality_cmd.py +208 -0
  52. semantic_code_intelligence/cli/commands/refactor_cmd.py +103 -0
  53. semantic_code_intelligence/cli/commands/review_cmd.py +88 -0
  54. semantic_code_intelligence/cli/commands/search_cmd.py +236 -0
  55. semantic_code_intelligence/cli/commands/serve_cmd.py +117 -0
  56. semantic_code_intelligence/cli/commands/suggest_cmd.py +100 -0
  57. semantic_code_intelligence/cli/commands/summary_cmd.py +78 -0
  58. semantic_code_intelligence/cli/commands/tool_cmd.py +282 -0
  59. semantic_code_intelligence/cli/commands/trace_cmd.py +123 -0
  60. semantic_code_intelligence/cli/commands/tui_cmd.py +58 -0
  61. semantic_code_intelligence/cli/commands/viz_cmd.py +127 -0
  62. semantic_code_intelligence/cli/commands/watch_cmd.py +72 -0
  63. semantic_code_intelligence/cli/commands/web_cmd.py +61 -0
  64. semantic_code_intelligence/cli/commands/workspace_cmd.py +250 -0
  65. semantic_code_intelligence/cli/main.py +65 -0
  66. semantic_code_intelligence/cli/router.py +92 -0
  67. semantic_code_intelligence/config/__init__.py +0 -0
  68. semantic_code_intelligence/config/settings.py +260 -0
  69. semantic_code_intelligence/context/__init__.py +19 -0
  70. semantic_code_intelligence/context/engine.py +429 -0
  71. semantic_code_intelligence/context/memory.py +253 -0
  72. semantic_code_intelligence/daemon/__init__.py +1 -0
  73. semantic_code_intelligence/daemon/watcher.py +515 -0
  74. semantic_code_intelligence/docs/__init__.py +1080 -0
  75. semantic_code_intelligence/embeddings/__init__.py +0 -0
  76. semantic_code_intelligence/embeddings/enhanced.py +131 -0
  77. semantic_code_intelligence/embeddings/generator.py +149 -0
  78. semantic_code_intelligence/embeddings/model_registry.py +100 -0
  79. semantic_code_intelligence/evolution/__init__.py +1 -0
  80. semantic_code_intelligence/evolution/budget_guard.py +111 -0
  81. semantic_code_intelligence/evolution/commit_manager.py +88 -0
  82. semantic_code_intelligence/evolution/context_builder.py +131 -0
  83. semantic_code_intelligence/evolution/engine.py +249 -0
  84. semantic_code_intelligence/evolution/patch_generator.py +229 -0
  85. semantic_code_intelligence/evolution/task_selector.py +214 -0
  86. semantic_code_intelligence/evolution/test_runner.py +111 -0
  87. semantic_code_intelligence/indexing/__init__.py +0 -0
  88. semantic_code_intelligence/indexing/chunker.py +174 -0
  89. semantic_code_intelligence/indexing/parallel.py +86 -0
  90. semantic_code_intelligence/indexing/scanner.py +146 -0
  91. semantic_code_intelligence/indexing/semantic_chunker.py +337 -0
  92. semantic_code_intelligence/llm/__init__.py +62 -0
  93. semantic_code_intelligence/llm/cache.py +219 -0
  94. semantic_code_intelligence/llm/cached_provider.py +145 -0
  95. semantic_code_intelligence/llm/conversation.py +190 -0
  96. semantic_code_intelligence/llm/cross_refactor.py +272 -0
  97. semantic_code_intelligence/llm/investigation.py +274 -0
  98. semantic_code_intelligence/llm/mock_provider.py +77 -0
  99. semantic_code_intelligence/llm/ollama_provider.py +122 -0
  100. semantic_code_intelligence/llm/openai_provider.py +100 -0
  101. semantic_code_intelligence/llm/provider.py +92 -0
  102. semantic_code_intelligence/llm/rate_limiter.py +164 -0
  103. semantic_code_intelligence/llm/reasoning.py +438 -0
  104. semantic_code_intelligence/llm/safety.py +110 -0
  105. semantic_code_intelligence/llm/streaming.py +251 -0
  106. semantic_code_intelligence/lsp/__init__.py +609 -0
  107. semantic_code_intelligence/mcp/__init__.py +393 -0
  108. semantic_code_intelligence/parsing/__init__.py +19 -0
  109. semantic_code_intelligence/parsing/parser.py +375 -0
  110. semantic_code_intelligence/plugins/__init__.py +255 -0
  111. semantic_code_intelligence/plugins/examples/__init__.py +1 -0
  112. semantic_code_intelligence/plugins/examples/code_quality.py +73 -0
  113. semantic_code_intelligence/plugins/examples/search_annotator.py +56 -0
  114. semantic_code_intelligence/scalability/__init__.py +205 -0
  115. semantic_code_intelligence/search/__init__.py +0 -0
  116. semantic_code_intelligence/search/formatter.py +123 -0
  117. semantic_code_intelligence/search/grep.py +361 -0
  118. semantic_code_intelligence/search/hybrid_search.py +170 -0
  119. semantic_code_intelligence/search/keyword_search.py +311 -0
  120. semantic_code_intelligence/search/section_expander.py +103 -0
  121. semantic_code_intelligence/services/__init__.py +0 -0
  122. semantic_code_intelligence/services/indexing_service.py +630 -0
  123. semantic_code_intelligence/services/search_service.py +269 -0
  124. semantic_code_intelligence/storage/__init__.py +0 -0
  125. semantic_code_intelligence/storage/chunk_hash_store.py +86 -0
  126. semantic_code_intelligence/storage/hash_store.py +66 -0
  127. semantic_code_intelligence/storage/index_manifest.py +85 -0
  128. semantic_code_intelligence/storage/index_stats.py +138 -0
  129. semantic_code_intelligence/storage/query_history.py +160 -0
  130. semantic_code_intelligence/storage/symbol_registry.py +209 -0
  131. semantic_code_intelligence/storage/vector_store.py +297 -0
  132. semantic_code_intelligence/tests/__init__.py +0 -0
  133. semantic_code_intelligence/tests/test_ai_features.py +351 -0
  134. semantic_code_intelligence/tests/test_chunker.py +119 -0
  135. semantic_code_intelligence/tests/test_cli.py +188 -0
  136. semantic_code_intelligence/tests/test_config.py +154 -0
  137. semantic_code_intelligence/tests/test_context.py +381 -0
  138. semantic_code_intelligence/tests/test_embeddings.py +73 -0
  139. semantic_code_intelligence/tests/test_endtoend.py +1142 -0
  140. semantic_code_intelligence/tests/test_enhanced_embeddings.py +92 -0
  141. semantic_code_intelligence/tests/test_hash_store.py +79 -0
  142. semantic_code_intelligence/tests/test_logging.py +55 -0
  143. semantic_code_intelligence/tests/test_new_cli.py +138 -0
  144. semantic_code_intelligence/tests/test_parser.py +495 -0
  145. semantic_code_intelligence/tests/test_phase10.py +355 -0
  146. semantic_code_intelligence/tests/test_phase11.py +593 -0
  147. semantic_code_intelligence/tests/test_phase12.py +375 -0
  148. semantic_code_intelligence/tests/test_phase13.py +663 -0
  149. semantic_code_intelligence/tests/test_phase14.py +568 -0
  150. semantic_code_intelligence/tests/test_phase15.py +814 -0
  151. semantic_code_intelligence/tests/test_phase16.py +792 -0
  152. semantic_code_intelligence/tests/test_phase17.py +815 -0
  153. semantic_code_intelligence/tests/test_phase18.py +934 -0
  154. semantic_code_intelligence/tests/test_phase19.py +986 -0
  155. semantic_code_intelligence/tests/test_phase20.py +2753 -0
  156. semantic_code_intelligence/tests/test_phase20b.py +2058 -0
  157. semantic_code_intelligence/tests/test_phase20c.py +962 -0
  158. semantic_code_intelligence/tests/test_phase21.py +428 -0
  159. semantic_code_intelligence/tests/test_phase22.py +799 -0
  160. semantic_code_intelligence/tests/test_phase23.py +783 -0
  161. semantic_code_intelligence/tests/test_phase24.py +715 -0
  162. semantic_code_intelligence/tests/test_phase25.py +496 -0
  163. semantic_code_intelligence/tests/test_phase26.py +251 -0
  164. semantic_code_intelligence/tests/test_phase27.py +531 -0
  165. semantic_code_intelligence/tests/test_phase8.py +592 -0
  166. semantic_code_intelligence/tests/test_phase9.py +643 -0
  167. semantic_code_intelligence/tests/test_plugins.py +293 -0
  168. semantic_code_intelligence/tests/test_priority_features.py +727 -0
  169. semantic_code_intelligence/tests/test_router.py +41 -0
  170. semantic_code_intelligence/tests/test_scalability.py +138 -0
  171. semantic_code_intelligence/tests/test_scanner.py +125 -0
  172. semantic_code_intelligence/tests/test_search.py +160 -0
  173. semantic_code_intelligence/tests/test_semantic_chunker.py +255 -0
  174. semantic_code_intelligence/tests/test_tools.py +182 -0
  175. semantic_code_intelligence/tests/test_vector_store.py +151 -0
  176. semantic_code_intelligence/tests/test_watcher.py +211 -0
  177. semantic_code_intelligence/tools/__init__.py +442 -0
  178. semantic_code_intelligence/tools/executor.py +232 -0
  179. semantic_code_intelligence/tools/protocol.py +200 -0
  180. semantic_code_intelligence/tui/__init__.py +454 -0
  181. semantic_code_intelligence/utils/__init__.py +0 -0
  182. semantic_code_intelligence/utils/logging.py +112 -0
  183. semantic_code_intelligence/version.py +3 -0
  184. semantic_code_intelligence/web/__init__.py +11 -0
  185. semantic_code_intelligence/web/api.py +289 -0
  186. semantic_code_intelligence/web/server.py +397 -0
  187. semantic_code_intelligence/web/ui.py +659 -0
  188. semantic_code_intelligence/web/visualize.py +226 -0
  189. semantic_code_intelligence/workspace/__init__.py +427 -0
@@ -0,0 +1,251 @@
1
+ """Streaming LLM support — delivers tokens incrementally with plugin hooks.
2
+
3
+ Provides:
4
+ - ``stream_chat()`` wrapper that works with any LLMProvider
5
+ - ``StreamEvent`` lightweight token container
6
+ - Plugin dispatch through ``PluginHook.ON_STREAM`` for each token
7
+ - Accumulator helpers for building final ``LLMResponse`` from a stream
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ from dataclasses import dataclass, field
13
+ from typing import Any, Generator
14
+
15
+ from semantic_code_intelligence.llm.provider import (
16
+ LLMMessage,
17
+ LLMProvider,
18
+ LLMResponse,
19
+ )
20
+ from semantic_code_intelligence.utils.logging import get_logger
21
+
22
+ logger = get_logger("llm.streaming")
23
+
24
+
25
+ # ---------------------------------------------------------------------------
26
+ # Data types
27
+ # ---------------------------------------------------------------------------
28
+
29
+ @dataclass
30
+ class StreamEvent:
31
+ """A single streaming event (token, status change, or error)."""
32
+
33
+ kind: str # "token" | "start" | "done" | "error"
34
+ content: str = ""
35
+ metadata: dict[str, Any] = field(default_factory=dict)
36
+
37
+ def to_dict(self) -> dict[str, Any]:
38
+ return {"kind": self.kind, "content": self.content, "metadata": self.metadata}
39
+
40
+ def to_sse(self) -> str:
41
+ """Format as a Server-Sent Event line."""
42
+ import json
43
+
44
+ return f"data: {json.dumps(self.to_dict())}\n\n"
45
+
46
+
47
+ # ---------------------------------------------------------------------------
48
+ # Streaming wrappers for each provider
49
+ # ---------------------------------------------------------------------------
50
+
51
+ def _stream_ollama(
52
+ provider: Any,
53
+ messages: list[LLMMessage],
54
+ **kwargs: Any,
55
+ ) -> Generator[StreamEvent, None, LLMResponse | None]:
56
+ """Stream tokens from an Ollama provider."""
57
+ import json as json_mod
58
+ from urllib.request import Request, urlopen
59
+
60
+ temperature = kwargs.get("temperature", provider._temperature)
61
+ payload: dict[str, Any] = {
62
+ "model": provider._model,
63
+ "messages": [m.to_dict() for m in messages],
64
+ "stream": True,
65
+ "options": {
66
+ "temperature": temperature,
67
+ "num_predict": kwargs.get("max_tokens", provider._max_tokens),
68
+ },
69
+ }
70
+
71
+ url = f"{provider._base_url}/api/chat"
72
+ data = json_mod.dumps(payload).encode("utf-8")
73
+ req = Request(url, data=data, headers={"Content-Type": "application/json"})
74
+
75
+ yield StreamEvent(kind="start", metadata={"model": provider._model, "provider": "ollama"})
76
+
77
+ accumulated = ""
78
+ prompt_tokens = 0
79
+ completion_tokens = 0
80
+
81
+ try:
82
+ with urlopen(req, timeout=120) as resp: # noqa: S310 — localhost only
83
+ for raw_line in resp:
84
+ line = raw_line.decode("utf-8", errors="replace").strip()
85
+ if not line:
86
+ continue
87
+ try:
88
+ chunk = json_mod.loads(line)
89
+ except json_mod.JSONDecodeError:
90
+ continue
91
+ msg = chunk.get("message", {})
92
+ token = msg.get("content", "")
93
+ if token:
94
+ accumulated += token
95
+ yield StreamEvent(kind="token", content=token)
96
+
97
+ if chunk.get("done"):
98
+ prompt_tokens = chunk.get("prompt_eval_count", 0)
99
+ completion_tokens = chunk.get("eval_count", 0)
100
+ except Exception as exc:
101
+ yield StreamEvent(kind="error", content=str(exc))
102
+ return None
103
+
104
+ yield StreamEvent(kind="done")
105
+ return LLMResponse(
106
+ content=accumulated,
107
+ model=provider._model,
108
+ provider="ollama",
109
+ usage={
110
+ "prompt_tokens": prompt_tokens,
111
+ "completion_tokens": completion_tokens,
112
+ "total_tokens": prompt_tokens + completion_tokens,
113
+ },
114
+ )
115
+
116
+
117
+ def _stream_openai(
118
+ provider: Any,
119
+ messages: list[LLMMessage],
120
+ **kwargs: Any,
121
+ ) -> Generator[StreamEvent, None, LLMResponse | None]:
122
+ """Stream tokens from an OpenAI provider."""
123
+ client = provider._get_client()
124
+ temperature = kwargs.get("temperature", provider._temperature)
125
+ max_tokens = kwargs.get("max_tokens", provider._max_tokens)
126
+
127
+ api_messages = [m.to_dict() for m in messages]
128
+
129
+ yield StreamEvent(kind="start", metadata={"model": provider._model, "provider": "openai"})
130
+
131
+ accumulated = ""
132
+ try:
133
+ response = client.chat.completions.create(
134
+ model=provider._model,
135
+ messages=api_messages,
136
+ temperature=temperature,
137
+ max_tokens=max_tokens,
138
+ stream=True,
139
+ )
140
+ for chunk in response:
141
+ delta = chunk.choices[0].delta if chunk.choices else None
142
+ if delta and delta.content:
143
+ accumulated += delta.content
144
+ yield StreamEvent(kind="token", content=delta.content)
145
+ except Exception as exc:
146
+ yield StreamEvent(kind="error", content=str(exc))
147
+ return None
148
+
149
+ yield StreamEvent(kind="done")
150
+ return LLMResponse(
151
+ content=accumulated,
152
+ model=provider._model,
153
+ provider="openai",
154
+ usage={"completion_tokens": len(accumulated) // 4},
155
+ )
156
+
157
+
158
+ def _stream_mock(
159
+ provider: Any,
160
+ messages: list[LLMMessage],
161
+ **kwargs: Any,
162
+ ) -> Generator[StreamEvent, None, LLMResponse | None]:
163
+ """Simulate streaming from a MockProvider by yielding word-by-word."""
164
+ yield StreamEvent(kind="start", metadata={"model": provider._model, "provider": "mock"})
165
+
166
+ content = provider._next_response()
167
+ provider._call_history.append({
168
+ "method": "stream_chat",
169
+ "messages": [m.to_dict() for m in messages],
170
+ "response": content,
171
+ })
172
+
173
+ words = content.split(" ")
174
+ for i, word in enumerate(words):
175
+ token = word if i == 0 else " " + word
176
+ yield StreamEvent(kind="token", content=token)
177
+
178
+ yield StreamEvent(kind="done")
179
+ return LLMResponse(
180
+ content=content,
181
+ model=provider._model,
182
+ provider="mock",
183
+ usage={"completion_tokens": len(content) // 4},
184
+ )
185
+
186
+
187
+ # ---------------------------------------------------------------------------
188
+ # Unified streaming API
189
+ # ---------------------------------------------------------------------------
190
+
191
+ def stream_chat(
192
+ provider: LLMProvider,
193
+ messages: list[LLMMessage],
194
+ *,
195
+ plugin_manager: Any | None = None,
196
+ **kwargs: Any,
197
+ ) -> Generator[StreamEvent, None, LLMResponse | None]:
198
+ """Stream chat tokens from any supported LLM provider.
199
+
200
+ Yields ``StreamEvent`` objects for each token. If a *plugin_manager*
201
+ is provided, dispatches ``PluginHook.ON_STREAM`` for each token event.
202
+
203
+ Usage::
204
+
205
+ gen = stream_chat(provider, messages)
206
+ for event in gen:
207
+ print(event.content, end="", flush=True)
208
+
209
+ The generator's return value (accessible via StopIteration.value) is
210
+ the accumulated ``LLMResponse``.
211
+ """
212
+ from semantic_code_intelligence.llm.ollama_provider import OllamaProvider
213
+ from semantic_code_intelligence.llm.openai_provider import OpenAIProvider
214
+ from semantic_code_intelligence.llm.mock_provider import MockProvider
215
+
216
+ # Select the appropriate streaming implementation
217
+ if isinstance(provider, OllamaProvider):
218
+ inner = _stream_ollama(provider, messages, **kwargs)
219
+ elif isinstance(provider, OpenAIProvider):
220
+ inner = _stream_openai(provider, messages, **kwargs)
221
+ elif isinstance(provider, MockProvider):
222
+ inner = _stream_mock(provider, messages, **kwargs)
223
+ else:
224
+ # Fallback — non-streaming: call chat() and emit as single token
225
+ resp = provider.chat(messages, **kwargs)
226
+ yield StreamEvent(kind="start", metadata={"provider": provider.name})
227
+ yield StreamEvent(kind="token", content=resp.content)
228
+ yield StreamEvent(kind="done")
229
+ return resp
230
+
231
+ # Iterate inner generator, dispatching plugin hooks
232
+ result: LLMResponse | None = None
233
+ try:
234
+ while True:
235
+ event = next(inner)
236
+ # Dispatch ON_STREAM plugin hook for token events
237
+ if plugin_manager and event.kind == "token":
238
+ try:
239
+ from semantic_code_intelligence.plugins import PluginHook
240
+
241
+ plugin_manager.dispatch(
242
+ PluginHook.ON_STREAM,
243
+ {"event": event.to_dict(), "accumulated": ""},
244
+ )
245
+ except Exception:
246
+ logger.debug("Plugin streaming hook failed")
247
+ yield event
248
+ except StopIteration as stop:
249
+ result = stop.value
250
+
251
+ return result