cct-cli 0.7.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 (325) hide show
  1. calc_terminal/__init__.py +14 -0
  2. calc_terminal/__main__.py +14 -0
  3. calc_terminal/activity.py +1334 -0
  4. calc_terminal/agent.py +3387 -0
  5. calc_terminal/agent_runtime.py +519 -0
  6. calc_terminal/ai_context.py +447 -0
  7. calc_terminal/ai_modes.py +752 -0
  8. calc_terminal/ai_personalization.py +286 -0
  9. calc_terminal/ai_preview_feedback.py +213 -0
  10. calc_terminal/aicore.py +2572 -0
  11. calc_terminal/anim.py +367 -0
  12. calc_terminal/app.py +3685 -0
  13. calc_terminal/art.py +639 -0
  14. calc_terminal/atomsim.py +368 -0
  15. calc_terminal/attachments.py +743 -0
  16. calc_terminal/benchmark_system.py +414 -0
  17. calc_terminal/browser/__init__.py +36 -0
  18. calc_terminal/browser/browser_state.py +346 -0
  19. calc_terminal/browser/devserver.py +176 -0
  20. calc_terminal/browser/engine.py +494 -0
  21. calc_terminal/browser/navigation.py +84 -0
  22. calc_terminal/browser/preview.py +429 -0
  23. calc_terminal/browser/preview_entry.py +95 -0
  24. calc_terminal/browser/project_detector.py +144 -0
  25. calc_terminal/browser/server.py +449 -0
  26. calc_terminal/browser/state.py +75 -0
  27. calc_terminal/browser/watcher.py +99 -0
  28. calc_terminal/browser_gui/__init__.py +1 -0
  29. calc_terminal/browser_gui/__main__.py +3 -0
  30. calc_terminal/browser_gui/launcher.py +173 -0
  31. calc_terminal/browser_gui/playwright_browser.py +117 -0
  32. calc_terminal/browser_gui/qt_browser.py +1501 -0
  33. calc_terminal/browser_gui/webview_browser.py +57 -0
  34. calc_terminal/capabilities/__init__.py +35 -0
  35. calc_terminal/capabilities/adapters/__init__.py +33 -0
  36. calc_terminal/capabilities/adapters/bioinformatics.py +204 -0
  37. calc_terminal/capabilities/adapters/browser_adapter.py +205 -0
  38. calc_terminal/capabilities/adapters/filesystem.py +206 -0
  39. calc_terminal/capabilities/adapters/git_adapter.py +202 -0
  40. calc_terminal/capabilities/adapters/jupyter_adapter.py +138 -0
  41. calc_terminal/capabilities/adapters/ml_frameworks.py +158 -0
  42. calc_terminal/capabilities/adapters/platforms.py +200 -0
  43. calc_terminal/capabilities/adapters/python_exec.py +93 -0
  44. calc_terminal/capabilities/adapters/quantum_adapter.py +150 -0
  45. calc_terminal/capabilities/adapters/scientific_comp.py +123 -0
  46. calc_terminal/capabilities/adapters/structural_bio.py +161 -0
  47. calc_terminal/capabilities/adapters/terminal.py +99 -0
  48. calc_terminal/capabilities/bus.py +178 -0
  49. calc_terminal/capabilities/discovery.py +207 -0
  50. calc_terminal/capabilities/schema.py +221 -0
  51. calc_terminal/cat.ico +0 -0
  52. calc_terminal/cat_browser.py +2018 -0
  53. calc_terminal/chat_store.py +703 -0
  54. calc_terminal/cli.py +1178 -0
  55. calc_terminal/code_editor.py +640 -0
  56. calc_terminal/collaboration.py +723 -0
  57. calc_terminal/commands_data.py +139 -0
  58. calc_terminal/compatibility_engine.py +352 -0
  59. calc_terminal/compute/__init__.py +31 -0
  60. calc_terminal/compute/fabric.py +350 -0
  61. calc_terminal/config.py +227 -0
  62. calc_terminal/core/__init__.py +41 -0
  63. calc_terminal/core/checkpoint.py +156 -0
  64. calc_terminal/core/input/__init__.py +45 -0
  65. calc_terminal/core/mode_registry.py +300 -0
  66. calc_terminal/core/project_graph.py +172 -0
  67. calc_terminal/core/recovery.py +129 -0
  68. calc_terminal/core/security_layer.py +112 -0
  69. calc_terminal/core/task_graph.py +202 -0
  70. calc_terminal/core/unified_runtime.py +184 -0
  71. calc_terminal/core/verification.py +257 -0
  72. calc_terminal/customization.py +1566 -0
  73. calc_terminal/derivations.py +153 -0
  74. calc_terminal/device_control.py +263 -0
  75. calc_terminal/diagnostics/__init__.py +27 -0
  76. calc_terminal/diagnostics/doctor_engine.py +382 -0
  77. calc_terminal/diagnostics/self_test.py +247 -0
  78. calc_terminal/doctor.py +519 -0
  79. calc_terminal/easter_eggs.py +274 -0
  80. calc_terminal/editor/__init__.py +1 -0
  81. calc_terminal/editor/actions.py +263 -0
  82. calc_terminal/editor/commands.py +160 -0
  83. calc_terminal/editor/shortcuts.py +226 -0
  84. calc_terminal/engine.py +259 -0
  85. calc_terminal/errors.py +120 -0
  86. calc_terminal/event_stream.py +146 -0
  87. calc_terminal/eventbus.py +133 -0
  88. calc_terminal/extensions.py +733 -0
  89. calc_terminal/fallback_cli.py +1321 -0
  90. calc_terminal/first_run.py +265 -0
  91. calc_terminal/fomoji_auth.py +1043 -0
  92. calc_terminal/formulas.py +82 -0
  93. calc_terminal/fs_cache.py +121 -0
  94. calc_terminal/fs_watcher.py +277 -0
  95. calc_terminal/game.py +193 -0
  96. calc_terminal/gen1.py +5 -0
  97. calc_terminal/generators.py +245 -0
  98. calc_terminal/gestures/__init__.py +42 -0
  99. calc_terminal/gestures/bindings.py +175 -0
  100. calc_terminal/gestures/manager.py +477 -0
  101. calc_terminal/goodbye.py +363 -0
  102. calc_terminal/gpu3d.py +290 -0
  103. calc_terminal/graphs.py +358 -0
  104. calc_terminal/hardware_analyzer.py +440 -0
  105. calc_terminal/host/__init__.py +30 -0
  106. calc_terminal/host/browser_manager.py +187 -0
  107. calc_terminal/host/desktop.py +1386 -0
  108. calc_terminal/host/launcher.py +395 -0
  109. calc_terminal/host/terminal.py +279 -0
  110. calc_terminal/identity.py +216 -0
  111. calc_terminal/input/__init__.py +54 -0
  112. calc_terminal/input/capabilities.py +258 -0
  113. calc_terminal/input/focus.py +87 -0
  114. calc_terminal/input/gestures.py +64 -0
  115. calc_terminal/input/pointer.py +114 -0
  116. calc_terminal/input/touch.py +345 -0
  117. calc_terminal/keys.py +84 -0
  118. calc_terminal/live_automation.py +165 -0
  119. calc_terminal/mathtext.py +433 -0
  120. calc_terminal/mcp.py +386 -0
  121. calc_terminal/memory.py +337 -0
  122. calc_terminal/memory_v2.py +479 -0
  123. calc_terminal/metrics.py +333 -0
  124. calc_terminal/mode_detection.py +146 -0
  125. calc_terminal/model.py +2431 -0
  126. calc_terminal/model_router.py +665 -0
  127. calc_terminal/models/__init__.py +0 -0
  128. calc_terminal/models/active_state.py +187 -0
  129. calc_terminal/models/dynamic_registry.py +584 -0
  130. calc_terminal/models/manager.py +781 -0
  131. calc_terminal/models/model_metadata.json +3526 -0
  132. calc_terminal/models/profiles.py +194 -0
  133. calc_terminal/models/registry.py +265 -0
  134. calc_terminal/models/schema.py +197 -0
  135. calc_terminal/models/validator.py +287 -0
  136. calc_terminal/models/verification_engine.py +368 -0
  137. calc_terminal/native_picker.py +215 -0
  138. calc_terminal/ollama_catalog.py +279 -0
  139. calc_terminal/ollama_download.py +233 -0
  140. calc_terminal/orchestrator.py +304 -0
  141. calc_terminal/package_research.py +322 -0
  142. calc_terminal/packages.py +1024 -0
  143. calc_terminal/pc_specs.py +116 -0
  144. calc_terminal/permissions.py +334 -0
  145. calc_terminal/pet.py +106 -0
  146. calc_terminal/pipeline.py +505 -0
  147. calc_terminal/platform/__init__.py +491 -0
  148. calc_terminal/platform/desktop.py +491 -0
  149. calc_terminal/platform/web.py +781 -0
  150. calc_terminal/preview/__init__.py +1 -0
  151. calc_terminal/preview/dev_server.py +303 -0
  152. calc_terminal/preview/diagnostics.py +131 -0
  153. calc_terminal/preview/live_reload.py +66 -0
  154. calc_terminal/preview/manager.py +129 -0
  155. calc_terminal/project_stats.py +209 -0
  156. calc_terminal/projects.py +328 -0
  157. calc_terminal/providers/__init__.py +0 -0
  158. calc_terminal/providers/adapters/__init__.py +80 -0
  159. calc_terminal/providers/adapters/anthropic_adapter.py +127 -0
  160. calc_terminal/providers/adapters/base.py +106 -0
  161. calc_terminal/providers/adapters/chinese_adapters.py +420 -0
  162. calc_terminal/providers/adapters/gemini_adapter.py +101 -0
  163. calc_terminal/providers/adapters/ollama_adapter.py +83 -0
  164. calc_terminal/providers/adapters/openai_adapter.py +159 -0
  165. calc_terminal/providers/adapters/other_adapters.py +246 -0
  166. calc_terminal/providers/anthropic_provider.py +172 -0
  167. calc_terminal/providers/auto_update.py +416 -0
  168. calc_terminal/providers/base_provider.py +105 -0
  169. calc_terminal/providers/discovery_manager.py +207 -0
  170. calc_terminal/providers/gemini_provider.py +178 -0
  171. calc_terminal/providers/lifecycle.py +767 -0
  172. calc_terminal/providers/ollama_adapter.py +707 -0
  173. calc_terminal/providers/openai_provider.py +254 -0
  174. calc_terminal/providers/provider_manager.py +1827 -0
  175. calc_terminal/providers/providers.json +4075 -0
  176. calc_terminal/reactionsim.py +279 -0
  177. calc_terminal/registry.py +337 -0
  178. calc_terminal/report.py +162 -0
  179. calc_terminal/research/__init__.py +45 -0
  180. calc_terminal/research/artifact_intel.py +126 -0
  181. calc_terminal/research/data_lineage.py +123 -0
  182. calc_terminal/research/experiment_ledger.py +303 -0
  183. calc_terminal/research/reproducibility.py +131 -0
  184. calc_terminal/resilience/__init__.py +47 -0
  185. calc_terminal/resilience/agent_state.py +121 -0
  186. calc_terminal/resilience/capability_matcher.py +174 -0
  187. calc_terminal/resilience/circuit_breaker.py +158 -0
  188. calc_terminal/resilience/failover_engine.py +230 -0
  189. calc_terminal/resilience/health_monitor.py +192 -0
  190. calc_terminal/resilience/ollama_adapter.py +125 -0
  191. calc_terminal/resilience/orchestrator.py +312 -0
  192. calc_terminal/resilience/types.py +134 -0
  193. calc_terminal/sandbox.py +98 -0
  194. calc_terminal/scires.py +558 -0
  195. calc_terminal/security_scanner.py +126 -0
  196. calc_terminal/session.py +294 -0
  197. calc_terminal/sim3d.py +206 -0
  198. calc_terminal/solver.py +276 -0
  199. calc_terminal/sound.py +127 -0
  200. calc_terminal/task_reports.py +287 -0
  201. calc_terminal/terminal_host.py +201 -0
  202. calc_terminal/terminal_identity.py +411 -0
  203. calc_terminal/test_ai_mode_reliability.py +344 -0
  204. calc_terminal/test_browser.py +368 -0
  205. calc_terminal/test_code_editor_upgrade.py +485 -0
  206. calc_terminal/test_customization.py +1148 -0
  207. calc_terminal/test_customization_ui.py +612 -0
  208. calc_terminal/test_dynamic_registry.py +304 -0
  209. calc_terminal/test_extensions.py +436 -0
  210. calc_terminal/test_overhaul.py +557 -0
  211. calc_terminal/test_project_detect.py +255 -0
  212. calc_terminal/test_root_cause_fix.py +527 -0
  213. calc_terminal/test_stability.py +532 -0
  214. calc_terminal/test_terminal_identity.py +132 -0
  215. calc_terminal/test_v079_speed.py +460 -0
  216. calc_terminal/theme.py +1107 -0
  217. calc_terminal/timeline.py +139 -0
  218. calc_terminal/todos.py +246 -0
  219. calc_terminal/tool_call_normalizer.py +419 -0
  220. calc_terminal/tui.py +104 -0
  221. calc_terminal/ui/__init__.py +8 -0
  222. calc_terminal/ui/activity_panel.py +231 -0
  223. calc_terminal/ui/activity_stream_panel.py +238 -0
  224. calc_terminal/ui/animations.py +122 -0
  225. calc_terminal/ui/app.py +7271 -0
  226. calc_terminal/ui/attach_panel.py +597 -0
  227. calc_terminal/ui/attachments.py +424 -0
  228. calc_terminal/ui/backup_panel.py +810 -0
  229. calc_terminal/ui/browser_shell.py +887 -0
  230. calc_terminal/ui/cat_agent.py +357 -0
  231. calc_terminal/ui/chats_panel.py +899 -0
  232. calc_terminal/ui/command_palette.py +125 -0
  233. calc_terminal/ui/command_palette_modal.py +166 -0
  234. calc_terminal/ui/composer.py +1141 -0
  235. calc_terminal/ui/context_menu.py +197 -0
  236. calc_terminal/ui/conversation.py +1435 -0
  237. calc_terminal/ui/customization_panel.py +1229 -0
  238. calc_terminal/ui/dashboard.py +404 -0
  239. calc_terminal/ui/design_system.py +557 -0
  240. calc_terminal/ui/diff_panel.py +213 -0
  241. calc_terminal/ui/editor.py +2102 -0
  242. calc_terminal/ui/empty_state.py +302 -0
  243. calc_terminal/ui/events.py +487 -0
  244. calc_terminal/ui/extensions_panel.py +815 -0
  245. calc_terminal/ui/footer.py +166 -0
  246. calc_terminal/ui/gestures_panel.py +383 -0
  247. calc_terminal/ui/goodbye_screen.py +100 -0
  248. calc_terminal/ui/header.py +1034 -0
  249. calc_terminal/ui/help_panel.py +254 -0
  250. calc_terminal/ui/live_activities.py +914 -0
  251. calc_terminal/ui/mcp_panel.py +570 -0
  252. calc_terminal/ui/memory_center.py +524 -0
  253. calc_terminal/ui/mode_colors_panel.py +525 -0
  254. calc_terminal/ui/nav_screens.py +747 -0
  255. calc_terminal/ui/ollama_panel.py +536 -0
  256. calc_terminal/ui/palette.py +221 -0
  257. calc_terminal/ui/permission_panel.py +269 -0
  258. calc_terminal/ui/personalization_panel.py +517 -0
  259. calc_terminal/ui/personalize_center.py +1568 -0
  260. calc_terminal/ui/preview_panel.py +441 -0
  261. calc_terminal/ui/resizers.py +402 -0
  262. calc_terminal/ui/sidebar.py +1285 -0
  263. calc_terminal/ui/statusbar.py +168 -0
  264. calc_terminal/ui/theme_css.py +1396 -0
  265. calc_terminal/ui/thinking.py +226 -0
  266. calc_terminal/ui/timeline_panel.py +102 -0
  267. calc_terminal/ui/todo_panel.py +193 -0
  268. calc_terminal/ui/viewport.py +136 -0
  269. calc_terminal/ui/vision_panel.py +489 -0
  270. calc_terminal/ui/welcome_modal.py +343 -0
  271. calc_terminal/ui/widgets.py +160 -0
  272. calc_terminal/ui/workspace.py +831 -0
  273. calc_terminal/viewers/__init__.py +1 -0
  274. calc_terminal/viewers/document_viewer.py +252 -0
  275. calc_terminal/viewers/image_viewer.py +241 -0
  276. calc_terminal/viewers/pdf_viewer.py +203 -0
  277. calc_terminal/viewers/presentation_viewer.py +164 -0
  278. calc_terminal/viewers/registry.py +120 -0
  279. calc_terminal/viewers/spreadsheet_viewer.py +204 -0
  280. calc_terminal/vision/__init__.py +89 -0
  281. calc_terminal/vision/analysis.py +194 -0
  282. calc_terminal/vision/annotations.py +297 -0
  283. calc_terminal/vision/capture.py +171 -0
  284. calc_terminal/vision/context.py +231 -0
  285. calc_terminal/vision/correlation.py +169 -0
  286. calc_terminal/vision/cursor.py +258 -0
  287. calc_terminal/vision/events.py +66 -0
  288. calc_terminal/vision/frame_pipeline.py +259 -0
  289. calc_terminal/vision/priority.py +218 -0
  290. calc_terminal/vision/provider.py +180 -0
  291. calc_terminal/vision/safety.py +149 -0
  292. calc_terminal/vision/session.py +281 -0
  293. calc_terminal/vision/verify.py +162 -0
  294. calc_terminal/vision.py +514 -0
  295. calc_terminal/vscode_integration.py +113 -0
  296. calc_terminal/web/__init__.py +8 -0
  297. calc_terminal/web/cat_runtime.py +710 -0
  298. calc_terminal/web/server.py +2891 -0
  299. calc_terminal/web/static/css/app.css +3152 -0
  300. calc_terminal/web/static/icons/badge-72.png +0 -0
  301. calc_terminal/web/static/icons/cat.ico +0 -0
  302. calc_terminal/web/static/icons/icon-128.png +0 -0
  303. calc_terminal/web/static/icons/icon-144.png +0 -0
  304. calc_terminal/web/static/icons/icon-152.png +0 -0
  305. calc_terminal/web/static/icons/icon-192.png +0 -0
  306. calc_terminal/web/static/icons/icon-384.png +0 -0
  307. calc_terminal/web/static/icons/icon-512.png +0 -0
  308. calc_terminal/web/static/icons/icon-72.png +0 -0
  309. calc_terminal/web/static/icons/icon-96.png +0 -0
  310. calc_terminal/web/static/icons/icon.svg +34 -0
  311. calc_terminal/web/static/icons/new-project.png +0 -0
  312. calc_terminal/web/static/icons/open-project.png +0 -0
  313. calc_terminal/web/static/index.html +734 -0
  314. calc_terminal/web/static/js/app.js +2403 -0
  315. calc_terminal/web/static/manifest.json +88 -0
  316. calc_terminal/web/static/sw.js +230 -0
  317. calc_terminal/workflow_engine.py +769 -0
  318. calc_terminal/workspace.py +593 -0
  319. calc_terminal/workspace_index.py +385 -0
  320. cct_cli-0.7.9.0.dist-info/METADATA +210 -0
  321. cct_cli-0.7.9.0.dist-info/RECORD +325 -0
  322. cct_cli-0.7.9.0.dist-info/WHEEL +5 -0
  323. cct_cli-0.7.9.0.dist-info/entry_points.txt +4 -0
  324. cct_cli-0.7.9.0.dist-info/licenses/LICENSE +21 -0
  325. cct_cli-0.7.9.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,101 @@
