velune-cli 0.9.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 (279) hide show
  1. velune/__init__.py +5 -0
  2. velune/__main__.py +6 -0
  3. velune/cli/__init__.py +5 -0
  4. velune/cli/app.py +208 -0
  5. velune/cli/autocomplete.py +80 -0
  6. velune/cli/banner.py +60 -0
  7. velune/cli/commands/__init__.py +32 -0
  8. velune/cli/commands/ask.py +175 -0
  9. velune/cli/commands/base.py +16 -0
  10. velune/cli/commands/chat.py +228 -0
  11. velune/cli/commands/config.py +224 -0
  12. velune/cli/commands/daemon.py +88 -0
  13. velune/cli/commands/doctor.py +721 -0
  14. velune/cli/commands/init.py +170 -0
  15. velune/cli/commands/mcp.py +82 -0
  16. velune/cli/commands/memory.py +293 -0
  17. velune/cli/commands/models.py +683 -0
  18. velune/cli/commands/preflight.py +95 -0
  19. velune/cli/commands/run.py +270 -0
  20. velune/cli/commands/setup.py +184 -0
  21. velune/cli/commands/workspace.py +249 -0
  22. velune/cli/context.py +36 -0
  23. velune/cli/councilmodel_ui.py +199 -0
  24. velune/cli/display/council_view.py +254 -0
  25. velune/cli/display/memory_view.py +126 -0
  26. velune/cli/display/panels.py +35 -0
  27. velune/cli/display/progress.py +25 -0
  28. velune/cli/display/themes.py +25 -0
  29. velune/cli/main.py +15 -0
  30. velune/cli/model_selector.py +51 -0
  31. velune/cli/modes.py +86 -0
  32. velune/cli/pull_ui.py +123 -0
  33. velune/cli/registry.py +80 -0
  34. velune/cli/rendering/__init__.py +5 -0
  35. velune/cli/rendering/error_panel.py +79 -0
  36. velune/cli/rendering/markdown.py +63 -0
  37. velune/cli/repl.py +1855 -0
  38. velune/cli/session_manager.py +71 -0
  39. velune/cli/slash_commands.py +37 -0
  40. velune/cli/theme.py +8 -0
  41. velune/cognition/__init__.py +23 -0
  42. velune/cognition/agents/__init__.py +7 -0
  43. velune/cognition/agents/coder.py +209 -0
  44. velune/cognition/agents/planner.py +156 -0
  45. velune/cognition/agents/reviewer.py +195 -0
  46. velune/cognition/arbitrator.py +220 -0
  47. velune/cognition/architecture.py +415 -0
  48. velune/cognition/budget.py +65 -0
  49. velune/cognition/council/__init__.py +47 -0
  50. velune/cognition/council/base.py +217 -0
  51. velune/cognition/council/challenger.py +74 -0
  52. velune/cognition/council/coder.py +79 -0
  53. velune/cognition/council/critic_agent.py +43 -0
  54. velune/cognition/council/critic_configs.py +111 -0
  55. velune/cognition/council/critics.py +41 -0
  56. velune/cognition/council/debate.py +46 -0
  57. velune/cognition/council/factory.py +140 -0
  58. velune/cognition/council/messages.py +56 -0
  59. velune/cognition/council/planner.py +124 -0
  60. velune/cognition/council/reviewer.py +74 -0
  61. velune/cognition/council/synthesizer.py +67 -0
  62. velune/cognition/council/tiers.py +188 -0
  63. velune/cognition/council_orchestrator.py +282 -0
  64. velune/cognition/firewall.py +354 -0
  65. velune/cognition/module.py +46 -0
  66. velune/cognition/orchestrator.py +1205 -0
  67. velune/cognition/personality.py +238 -0
  68. velune/cognition/state.py +104 -0
  69. velune/cognition/style_resolver.py +64 -0
  70. velune/cognition/verification.py +205 -0
  71. velune/context/__init__.py +28 -0
  72. velune/context/assembler.py +240 -0
  73. velune/context/budget.py +97 -0
  74. velune/context/extractive.py +95 -0
  75. velune/context/prompt_adaptation.py +480 -0
  76. velune/context/sections.py +99 -0
  77. velune/context/token_counter.py +134 -0
  78. velune/context/utilization.py +33 -0
  79. velune/context/window.py +63 -0
  80. velune/core/__init__.py +89 -0
  81. velune/core/background.py +5 -0
  82. velune/core/config/__init__.py +37 -0
  83. velune/core/errors/__init__.py +90 -0
  84. velune/core/errors/catalog.py +188 -0
  85. velune/core/errors/execution.py +31 -0
  86. velune/core/errors/memory.py +25 -0
  87. velune/core/errors/orchestration.py +31 -0
  88. velune/core/errors/provider.py +37 -0
  89. velune/core/event_loop.py +35 -0
  90. velune/core/logging.py +83 -0
  91. velune/core/paths.py +165 -0
  92. velune/core/runtime.py +113 -0
  93. velune/core/startup_profiler.py +56 -0
  94. velune/core/task_registry.py +117 -0
  95. velune/core/trace.py +83 -0
  96. velune/core/types/__init__.py +48 -0
  97. velune/core/types/agent.py +53 -0
  98. velune/core/types/context.py +42 -0
  99. velune/core/types/inference.py +38 -0
  100. velune/core/types/memory.py +42 -0
  101. velune/core/types/model.py +70 -0
  102. velune/core/types/provider.py +62 -0
  103. velune/core/types/repository.py +38 -0
  104. velune/core/types/task.py +61 -0
  105. velune/core/types/workspace.py +28 -0
  106. velune/daemon/client.py +13 -0
  107. velune/daemon/server.py +127 -0
  108. velune/daemon/transport.py +179 -0
  109. velune/events.py +204 -0
  110. velune/execution/__init__.py +22 -0
  111. velune/execution/benchmarker.py +315 -0
  112. velune/execution/cancellation.py +53 -0
  113. velune/execution/checkpointer.py +130 -0
  114. velune/execution/command_spec.py +165 -0
  115. velune/execution/diff_preview.py +197 -0
  116. velune/execution/executor.py +181 -0
  117. velune/execution/module.py +18 -0
  118. velune/execution/multi_diff.py +67 -0
  119. velune/execution/path_guard.py +74 -0
  120. velune/execution/planner.py +91 -0
  121. velune/execution/rollback.py +89 -0
  122. velune/execution/sandbox.py +268 -0
  123. velune/execution/validator.py +115 -0
  124. velune/hardware/__init__.py +1 -0
  125. velune/hardware/detector.py +192 -0
  126. velune/kernel/__init__.py +55 -0
  127. velune/kernel/bootstrap.py +125 -0
  128. velune/kernel/config.py +426 -0
  129. velune/kernel/entrypoint.py +78 -0
  130. velune/kernel/health.py +54 -0
  131. velune/kernel/lifecycle.py +143 -0
  132. velune/kernel/module.py +17 -0
  133. velune/kernel/modules.py +23 -0
  134. velune/kernel/registry.py +96 -0
  135. velune/kernel/schemas.py +28 -0
  136. velune/main.py +9 -0
  137. velune/mcp/__init__.py +9 -0
  138. velune/mcp/client.py +115 -0
  139. velune/mcp/config.py +19 -0
  140. velune/mcp/server.py +624 -0
  141. velune/memory/__init__.py +32 -0
  142. velune/memory/compaction.py +506 -0
  143. velune/memory/embedding_pipeline.py +241 -0
  144. velune/memory/lifecycle.py +680 -0
  145. velune/memory/module.py +218 -0
  146. velune/memory/prioritizer.py +67 -0
  147. velune/memory/storage/episodic_schema.sql +53 -0
  148. velune/memory/storage/lancedb_store.py +282 -0
  149. velune/memory/storage/sqlite_manager.py +369 -0
  150. velune/memory/storage/sqlite_pool.py +149 -0
  151. velune/memory/tiers/episodic.py +588 -0
  152. velune/memory/tiers/graph.py +378 -0
  153. velune/memory/tiers/lineage.py +416 -0
  154. velune/memory/tiers/semantic.py +475 -0
  155. velune/memory/tiers/working.py +168 -0
  156. velune/memory/vitality.py +132 -0
  157. velune/models/__init__.py +15 -0
  158. velune/models/family.py +76 -0
  159. velune/models/module.py +20 -0
  160. velune/models/probes.py +192 -0
  161. velune/models/profile_cache.py +84 -0
  162. velune/models/profiler.py +108 -0
  163. velune/models/registry.py +251 -0
  164. velune/models/scorer.py +233 -0
  165. velune/models/specializations.py +205 -0
  166. velune/orchestration/__init__.py +19 -0
  167. velune/orchestration/engine.py +239 -0
  168. velune/orchestration/module.py +15 -0
  169. velune/orchestration/role_assignments.py +82 -0
  170. velune/orchestration/schemas.py +98 -0
  171. velune/plugins/__init__.py +20 -0
  172. velune/plugins/hooks.py +50 -0
  173. velune/plugins/loader.py +161 -0
  174. velune/plugins/registry.py +56 -0
  175. velune/plugins/schemas.py +21 -0
  176. velune/providers/__init__.py +23 -0
  177. velune/providers/adapters/anthropic.py +257 -0
  178. velune/providers/adapters/fireworks.py +115 -0
  179. velune/providers/adapters/google.py +234 -0
  180. velune/providers/adapters/groq.py +151 -0
  181. velune/providers/adapters/huggingface.py +210 -0
  182. velune/providers/adapters/llamacpp.py +208 -0
  183. velune/providers/adapters/lmstudio.py +175 -0
  184. velune/providers/adapters/ollama.py +233 -0
  185. velune/providers/adapters/openai.py +213 -0
  186. velune/providers/adapters/openrouter.py +81 -0
  187. velune/providers/adapters/together.py +134 -0
  188. velune/providers/adapters/xai.py +60 -0
  189. velune/providers/base.py +86 -0
  190. velune/providers/benchmarker.py +138 -0
  191. velune/providers/discovery/__init__.py +33 -0
  192. velune/providers/discovery/anthropic.py +79 -0
  193. velune/providers/discovery/benchmarks.py +44 -0
  194. velune/providers/discovery/classifier.py +69 -0
  195. velune/providers/discovery/fireworks.py +95 -0
  196. velune/providers/discovery/gguf.py +88 -0
  197. velune/providers/discovery/google.py +95 -0
  198. velune/providers/discovery/gpu.py +117 -0
  199. velune/providers/discovery/groq.py +21 -0
  200. velune/providers/discovery/huggingface.py +67 -0
  201. velune/providers/discovery/lmstudio.py +80 -0
  202. velune/providers/discovery/ollama.py +162 -0
  203. velune/providers/discovery/openai.py +96 -0
  204. velune/providers/discovery/openrouter.py +113 -0
  205. velune/providers/discovery/scanner.py +115 -0
  206. velune/providers/discovery/together.py +114 -0
  207. velune/providers/discovery/xai.py +57 -0
  208. velune/providers/health.py +67 -0
  209. velune/providers/health_monitor.py +169 -0
  210. velune/providers/keystore.py +142 -0
  211. velune/providers/local_paths.py +49 -0
  212. velune/providers/local_resolver.py +229 -0
  213. velune/providers/module.py +51 -0
  214. velune/providers/ollama_manager.py +193 -0
  215. velune/providers/registry.py +220 -0
  216. velune/providers/router.py +255 -0
  217. velune/providers/task_classifier.py +288 -0
  218. velune/py.typed +0 -0
  219. velune/repository/__init__.py +33 -0
  220. velune/repository/analyzer.py +127 -0
  221. velune/repository/ast_parser.py +822 -0
  222. velune/repository/blast_radius.py +298 -0
  223. velune/repository/boundary_classifier.py +295 -0
  224. velune/repository/cognition.py +316 -0
  225. velune/repository/grapher.py +179 -0
  226. velune/repository/import_graph.py +263 -0
  227. velune/repository/incremental_indexer.py +275 -0
  228. velune/repository/index_state.py +96 -0
  229. velune/repository/indexer.py +243 -0
  230. velune/repository/module.py +17 -0
  231. velune/repository/parser.py +474 -0
  232. velune/repository/project_type.py +300 -0
  233. velune/repository/rename_journal.py +287 -0
  234. velune/repository/scanner.py +193 -0
  235. velune/repository/schemas.py +102 -0
  236. velune/repository/symbol_registry.py +365 -0
  237. velune/repository/tracker.py +252 -0
  238. velune/retrieval/__init__.py +27 -0
  239. velune/retrieval/cache.py +110 -0
  240. velune/retrieval/fast_path.py +391 -0
  241. velune/retrieval/graph.py +124 -0
  242. velune/retrieval/hybrid.py +271 -0
  243. velune/retrieval/keyword.py +131 -0
  244. velune/retrieval/module.py +26 -0
  245. velune/retrieval/pipeline.py +303 -0
  246. velune/retrieval/reranker.py +102 -0
  247. velune/retrieval/schemas.py +59 -0
  248. velune/retrieval/slow_path.py +364 -0
  249. velune/retrieval/vector.py +203 -0
  250. velune/telemetry/__init__.py +59 -0
  251. velune/telemetry/cognition.py +267 -0
  252. velune/telemetry/cost_estimator.py +92 -0
  253. velune/telemetry/debug.py +304 -0
  254. velune/telemetry/doctor.py +244 -0
  255. velune/telemetry/logging.py +286 -0
  256. velune/telemetry/spans.py +277 -0
  257. velune/telemetry/token_tracker.py +140 -0
  258. velune/telemetry/usage_tracker.py +340 -0
  259. velune/tools/__init__.py +41 -0
  260. velune/tools/base/registry.py +87 -0
  261. velune/tools/base/tool.py +63 -0
  262. velune/tools/code/navigate.py +116 -0
  263. velune/tools/code/search.py +123 -0
  264. velune/tools/filesystem/read.py +75 -0
  265. velune/tools/filesystem/search.py +136 -0
  266. velune/tools/filesystem/write.py +163 -0
  267. velune/tools/git/history.py +177 -0
  268. velune/tools/git/operations.py +122 -0
  269. velune/tools/git/state.py +121 -0
  270. velune/tools/module.py +81 -0
  271. velune/tools/terminal/execute.py +72 -0
  272. velune/tools/terminal/history.py +47 -0
  273. velune/tools/web/fetch.py +55 -0
  274. velune/tools/web/validator.py +122 -0
  275. velune_cli-0.9.0.dist-info/METADATA +518 -0
  276. velune_cli-0.9.0.dist-info/RECORD +279 -0
  277. velune_cli-0.9.0.dist-info/WHEEL +4 -0
  278. velune_cli-0.9.0.dist-info/entry_points.txt +2 -0
  279. velune_cli-0.9.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,134 @@