1
+ """
2
+ calc_terminal/providers/adapters/gemini_adapter.py
3
+ ==================================================
4
+ Google Gemini Provider Adapter with live discovery and Gemini 2.5 support.
5
+ """
6
+
7
+ import requests
8
+ from typing import List
9
+
10
+ from .base import BaseProviderAdapter
11
+ from ...models.schema import ModelInfo
12
+ from ...models.validator import ModelValidator
13
+
14
+
15
+ class GeminiAdapter(BaseProviderAdapter):
16
+ provider_id = "gemini"
17
+ display_name = "Google Gemini"
18
+ company = "Google"
19
+ region = "US"
20
+ api_base = "https://generativelanguage.googleapis.com/v1beta"
21
+ authentication_type = "query_param"
22
+ documentation_url = "https://ai.google.dev/gemini-api/docs/models/gemini"
23
+
24
+ CATALOG_MODELS = {
25
+ "gemini-2.5-pro": {
26
+ "display_name": "Gemini 2.5 Pro",
27
+ "family": "Gemini",
28
+ "version": "2.5",
29
+ "context_window": 2000000,
30
+ "max_output_tokens": 65536,
31
+ "capabilities": ["reasoning", "coding", "vision", "audio", "tools", "streaming", "long_context"],
32
+ "pricing": {"input_price_per_1m": 1.25, "output_price_per_1m": 5.0},
33
+ "recommendation_badges": ["Best for Coding", "Best for Research"],
34
+ },
35
+ "gemini-2.5-flash": {
36
+ "display_name": "Gemini 2.5 Flash",
37
+ "family": "Gemini",
38
+ "version": "2.5",
39
+ "context_window": 1000000,
40
+ "max_output_tokens": 32768,
41
+ "capabilities": ["reasoning", "coding", "vision", "tools", "streaming", "fast", "long_context"],
42
+ "pricing": {"input_price_per_1m": 0.1, "output_price_per_1m": 0.4},
43
+ "recommendation_badges": ["Best Fast Model", "Best Budget Model"],
44
+ },
45
+ "gemini-2.0-flash": {
46
+ "display_name": "Gemini 2.0 Flash",
47
+ "family": "Gemini",
48
+ "version": "2.0",
49
+ "context_window": 1000000,
50
+ "max_output_tokens": 8192,
51
+ "capabilities": ["vision", "coding", "tools", "streaming", "fast"],
52
+ "pricing": {"input_price_per_1m": 0.1, "output_price_per_1m": 0.4},
53
+ "recommendation_badges": ["Best Fast Model"],
54
+ },
55
+ "gemini-2.0-flash-thinking": {
56
+ "display_name": "Gemini 2.0 Flash Thinking",
57
+ "family": "Gemini",
58
+ "version": "2.0",
59
+ "context_window": 1000000,
60
+ "max_output_tokens": 65536,
61
+ "reasoning_levels": ["high"],
62
+ "capabilities": ["reasoning", "coding", "vision", "tools", "streaming"],
63
+ "pricing": {"input_price_per_1m": 0.15, "output_price_per_1m": 0.6},
64
+ "recommendation_badges": ["Best for Reasoning"],
65
+ },
66
+ }
67
+
68
+ def discover_models(self, timeout: float = 8.0) -> List[ModelInfo]:
69
+ base = self.get_api_base()
70
+ key = self.get_api_key()
71
+ params = {}
72
+ if key:
73
+ params["key"] = key
74
+
75
+ discovered_ids = []
76
+ try:
77
+ resp = requests.get(f"{base}/models", params=params, timeout=timeout)
78
+ if resp.status_code == 200:
79
+ models = resp.json().get("models", [])
80
+ for m in models:
81
+ name = str(m.get("name", "")).strip()
82
+ if "/" in name:
83
+ name = name.split("/")[-1]
84
+ if name and not any(name.startswith(x) for x in ("embedding", "aqa", "imagen")):
85
+ discovered_ids.append(name)
86
+ except Exception:
87
+ pass
88
+
89
+ for cat_id in self.CATALOG_MODELS:
90
+ if cat_id not in discovered_ids:
91
+ discovered_ids.append(cat_id)
92
+
93
+ results = []
94
+ for mid in discovered_ids:
95
+ meta = dict(self.CATALOG_MODELS.get(mid, {}))
96
+ meta["model_id"] = mid
97
+ meta["endpoint"] = base
98
+ val = ModelValidator.validate_raw(meta, self.provider_id, self.config)
99
+ if val.is_valid and val.model_info:
100
+ results.append(val.model_info)
101
+ return results
@@ -0,0 +1,83 @@
1
+ """
2
+ calc_terminal/providers/adapters/ollama_adapter.py
3
+ ==================================================
4
+ Ollama Provider Adapter for Local and Cloud models.
5
+ """
6
+
7
+ import requests
8
+ from typing import List
9
+
10
+ from .base import BaseProviderAdapter
11
+ from ...models.schema import ModelInfo, AVAILABILITY_LOCAL, AVAILABILITY_CLOUD, AVAILABILITY_OPEN_WEIGHT
12
+ from ...models.validator import ModelValidator
13
+
14
+
15
+ class OllamaAdapter(BaseProviderAdapter):
16
+ provider_id = "ollama"
17
+ display_name = "Ollama (Local / Cloud)"
18
+ company = "Ollama"
19
+ region = "Local"
20
+ api_base = "http://localhost:11434"
21
+ authentication_type = "none"
22
+ documentation_url = "https://ollama.com"
23
+
24
+ DEFAULT_FALLBACKS = [
25
+ "llama3.3", "deepseek-r1", "qwen2.5-coder", "mistral", "phi4", "codellama"
26
+ ]
27
+
28
+ @property
29
+ def is_local(self) -> bool:
30
+ base = self.get_api_base()
31
+ return not ("ollama.ai" in base or "cloud" in base)
32
+
33
+ def discover_models(self, timeout: float = 6.0) -> List[ModelInfo]:
34
+ base = self.get_api_base()
35
+ models = []
36
+
37
+ is_cloud = "ollama.ai" in base or "cloud" in base
38
+
39
+ try:
40
+ resp = requests.get(f"{base}/api/tags", timeout=timeout)
41
+ if resp.status_code == 200:
42
+ raw_models = resp.json().get("models", [])
43
+ for m in raw_models:
44
+ name = str(m.get("name", "")).strip()
45
+ if name:
46
+ meta = {
47
+ "model_id": name,
48
+ "display_name": f"{name} (Local)" if not is_cloud else f"{name} (Cloud)",
49
+ "family": name.split(":")[0].capitalize(),
50
+ "availability": AVAILABILITY_CLOUD if is_cloud else AVAILABILITY_LOCAL,
51
+ "capabilities": ["chat", "streaming", "local" if not is_cloud else "cloud"],
52
+ "tags": ["local" if not is_cloud else "cloud", "open_weight"],
53
+ "endpoint": base,
54
+ "verified": True,
55
+ }
56
+ val = ModelValidator.validate_raw(meta, self.provider_id, self.config)
57
+ if val.is_valid and val.model_info:
58
+ val.model_info.local = not is_cloud
59
+ val.model_info.cloud = is_cloud
60
+ val.model_info.recommendation_badges = ["Best Local Model"] if not is_cloud else []
61
+ models.append(val.model_info)
62
+ except Exception:
63
+ pass
64
+
65
+ # If local Ollama isn't currently running, return standard installable catalog as preview
66
+ if not models:
67
+ for name in self.DEFAULT_FALLBACKS:
68
+ meta = {
69
+ "model_id": name,
70
+ "display_name": f"{name} (Ollama)",
71
+ "availability": AVAILABILITY_LOCAL,
72
+ "capabilities": ["chat", "streaming", "local"],
73
+ "tags": ["local", "open_weight"],
74
+ "endpoint": base,
75
+ "source": "fallback",
76
+ }
77
+ val = ModelValidator.validate_raw(meta, self.provider_id, self.config)
78
+ if val.is_valid and val.model_info:
79
+ val.model_info.local = True
80
+ val.model_info.cloud = False
81
+ models.append(val.model_info)
82
+
83
+ return models
@@ -0,0 +1,159 @@
1
+ """
2
+ calc_terminal/providers/adapters/openai_adapter.py
3
+ =================================================
4
+ OpenAI Provider Adapter with live discovery and 2026 model coverage.
5
+
6
+ Includes native metadata for:
7
+ - GPT-6 Astra (gpt-6-astra):
8
+ * Reasoning levels: low, medium, high, xhigh, max
9
+ * Context window: 1,050,000 tokens
10
+ * Max output tokens: 128,000 tokens
11
+ * Capabilities: reasoning, coding, vision, computer_use, research,
12
+ document_workflows, tools, streaming, long_context
13
+ - GPT-5.6 series (Sol, Terra, Luna)
14
+ - o3 and o1 series (o3, o3-mini, o1, o1-mini)
15
+ - GPT-4o and GPT-4o-mini
16
+ """
17
+
18
+ import requests
19
+ from typing import List, Optional
20
+
21
+ from .base import BaseProviderAdapter
22
+ from ...models.schema import ModelInfo, STATUS_ACTIVE, AVAILABILITY_PAID_API
23
+ from ...models.validator import ModelValidator
24
+
25
+
26
+ class OpenAIAdapter(BaseProviderAdapter):
27
+ provider_id = "openai"
28
+ display_name = "OpenAI"
29
+ company = "OpenAI"
30
+ region = "US"
31
+ api_base = "https://api.openai.com/v1"
32
+ authentication_type = "bearer_token"
33
+ documentation_url = "https://platform.openai.com/docs/models"
34
+
35
+ # Known flagship catalog specifications
36
+ CATALOG_MODELS = {
37
+ "gpt-6-astra": {
38
+ "display_name": "GPT-6 Astra",
39
+ "family": "GPT",
40
+ "version": "6",
41
+ "release_date": "2026-03",
42
+ "context_window": 1050000,
43
+ "max_output_tokens": 128000,
44
+ "reasoning_levels": ["low", "medium", "high", "xhigh", "max"],
45
+ "modalities": ["text", "image"],
46
+ "capabilities": [
47
+ "reasoning", "coding", "vision", "computer_use", "research",
48
+ "document_workflows", "tools", "streaming", "long_context"
49
+ ],
50
+ "pricing": {"input_price_per_1m": 5.0, "output_price_per_1m": 20.0},
51
+ "recommendation_badges": ["Best for Coding", "Best for Reasoning", "Best Agent Model"],
52
+ },
53
+ "gpt-5.6-sol": {
54
+ "display_name": "GPT-5.6 Sol",
55
+ "family": "GPT",
56
+ "version": "5.6",
57
+ "context_window": 512000,
58
+ "max_output_tokens": 64000,
59
+ "capabilities": ["reasoning", "coding", "vision", "tools", "streaming", "long_context"],
60
+ "pricing": {"input_price_per_1m": 2.5, "output_price_per_1m": 10.0},
61
+ "recommendation_badges": ["Best for Reasoning"],
62
+ },
63
+ "gpt-5.6-terra": {
64
+ "display_name": "GPT-5.6 Terra",
65
+ "family": "GPT",
66
+ "version": "5.6",
67
+ "context_window": 256000,
68
+ "max_output_tokens": 32000,
69
+ "capabilities": ["coding", "vision", "tools", "streaming", "fast"],
70
+ "pricing": {"input_price_per_1m": 1.0, "output_price_per_1m": 4.0},
71
+ "recommendation_badges": ["Best Fast Model"],
72
+ },
73
+ "gpt-5.6-luna": {
74
+ "display_name": "GPT-5.6 Luna",
75
+ "family": "GPT",
76
+ "version": "5.6",
77
+ "context_window": 128000,
78
+ "max_output_tokens": 16000,
79
+ "capabilities": ["chat", "coding", "tools", "fast"],
80
+ "pricing": {"input_price_per_1m": 0.3, "output_price_per_1m": 1.2},
81
+ "recommendation_badges": ["Best Budget Model"],
82
+ },
83
+ "o3": {
84
+ "display_name": "o3",
85
+ "family": "o-series",
86
+ "context_window": 200000,
87
+ "max_output_tokens": 100000,
88
+ "reasoning_levels": ["low", "medium", "high"],
89
+ "capabilities": ["reasoning", "coding", "vision", "tools", "streaming"],
90
+ "pricing": {"input_price_per_1m": 10.0, "output_price_per_1m": 40.0},
91
+ "recommendation_badges": ["Best for Reasoning"],
92
+ },
93
+ "o3-mini": {
94
+ "display_name": "o3-mini",
95
+ "family": "o-series",
96
+ "context_window": 200000,
97
+ "max_output_tokens": 65536,
98
+ "reasoning_levels": ["low", "medium", "high"],
99
+ "capabilities": ["reasoning", "coding", "tools", "streaming", "fast"],
100
+ "pricing": {"input_price_per_1m": 1.1, "output_price_per_1m": 4.4},
101
+ "recommendation_badges": ["Best for Coding", "Best for Reasoning"],
102
+ },
103
+ "gpt-4o": {
104
+ "display_name": "GPT-4o",
105
+ "family": "GPT",
106
+ "version": "4o",
107
+ "context_window": 128000,
108
+ "max_output_tokens": 16384,
109
+ "capabilities": ["vision", "coding", "tools", "streaming", "audio"],
110
+ "pricing": {"input_price_per_1m": 2.5, "output_price_per_1m": 10.0},
111
+ },
112
+ "gpt-4o-mini": {
113
+ "display_name": "GPT-4o-mini",
114
+ "family": "GPT",
115
+ "version": "4o",
116
+ "context_window": 128000,
117
+ "max_output_tokens": 16384,
118
+ "capabilities": ["vision", "coding", "tools", "streaming", "fast"],
119
+ "pricing": {"input_price_per_1m": 0.15, "output_price_per_1m": 0.6},
120
+ "recommendation_badges": ["Best Fast Model"],
121
+ },
122
+ }
123
+
124
+ def discover_models(self, timeout: float = 8.0) -> List[ModelInfo]:
125
+ """Query official OpenAI /models API with catalog enrichment."""
126
+ base = self.get_api_base()
127
+ key = self.get_api_key()
128
+ headers = {"Content-Type": "application/json"}
129
+ if key:
130
+ headers["Authorization"] = f"Bearer {key}"
131
+
132
+ discovered_ids = []
133
+ try:
134
+ resp = requests.get(f"{base}/models", headers=headers, timeout=timeout)
135
+ if resp.status_code == 200:
136
+ data = resp.json().get("data", [])
137
+ for item in data:
138
+ mid = str(item.get("id", "")).strip()
139
+ # Filter out non-chat / internal embedding / TTS endpoints
140
+ if mid and not any(mid.startswith(x) for x in ("dall-e", "text-embedding", "tts", "whisper", "babbage", "davinci")):
141
+ discovered_ids.append(mid)
142
+ except Exception:
143
+ pass
144
+
145
+ # Always include our verified catalog specs even if live endpoint temporarily drops or has rate-limits
146
+ for cat_id in self.CATALOG_MODELS:
147
+ if cat_id not in discovered_ids:
148
+ discovered_ids.append(cat_id)
149
+
150
+ results = []
151
+ for mid in discovered_ids:
152
+ meta = dict(self.CATALOG_MODELS.get(mid, {}))
153
+ meta["model_id"] = mid
154
+ meta["endpoint"] = base
155
+ val = ModelValidator.validate_raw(meta, self.provider_id, self.config)
156
+ if val.is_valid and val.model_info:
157
+ results.append(val.model_info)
158
+
159
+ return results
@@ -0,0 +1,246 @@
1
+ """
2
+ calc_terminal/providers/adapters/other_adapters.py
3
+ ==================================================
4
+ Adapters for xAI (Grok), Mistral, Cohere, Meta, and Generic OpenAI-compatible endpoints.
5
+ """
6
+
7
+ import requests
8
+ from typing import List, Dict, Any
9
+
10
+ from .base import BaseProviderAdapter
11
+ from ...models.schema import ModelInfo, AVAILABILITY_PAID_API, AVAILABILITY_OPEN_WEIGHT
12
+ from ...models.validator import ModelValidator
13
+
14
+
15
+ class XAIAdapter(BaseProviderAdapter):
16
+ provider_id = "xai"
17
+ display_name = "xAI (Grok)"
18
+ company = "xAI"
19
+ region = "US"
20
+ api_base = "https://api.x.ai/v1"
21
+ authentication_type = "bearer_token"
22
+ documentation_url = "https://docs.x.ai"
23
+
24
+ catalog = {
25
+ "grok-3": {
26
+ "display_name": "Grok 3",
27
+ "family": "Grok",
28
+ "version": "3",
29
+ "context_window": 131072,
30
+ "max_output_tokens": 16384,
31
+ "capabilities": ["reasoning", "coding", "vision", "tools", "streaming"],
32
+ "pricing": {"input_price_per_1m": 3.0, "output_price_per_1m": 15.0},
33
+ "recommendation_badges": ["Best for Reasoning"],
34
+ },
35
+ "grok-3-mini": {
36
+ "display_name": "Grok 3 Mini",
37
+ "family": "Grok",
38
+ "version": "3",
39
+ "context_window": 131072,
40
+ "max_output_tokens": 16384,
41
+ "capabilities": ["coding", "tools", "streaming", "fast"],
42
+ "pricing": {"input_price_per_1m": 0.3, "output_price_per_1m": 1.5},
43
+ "recommendation_badges": ["Best Fast Model"],
44
+ },
45
+ "grok-2": {
46
+ "display_name": "Grok 2",
47
+ "family": "Grok",
48
+ "version": "2",
49
+ "context_window": 131072,
50
+ "max_output_tokens": 8192,
51
+ "capabilities": ["vision", "coding", "tools", "streaming"],
52
+ "pricing": {"input_price_per_1m": 2.0, "output_price_per_1m": 10.0},
53
+ },
54
+ }
55
+
56
+ def discover_models(self, timeout: float = 8.0) -> List[ModelInfo]:
57
+ base = self.get_api_base()
58
+ key = self.get_api_key()
59
+ headers = {"Content-Type": "application/json"}
60
+ if key:
61
+ headers["Authorization"] = f"Bearer {key}"
62
+
63
+ discovered_ids = []
64
+ try:
65
+ resp = requests.get(f"{base}/models", headers=headers, timeout=timeout)
66
+ if resp.status_code == 200:
67
+ for item in resp.json().get("data", []):
68
+ mid = str(item.get("id", "")).strip()
69
+ if mid:
70
+ discovered_ids.append(mid)
71
+ except Exception:
72
+ pass
73
+
74
+ for cat_id in self.catalog:
75
+ if cat_id not in discovered_ids:
76
+ discovered_ids.append(cat_id)
77
+
78
+ results = []
79
+ for mid in discovered_ids:
80
+ meta = dict(self.catalog.get(mid, {}))
81
+ meta["model_id"] = mid
82
+ meta["endpoint"] = base
83
+ val = ModelValidator.validate_raw(meta, self.provider_id, self.config)
84
+ if val.is_valid and val.model_info:
85
+ results.append(val.model_info)
86
+ return results
87
+
88
+
89
+ class MistralAdapter(BaseProviderAdapter):
90
+ provider_id = "mistral"
91
+ display_name = "Mistral AI"
92
+ company = "Mistral AI"
93
+ region = "EU"
94
+ api_base = "https://api.mistral.ai/v1"
95
+ authentication_type = "bearer_token"
96
+ documentation_url = "https://docs.mistral.ai/getting-started/models/models_overview/"
97
+
98
+ catalog = {
99
+ "mistral-large-latest": {
100
+ "display_name": "Mistral Large (Latest)",
101
+ "family": "Mistral",
102
+ "context_window": 128000,
103
+ "max_output_tokens": 8192,
104
+ "capabilities": ["reasoning", "coding", "tools", "streaming"],
105
+ "pricing": {"input_price_per_1m": 2.0, "output_price_per_1m": 6.0},
106
+ "recommendation_badges": ["Best for Coding"],
107
+ },
108
+ "codestral-latest": {
109
+ "display_name": "Codestral (Latest)",
110
+ "family": "Mistral",
111
+ "context_window": 256000,
112
+ "max_output_tokens": 16384,
113
+ "capabilities": ["coding", "tools", "streaming", "fast"],
114
+ "pricing": {"input_price_per_1m": 0.3, "output_price_per_1m": 0.9},
115
+ "recommendation_badges": ["Best for Coding"],
116
+ },
117
+ "mistral-small-latest": {
118
+ "display_name": "Mistral Small (Latest)",
119
+ "family": "Mistral",
120
+ "context_window": 128000,
121
+ "max_output_tokens": 8192,
122
+ "capabilities": ["chat", "fast", "tools", "streaming"],
123
+ "pricing": {"input_price_per_1m": 0.1, "output_price_per_1m": 0.3},
124
+ "recommendation_badges": ["Best Fast Model"],
125
+ },
126
+ }
127
+
128
+ def discover_models(self, timeout: float = 8.0) -> List[ModelInfo]:
129
+ base = self.get_api_base()
130
+ key = self.get_api_key()
131
+ headers = {"Content-Type": "application/json"}
132
+ if key:
133
+ headers["Authorization"] = f"Bearer {key}"
134
+
135
+ discovered_ids = []
136
+ try:
137
+ resp = requests.get(f"{base}/models", headers=headers, timeout=timeout)
138
+ if resp.status_code == 200:
139
+ for item in resp.json().get("data", []):
140
+ mid = str(item.get("id", "")).strip()
141
+ if mid:
142
+ discovered_ids.append(mid)
143
+ except Exception:
144
+ pass
145
+
146
+ for cat_id in self.catalog:
147
+ if cat_id not in discovered_ids:
148
+ discovered_ids.append(cat_id)
149
+
150
+ results = []
151
+ for mid in discovered_ids:
152
+ meta = dict(self.catalog.get(mid, {}))
153
+ meta["model_id"] = mid
154
+ meta["endpoint"] = base
155
+ val = ModelValidator.validate_raw(meta, self.provider_id, self.config)
156
+ if val.is_valid and val.model_info:
157
+ results.append(val.model_info)
158
+ return results
159
+
160
+
161
+ class CohereAdapter(BaseProviderAdapter):
162
+ provider_id = "cohere"
163
+ display_name = "Cohere"
164
+ company = "Cohere"
165
+ region = "CA"
166
+ api_base = "https://api.cohere.com/v2"
167
+ authentication_type = "bearer_token"
168
+ documentation_url = "https://docs.cohere.com/v2/docs/models"
169
+
170
+ catalog = {
171
+ "command-r-plus": {
172
+ "display_name": "Command R+",
173
+ "family": "Command",
174
+ "context_window": 128000,
175
+ "max_output_tokens": 4096,
176
+ "capabilities": ["reasoning", "coding", "tools", "streaming"],
177
+ "pricing": {"input_price_per_1m": 2.5, "output_price_per_1m": 10.0},
178
+ },
179
+ "command-r": {
180
+ "display_name": "Command R",
181
+ "family": "Command",
182
+ "context_window": 128000,
183
+ "max_output_tokens": 4096,
184
+ "capabilities": ["coding", "tools", "streaming", "fast"],
185
+ "pricing": {"input_price_per_1m": 0.5, "output_price_per_1m": 1.5},
186
+ "recommendation_badges": ["Best Fast Model"],
187
+ },
188
+ }
189
+
190
+ def discover_models(self, timeout: float = 8.0) -> List[ModelInfo]:
191
+ base = self.get_api_base()
192
+ key = self.get_api_key()
193
+ headers = {"Content-Type": "application/json"}
194
+ if key:
195
+ headers["Authorization"] = f"Bearer {key}"
196
+
197
+ discovered_ids = []
198
+ try:
199
+ resp = requests.get(f"{base}/models", headers=headers, timeout=timeout)
200
+ if resp.status_code == 200:
201
+ for item in resp.json().get("models", []):
202
+ mid = str(item.get("name", "")).strip()
203
+ if mid:
204
+ discovered_ids.append(mid)
205
+ except Exception:
206
+ pass
207
+
208
+ for cat_id in self.catalog:
209
+ if cat_id not in discovered_ids:
210
+ discovered_ids.append(cat_id)
211
+
212
+ results = []
213
+ for mid in discovered_ids:
214
+ meta = dict(self.catalog.get(mid, {}))
215
+ meta["model_id"] = mid
216
+ meta["endpoint"] = base
217
+ val = ModelValidator.validate_raw(meta, self.provider_id, self.config)
218
+ if val.is_valid and val.model_info:
219
+ results.append(val.model_info)
220
+ return results
221
+
222
+
223
+ class GenericOpenAIAdapter(BaseProviderAdapter):
224
+ """Fallback adapter for any OpenAI-compatible provider."""
225
+
226
+ def discover_models(self, timeout: float = 8.0) -> List[ModelInfo]:
227
+ base = self.get_api_base()
228
+ key = self.get_api_key()
229
+ headers = {"Content-Type": "application/json"}
230
+ if key:
231
+ headers["Authorization"] = f"Bearer {key}"
232
+
233
+ discovered = []
234
+ try:
235
+ resp = requests.get(f"{base}/models", headers=headers, timeout=timeout)
236
+ if resp.status_code == 200:
237
+ for item in resp.json().get("data", []):
238
+ mid = str(item.get("id", "")).strip()
239
+ if mid:
240
+ meta = {"model_id": mid, "endpoint": base}
241
+ val = ModelValidator.validate_raw(meta, self.provider_id, self.config)
242
+ if val.is_valid and val.model_info:
243
+ discovered.append(val.model_info)
244
+ except Exception:
245
+ pass
246
+ return discovered