1
+ """Token counter with model-aware encoding support.
2
+
3
+ Supports accurate token counting for OpenAI-family models via tiktoken,
4
+ with conservative fallback for other model families.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import logging
10
+ from typing import Any
11
+
12
+ from velune.core.types.model import ModelDescriptor
13
+ from velune.models.family import ModelFamily, detect_family
14
+
15
+ logger = logging.getLogger("velune.context.token_counter")
16
+
17
+ # Attempt to load tiktoken for accurate OpenAI-family token counting
18
+ try:
19
+ import tiktoken
20
+
21
+ HAS_TIKTOKEN = True
22
+ except ImportError:
23
+ HAS_TIKTOKEN = False
24
+ logger.warning("tiktoken not available; using heuristic token estimation")
25
+
26
+
27
+ class TokenCounter:
28
+ """Token counting with model-specific encoding support."""
29
+
30
+ # Tiktoken encoding registry for OpenAI-family models
31
+ _ENCODING_CACHE: dict[str, Any] = {}
32
+
33
+ @staticmethod
34
+ def count(text: str, model: ModelDescriptor) -> int:
35
+ """Count tokens in text for the given model.
36
+
37
+ Args:
38
+ text: Text to count tokens in
39
+ model: ModelDescriptor with model_id and family information
40
+
41
+ Returns:
42
+ Estimated or exact token count
43
+ """
44
+ if not text:
45
+ return 0
46
+
47
+ # Detect model family if not specified
48
+ family = detect_family(model.model_id)
49
+
50
+ # OpenAI-family models: use tiktoken for accuracy
51
+ if family in (ModelFamily.CLAUDE, ModelFamily.GPT):
52
+ return TokenCounter._count_openai_family(text, model.model_id)
53
+
54
+ # Other families: conservative heuristic
55
+ return TokenCounter._count_heuristic(text)
56
+
57
+ @staticmethod
58
+ def count_messages(messages: list[dict[str, str]], model: ModelDescriptor) -> int:
59
+ """Count tokens in a list of messages.
60
+
61
+ Args:
62
+ messages: List of message dicts with 'role' and 'content' keys
63
+ model: ModelDescriptor for encoding selection
64
+
65
+ Returns:
66
+ Total token count including overhead for message structure
67
+ """
68
+ if not messages:
69
+ return 0
70
+
71
+ # Message structure overhead: ~4 tokens per message for role markers
72
+ structure_overhead = len(messages) * 4
73
+
74
+ # Count tokens in all message content
75
+ content_tokens = sum(TokenCounter.count(msg.get("content", ""), model) for msg in messages)
76
+
77
+ return structure_overhead + content_tokens
78
+
79
+ @staticmethod
80
+ def _count_openai_family(text: str, model_id: str) -> int:
81
+ """Count tokens using tiktoken for OpenAI-family models.
82
+
83
+ Falls back to heuristic if tiktoken unavailable.
84
+ """
85
+ if not HAS_TIKTOKEN:
86
+ return TokenCounter._count_heuristic(text)
87
+
88
+ try:
89
+ # Determine appropriate encoding
90
+ encoding_name = TokenCounter._select_encoding(model_id)
91
+ if encoding_name not in TokenCounter._ENCODING_CACHE:
92
+ TokenCounter._ENCODING_CACHE[encoding_name] = tiktoken.get_encoding(encoding_name)
93
+ encoding = TokenCounter._ENCODING_CACHE[encoding_name]
94
+
95
+ # Count tokens, allowing special characters
96
+ return len(encoding.encode(text, disallowed_special=()))
97
+ except Exception as e:
98
+ logger.debug(f"tiktoken counting failed for {model_id}: {e}; falling back to heuristic")
99
+ return TokenCounter._count_heuristic(text)
100
+
101
+ @staticmethod
102
+ def _count_heuristic(text: str) -> int:
103
+ """Conservative token estimation for non-OpenAI models.
104
+
105
+ Assumes 1 token ≈ 1.35 words (English language average).
106
+ Used as fallback when tiktoken unavailable or for non-OpenAI models.
107
+ """
108
+ if not text:
109
+ return 0
110
+ word_count = len(text.split())
111
+ return max(1, int(word_count * 1.35))
112
+
113
+ @staticmethod
114
+ def _select_encoding(model_id: str) -> str:
115
+ """Select appropriate tiktoken encoding based on model.
116
+
117
+ Args:
118
+ model_id: Model identifier (e.g., "gpt-4-turbo", "gpt-3.5-turbo")
119
+
120
+ Returns:
121
+ Tiktoken encoding name (e.g., "cl100k_base", "o200k_base")
122
+ """
123
+ model_lower = model_id.lower()
124
+
125
+ # o1 and newer models: o200k_base
126
+ if "o1" in model_lower or "o200k" in model_lower:
127
+ return "o200k_base"
128
+
129
+ # GPT-4-turbo and newer: cl100k_base
130
+ if "gpt-4" in model_lower or "gpt-4-turbo" in model_lower:
131
+ return "cl100k_base"
132
+
133
+ # GPT-3.5 and other models: cl100k_base
134
+ return "cl100k_base"
@@ -0,0 +1,33 @@
1
+ from __future__ import annotations
2
+
3
+ from velune.context.window import estimate_tokens
4
+
5
+
6
+ class ContextUtilizationTracker:
7
+ """Tracks token consumption dynamically and reports utilization percentages."""
8
+
9
+ def __init__(self, max_tokens: int = 8192) -> None:
10
+ self.max_tokens = max_tokens
11
+ self.used_tokens = 0
12
+
13
+ def update(self, conversation: list[dict] | str) -> None:
14
+ """Update the used token count based on active conversation list or raw string."""
15
+ if isinstance(conversation, str):
16
+ self.used_tokens = estimate_tokens(conversation)
17
+ elif isinstance(conversation, list):
18
+ text = " ".join(m.get("content", "") for m in conversation if isinstance(m, dict))
19
+ self.used_tokens = estimate_tokens(text)
20
+ else:
21
+ self.used_tokens = 0
22
+
23
+ @property
24
+ def percentage(self) -> float:
25
+ """Returns the percentage of utilization, from 0.0 to 100.0."""
26
+ if self.max_tokens <= 0:
27
+ return 0.0
28
+ return min((self.used_tokens / self.max_tokens) * 100.0, 100.0)
29
+
30
+ @property
31
+ def formatted_badge(self) -> str:
32
+ """Returns a string in the format [ctx:NN%]."""
33
+ return f"[ctx:{self.percentage:.0f}%]"
@@ -0,0 +1,63 @@
1
+ """Context window and token tracking utilities."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+
7
+ logger = logging.getLogger("velune.context.window")
8
+
9
+ # Attempt to load tiktoken, fallback to heuristic if unavailable
10
+ try:
11
+ import tiktoken
12
+
13
+ _encoding = tiktoken.get_encoding("cl100k_base")
14
+ HAS_TIKTOKEN = True
15
+ except ImportError:
16
+ HAS_TIKTOKEN = False
17
+ _encoding = None
18
+
19
+
20
+ def estimate_tokens(text: str) -> int:
21
+ """Accurately count or estimate tokens in a given text block."""
22
+ if not text:
23
+ return 0
24
+ if HAS_TIKTOKEN and _encoding is not None:
25
+ try:
26
+ return len(_encoding.encode(text, disallowed_special=()))
27
+ except Exception:
28
+ pass
29
+ # Fallback heuristic: 1 token is roughly 4 characters
30
+ return len(text) // 4 + (1 if len(text) % 4 > 0 else 0)
31
+
32
+
33
+ class ContextWindowTracker:
34
+ """Tracks token consumption dynamically against a maximum budget capacity."""
35
+
36
+ def __init__(self, max_tokens: int = 8192) -> None:
37
+ self.max_tokens = max_tokens
38
+ self.current_tokens = 0
39
+ self.segments: dict[str, int] = {}
40
+
41
+ def reserve(self, segment_name: str, text: str) -> int:
42
+ """Reserve token budget for a specific context segment."""
43
+ tokens = estimate_tokens(text)
44
+ self.segments[segment_name] = tokens
45
+ self._recalculate()
46
+ return tokens
47
+
48
+ def release(self, segment_name: str) -> None:
49
+ """Release reservation for a context segment."""
50
+ self.segments.pop(segment_name, None)
51
+ self._recalculate()
52
+
53
+ def get_remaining(self) -> int:
54
+ """Get remaining available token budget."""
55
+ return max(0, self.max_tokens - self.current_tokens)
56
+
57
+ def is_overflowed(self) -> bool:
58
+ """Check if current reservations exceed max tokens."""
59
+ return self.current_tokens > self.max_tokens
60
+
61
+ def _recalculate(self) -> None:
62
+ self.current_tokens = sum(self.segments.values())
63
+ logger.debug("Recalculated tokens: %d/%d", self.current_tokens, self.max_tokens)
@@ -0,0 +1,89 @@
1
+ """Foundational primitives and contracts."""
2
+
3
+ from velune.core.errors import *
4
+ from velune.core.types import *
5
+ from velune.kernel.config import (
6
+ ConfigLoader,
7
+ ContextConfig,
8
+ ExecutionConfig,
9
+ MemoryConfig,
10
+ ProjectConfig,
11
+ ProviderEntry,
12
+ ProvidersConfig,
13
+ RetrievalConfig,
14
+ TelemetryConfig,
15
+ VeluneConfig,
16
+ WorkspaceConfig,
17
+ get_default_config,
18
+ )
19
+ from velune.kernel.registry import ServiceContainer, get_container, inject
20
+
21
+ __all__ = [
22
+ # Types
23
+ "AgentRole",
24
+ "AgentMessage",
25
+ "AgentMessageType",
26
+ "AgentResult",
27
+ "ContextPriority",
28
+ "ContextChunk",
29
+ "ContextWindow",
30
+ "InferenceRequest",
31
+ "StreamChunk",
32
+ "InferenceResponse",
33
+ "MemoryType",
34
+ "MemoryRecord",
35
+ "MemoryQuery",
36
+ "CapabilityLevel",
37
+ "ModelCapability",
38
+ "ModelDescriptor",
39
+ "ProviderConfig",
40
+ "ProviderCapabilities",
41
+ "FileNode",
42
+ "SymbolNode",
43
+ "DependencyEdge",
44
+ "TaskStatus",
45
+ "Task",
46
+ "TaskStep",
47
+ "TaskPlan",
48
+ "TaskResult",
49
+ "WorkspaceState",
50
+ "WorkspaceEvent",
51
+ # Config
52
+ "VeluneConfig",
53
+ "ProjectConfig",
54
+ "WorkspaceConfig",
55
+ "ContextConfig",
56
+ "MemoryConfig",
57
+ "RetrievalConfig",
58
+ "ExecutionConfig",
59
+ "ProviderEntry",
60
+ "ProvidersConfig",
61
+ "TelemetryConfig",
62
+ "ConfigLoader",
63
+ "get_default_config",
64
+ # Errors
65
+ "ProviderError",
66
+ "ProviderNotFoundError",
67
+ "ProviderConnectionError",
68
+ "ProviderAuthenticationError",
69
+ "ModelNotFoundError",
70
+ "InferenceError",
71
+ "OrchestrationError",
72
+ "AgentExecutionError",
73
+ "PipelineExecutionError",
74
+ "StateTransitionError",
75
+ "CheckpointError",
76
+ "VeluneMemoryError",
77
+ "VeluneMemoryStoreError",
78
+ "VeluneMemoryRetrievalError",
79
+ "VeluneMemoryConsolidationError",
80
+ "ExecutionError",
81
+ "SandboxError",
82
+ "SnapshotError",
83
+ "RollbackError",
84
+ "ValidationError",
85
+ # Registry
86
+ "ServiceContainer",
87
+ "inject",
88
+ "get_container",
89
+ ]
@@ -0,0 +1,5 @@
1
+ """Re-export BackgroundTaskRegistry under the canonical background module path."""
2
+
3
+ from velune.core.task_registry import BackgroundTaskRegistry
4
+
5
+ __all__ = ["BackgroundTaskRegistry"]
@@ -0,0 +1,37 @@
1
+ """Configuration management re-exported from velune.kernel.config."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from velune.kernel.config import (
6
+ ConfigLoader,
7
+ ConfigService,
8
+ ContextConfig,
9
+ ExecutionConfig,
10
+ MCPConfig,
11
+ MemoryConfig,
12
+ ProjectConfig,
13
+ ProviderEntry,
14
+ ProvidersConfig,
15
+ RetrievalConfig,
16
+ TelemetryConfig,
17
+ VeluneConfig,
18
+ WorkspaceConfig,
19
+ get_default_config,
20
+ )
21
+
22
+ __all__ = [
23
+ "VeluneConfig",
24
+ "ProjectConfig",
25
+ "WorkspaceConfig",
26
+ "ContextConfig",
27
+ "MemoryConfig",
28
+ "RetrievalConfig",
29
+ "ExecutionConfig",
30
+ "ProviderEntry",
31
+ "ProvidersConfig",
32
+ "TelemetryConfig",
33
+ "MCPConfig",
34
+ "ConfigLoader",
35
+ "ConfigService",
36
+ "get_default_config",
37
+ ]
@@ -0,0 +1,90 @@
1
+ """Typed error hierarchy."""
2
+
3
+ from velune.core.errors.catalog import (
4
+ APIKeyMissingError,
5
+ ContextWindowExceededError,
6
+ IndexingFailedError,
7
+ InsufficientVRAMError,
8
+ NoModelsAvailableError,
9
+ OllamaNotRunningError,
10
+ ProviderUnavailableError,
11
+ RateLimitError,
12
+ SSRFAttemptError,
13
+ VeluneError,
14
+ WorkspaceNotInitializedError,
15
+ )
16
+ from velune.core.errors.catalog import (
17
+ ModelNotFoundError as ModelNotFoundVeluneError,
18
+ )
19
+ from velune.core.errors.catalog import (
20
+ PathTraversalError as PathTraversalVeluneError,
21
+ )
22
+ from velune.core.errors.execution import (
23
+ ExecutionError,
24
+ RollbackError,
25
+ SandboxError,
26
+ SnapshotError,
27
+ ValidationError,
28
+ )
29
+ from velune.core.errors.memory import (
30
+ VeluneMemoryConsolidationError,
31
+ VeluneMemoryError,
32
+ VeluneMemoryRetrievalError,
33
+ VeluneMemoryStoreError,
34
+ )
35
+ from velune.core.errors.orchestration import (
36
+ AgentExecutionError,
37
+ CheckpointError,
38
+ OrchestrationError,
39
+ PipelineExecutionError,
40
+ StateTransitionError,
41
+ )
42
+ from velune.core.errors.provider import (
43
+ InferenceError,
44
+ ModelNotFoundError,
45
+ ProviderAuthenticationError,
46
+ ProviderConnectionError,
47
+ ProviderError,
48
+ ProviderNotFoundError,
49
+ )
50
+
51
+ __all__ = [
52
+ # User-facing catalog errors
53
+ "VeluneError",
54
+ "OllamaNotRunningError",
55
+ "ModelNotFoundVeluneError",
56
+ "NoModelsAvailableError",
57
+ "APIKeyMissingError",
58
+ "WorkspaceNotInitializedError",
59
+ "ProviderUnavailableError",
60
+ "ContextWindowExceededError",
61
+ "RateLimitError",
62
+ "InsufficientVRAMError",
63
+ "PathTraversalVeluneError",
64
+ "SSRFAttemptError",
65
+ "IndexingFailedError",
66
+ # Internal provider errors
67
+ "ProviderError",
68
+ "ProviderNotFoundError",
69
+ "ProviderConnectionError",
70
+ "ProviderAuthenticationError",
71
+ "ModelNotFoundError",
72
+ "InferenceError",
73
+ # Internal orchestration errors
74
+ "OrchestrationError",
75
+ "AgentExecutionError",
76
+ "PipelineExecutionError",
77
+ "StateTransitionError",
78
+ "CheckpointError",
79
+ # Internal memory errors
80
+ "VeluneMemoryError",
81
+ "VeluneMemoryStoreError",
82
+ "VeluneMemoryRetrievalError",
83
+ "VeluneMemoryConsolidationError",
84
+ # Internal execution errors
85
+ "ExecutionError",
86
+ "SandboxError",
87
+ "SnapshotError",
88
+ "RollbackError",
89
+ "ValidationError",
90
+ ]
@@ -0,0 +1,188 @@
1
+ """Structured user-facing error catalog.
2
+
3
+ Every error type carries a short title, a cause explanation, and actionable
4
+ fix steps. The CLI renders these via ``velune.cli.rendering.error_panel``
5
+ instead of printing raw exception text.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+
11
+ class VeluneError(Exception):
12
+ """Base class for all user-facing Velune errors with rich display metadata.
13
+
14
+ Subclasses declare ``title``, ``cause``, ``fix``, and optionally
15
+ ``docs_url`` as class attributes. The ``__init__`` accepts an optional
16
+ *detail* string (e.g. the underlying exception message) and an optional
17
+ *cause_override* to substitute the class-level ``cause`` at runtime when
18
+ the root cause is known precisely.
19
+ """
20
+
21
+ title: str = "An unexpected error occurred"
22
+ cause: str = "An internal error was encountered."
23
+ fix: list[str] = ["Run `velune doctor` to diagnose your environment."]
24
+ docs_url: str | None = None
25
+
26
+ def __init__(
27
+ self,
28
+ detail: str | None = None,
29
+ *,
30
+ cause_override: str | None = None,
31
+ ) -> None:
32
+ self._detail = detail
33
+ self._cause_override = cause_override
34
+ super().__init__(detail or self.title)
35
+
36
+ def get_cause(self) -> str:
37
+ return self._cause_override or self.cause
38
+
39
+ def get_detail(self) -> str | None:
40
+ return self._detail
41
+
42
+
43
+ # ---------------------------------------------------------------------------
44
+ # Provider / model errors
45
+ # ---------------------------------------------------------------------------
46
+
47
+
48
+ class OllamaNotRunningError(VeluneError):
49
+ title = "Ollama is not running"
50
+ cause = "Velune tried to connect to Ollama at localhost:11434 but the connection was refused."
51
+ fix = [
52
+ "Run `ollama serve` in a separate terminal window",
53
+ "Then retry your command, or run `velune doctor` to verify all providers",
54
+ ]
55
+
56
+
57
+ class ModelNotFoundError(VeluneError):
58
+ title = "Model not found"
59
+ cause = "The requested model ID is not registered in the Velune model catalog."
60
+ fix = [
61
+ "Run `velune models scan` to discover available models",
62
+ "Check the model ID for typos",
63
+ "Run `velune models list` to see all registered models",
64
+ ]
65
+
66
+
67
+ class NoModelsAvailableError(VeluneError):
68
+ title = "No models available"
69
+ cause = "No models are configured for any provider in this workspace."
70
+ fix = [
71
+ "Run `velune models scan` to discover local Ollama models",
72
+ "Configure an API key with `velune config set providers.anthropic.api_key <key>`",
73
+ "Run `velune doctor` to diagnose provider connectivity",
74
+ ]
75
+
76
+
77
+ class APIKeyMissingError(VeluneError):
78
+ title = "API key missing"
79
+ cause = (
80
+ "A cloud provider is configured but no API key was found in the environment or keystore."
81
+ )
82
+ fix = [
83
+ "Set the API key with `velune config set providers.<name>.api_key <key>`",
84
+ "Or export it as an environment variable (e.g. ANTHROPIC_API_KEY=...)",
85
+ "Run `velune doctor` to see which providers are missing keys",
86
+ ]
87
+
88
+
89
+ class ProviderUnavailableError(VeluneError):
90
+ title = "Provider unavailable"
91
+ cause = "The model provider failed its health check and cannot accept inference requests."
92
+ fix = [
93
+ "Run `velune doctor check` to identify which providers are unreachable",
94
+ "Verify the provider service is running (e.g. `ollama serve` for Ollama)",
95
+ "Check API key and network connectivity for cloud providers",
96
+ ]
97
+
98
+
99
+ class RateLimitError(VeluneError):
100
+ title = "Rate limit reached"
101
+ cause = "The cloud provider has temporarily limited requests from this API key."
102
+ fix = [
103
+ "Wait a moment and retry the command",
104
+ "Use a local model (Ollama) as a fallback to avoid rate limits",
105
+ "Check your provider's dashboard for quota and usage details",
106
+ ]
107
+
108
+
109
+ class ContextWindowExceededError(VeluneError):
110
+ title = "Context window exceeded"
111
+ cause = "The combined prompt and context is larger than the model's maximum context length."
112
+ fix = [
113
+ "Use a model with a larger context window (`velune models list`)",
114
+ "Reduce the amount of repository context by narrowing the file selection",
115
+ "Split the task into smaller, focused sub-tasks",
116
+ ]
117
+
118
+
119
+ class InsufficientVRAMError(VeluneError):
120
+ title = "Insufficient VRAM"
121
+ cause = "The selected local model requires more GPU memory than is currently available."
122
+ fix = [
123
+ "Close other GPU-intensive applications to free VRAM",
124
+ "Use a smaller quantized version of the model (e.g. q4_K_M instead of q8_0)",
125
+ "Run `velune doctor` to view your hardware profile and compatible models",
126
+ ]
127
+
128
+
129
+ # ---------------------------------------------------------------------------
130
+ # Workspace / configuration errors
131
+ # ---------------------------------------------------------------------------
132
+
133
+
134
+ class WorkspaceNotInitializedError(VeluneError):
135
+ title = "Workspace not initialized"
136
+ cause = "This directory does not contain a Velune workspace (velune.toml not found)."
137
+ fix = [
138
+ "Run `velune workspace init` to initialize this directory as a Velune workspace",
139
+ "Or change to a directory that already contains a velune.toml",
140
+ "Use `--workspace <path>` to point to an existing workspace",
141
+ ]
142
+
143
+
144
+ # ---------------------------------------------------------------------------
145
+ # Security errors
146
+ # ---------------------------------------------------------------------------
147
+
148
+
149
+ class PathTraversalError(VeluneError):
150
+ title = "Path traversal blocked"
151
+ cause = (
152
+ "A file path resolved to a location outside the workspace root. "
153
+ "This is a security violation."
154
+ )
155
+ fix = [
156
+ "Ensure all file paths are relative to the workspace root",
157
+ "Do not use `..` sequences or absolute paths that escape the workspace",
158
+ "Run `velune workspace info` to confirm your current workspace root",
159
+ ]
160
+
161
+
162
+ class SSRFAttemptError(VeluneError):
163
+ title = "Internal network request blocked"
164
+ cause = (
165
+ "A web tool attempted to reach an internal or metadata network address "
166
+ "(e.g. cloud provider IMDS, RFC 1918 private ranges). "
167
+ "This request was blocked to prevent SSRF attacks."
168
+ )
169
+ fix = [
170
+ "Only fetch publicly accessible URLs",
171
+ "Avoid internal network addresses (169.254.x.x, 10.x.x.x, 192.168.x.x, etc.)",
172
+ "If this was unexpected, inspect workspace content for injected URLs",
173
+ ]
174
+
175
+
176
+ # ---------------------------------------------------------------------------
177
+ # Repository / indexing errors
178
+ # ---------------------------------------------------------------------------
179
+
180
+
181
+ class IndexingFailedError(VeluneError):
182
+ title = "Repository indexing failed"
183
+ cause = "Velune encountered an error while indexing the repository AST and structure."
184
+ fix = [
185
+ "Run `velune workspace reindex` to force a fresh index",
186
+ "Check file permissions in the workspace directory",
187
+ "Run `velune doctor` to verify the workspace is correctly configured",
188
+ ]
@@ -0,0 +1,31 @@
1
+ """Execution-related errors."""
2
+
3
+
4
+ class ExecutionError(Exception):
5
+ """Base exception for execution errors."""
6
+
7
+ pass
8
+
9
+
10
+ class SandboxError(ExecutionError):
11
+ """Raised when sandbox operation fails."""
12
+
13
+ pass
14
+
15
+
16
+ class SnapshotError(ExecutionError):
17
+ """Raised when snapshot operation fails."""
18
+
19
+ pass
20
+
21
+
22
+ class RollbackError(ExecutionError):
23
+ """Raised when rollback operation fails."""
24
+
25
+ pass
26
+
27
+
28
+ class ValidationError(ExecutionError):
29
+ """Raised when validation fails."""
30
+
31
+ pass