cremind 0.0.1__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 (543) hide show
  1. app/__init__.py +0 -0
  2. app/__main__.py +0 -0
  3. app/__version__.py +19 -0
  4. app/agent/__init__.py +4 -0
  5. app/agent/agent.py +352 -0
  6. app/agent/context_store.py +40 -0
  7. app/agent/executor.py +477 -0
  8. app/agent/reasoning_agent.py +1473 -0
  9. app/agent/skill_classifier.py +164 -0
  10. app/agent/stream_runner.py +565 -0
  11. app/agent/summary.py +45 -0
  12. app/alembic/__init__.py +0 -0
  13. app/alembic/env.py +83 -0
  14. app/alembic/script.py.mako +26 -0
  15. app/alembic/versions/20260509_baseline.py +106 -0
  16. app/alembic/versions/__init__.py +0 -0
  17. app/api/__init__.py +77 -0
  18. app/api/_auth.py +40 -0
  19. app/api/agents.py +720 -0
  20. app/api/channels.py +532 -0
  21. app/api/config.py +1658 -0
  22. app/api/conversations.py +520 -0
  23. app/api/embedding_stream.py +99 -0
  24. app/api/events.py +542 -0
  25. app/api/features.py +261 -0
  26. app/api/file_watchers.py +368 -0
  27. app/api/files.py +659 -0
  28. app/api/llm.py +422 -0
  29. app/api/logs_stream.py +70 -0
  30. app/api/oauth2.py +140 -0
  31. app/api/oauth_loopback.py +182 -0
  32. app/api/processes.py +491 -0
  33. app/api/profile_events.py +196 -0
  34. app/api/profiles.py +270 -0
  35. app/api/settings_stream.py +90 -0
  36. app/api/setup_stream.py +81 -0
  37. app/api/skills.py +253 -0
  38. app/api/system.py +77 -0
  39. app/api/system_vars.py +50 -0
  40. app/api/tokens.py +42 -0
  41. app/api/tools.py +768 -0
  42. app/api/upgrade.py +363 -0
  43. app/api/user_config.py +157 -0
  44. app/api/version.py +137 -0
  45. app/channels/__init__.py +17 -0
  46. app/channels/adapters/__init__.py +0 -0
  47. app/channels/adapters/discord.py +19 -0
  48. app/channels/adapters/messenger.py +19 -0
  49. app/channels/adapters/slack.py +19 -0
  50. app/channels/adapters/telegram.py +246 -0
  51. app/channels/adapters/telegram_userbot.py +363 -0
  52. app/channels/adapters/whatsapp.py +330 -0
  53. app/channels/base.py +857 -0
  54. app/channels/exceptions.py +17 -0
  55. app/channels/registry.py +193 -0
  56. app/channels/sidecars/__init__.py +0 -0
  57. app/channels/sidecars/bootstrap.py +136 -0
  58. app/channels/sidecars/whatsapp/.gitignore +1 -0
  59. app/channels/sidecars/whatsapp/index.js +269 -0
  60. app/channels/sidecars/whatsapp/package.json +17 -0
  61. app/cli/__init__.py +0 -0
  62. app/cli/client/__init__.py +11 -0
  63. app/cli/client/_base.py +179 -0
  64. app/cli/client/_sse.py +70 -0
  65. app/cli/client/_ws.py +58 -0
  66. app/cli/client/agents.py +75 -0
  67. app/cli/client/channels.py +131 -0
  68. app/cli/client/config.py +43 -0
  69. app/cli/client/conversations.py +137 -0
  70. app/cli/client/file_watchers.py +34 -0
  71. app/cli/client/llm.py +127 -0
  72. app/cli/client/me.py +50 -0
  73. app/cli/client/processes.py +97 -0
  74. app/cli/client/profiles.py +55 -0
  75. app/cli/client/setup.py +81 -0
  76. app/cli/client/skill_events.py +62 -0
  77. app/cli/client/system_vars.py +30 -0
  78. app/cli/client/tools.py +102 -0
  79. app/cli/commands/__init__.py +0 -0
  80. app/cli/commands/_helpers.py +41 -0
  81. app/cli/commands/agents.py +361 -0
  82. app/cli/commands/channels.py +401 -0
  83. app/cli/commands/chat.py +69 -0
  84. app/cli/commands/config.py +195 -0
  85. app/cli/commands/conv.py +405 -0
  86. app/cli/commands/db.py +167 -0
  87. app/cli/commands/file_watchers.py +208 -0
  88. app/cli/commands/llm.py +368 -0
  89. app/cli/commands/me.py +53 -0
  90. app/cli/commands/processes.py +562 -0
  91. app/cli/commands/profile.py +258 -0
  92. app/cli/commands/serve.py +38 -0
  93. app/cli/commands/setup.py +308 -0
  94. app/cli/commands/skill_events.py +271 -0
  95. app/cli/commands/system_vars.py +43 -0
  96. app/cli/commands/tools.py +352 -0
  97. app/cli/commands/upgrade.py +125 -0
  98. app/cli/config.py +74 -0
  99. app/cli/io/__init__.py +0 -0
  100. app/cli/io/raw_tty.py +122 -0
  101. app/cli/main.py +138 -0
  102. app/cli/output/__init__.py +21 -0
  103. app/cli/output/console.py +43 -0
  104. app/cli/output/formatting.py +29 -0
  105. app/cli/output/json_output.py +29 -0
  106. app/cli/output/tables.py +66 -0
  107. app/cli/streaming.py +167 -0
  108. app/cli/tui/__init__.py +0 -0
  109. app/cli/tui/chat.py +289 -0
  110. app/cli/tui/renderer.py +210 -0
  111. app/config/__init__.py +88 -0
  112. app/config/bootstrap.py +190 -0
  113. app/config/channels/discord.toml +40 -0
  114. app/config/channels/messenger.toml +41 -0
  115. app/config/channels/slack.toml +43 -0
  116. app/config/channels/telegram.toml +44 -0
  117. app/config/channels/whatsapp.toml +29 -0
  118. app/config/config_schema.py +261 -0
  119. app/config/credentials_file.py +285 -0
  120. app/config/embedding_state.py +238 -0
  121. app/config/install_catalog.py +274 -0
  122. app/config/install_catalog.toml +193 -0
  123. app/config/provider_auth.py +55 -0
  124. app/config/providers/anthropic.toml +80 -0
  125. app/config/providers/chutes.toml +50 -0
  126. app/config/providers/cloudflare-ai-gateway.toml +30 -0
  127. app/config/providers/deepseek.toml +29 -0
  128. app/config/providers/fireworks.toml +57 -0
  129. app/config/providers/github-copilot.toml +64 -0
  130. app/config/providers/google-gemini.toml +64 -0
  131. app/config/providers/groq.toml +66 -0
  132. app/config/providers/huggingface.toml +50 -0
  133. app/config/providers/litellm.toml +22 -0
  134. app/config/providers/minimax.toml +46 -0
  135. app/config/providers/mistral.toml +57 -0
  136. app/config/providers/moonshot.toml +46 -0
  137. app/config/providers/nvidia.toml +50 -0
  138. app/config/providers/ollama.toml +53 -0
  139. app/config/providers/openai.toml +117 -0
  140. app/config/providers/openrouter.toml +57 -0
  141. app/config/providers/perplexity.toml +43 -0
  142. app/config/providers/qwen.toml +67 -0
  143. app/config/providers/together.toml +64 -0
  144. app/config/providers/vertexai.toml +75 -0
  145. app/config/providers/vllm.toml +39 -0
  146. app/config/providers/xai.toml +44 -0
  147. app/config/settings.py +514 -0
  148. app/config/settings.toml +66 -0
  149. app/config/setup_profiles.py +185 -0
  150. app/config/setup_profiles.toml +201 -0
  151. app/config/system_vars.py +120 -0
  152. app/config/user_config.py +163 -0
  153. app/constants/__init__.py +17 -0
  154. app/constants/prompts.py +9 -0
  155. app/constants/status.py +10 -0
  156. app/databases/__init__.py +51 -0
  157. app/databases/base.py +130 -0
  158. app/databases/factory.py +59 -0
  159. app/databases/postgres.py +465 -0
  160. app/databases/sqlite.py +173 -0
  161. app/documents/__init__.py +34 -0
  162. app/documents/bundled/[cli]cremind agents.md +404 -0
  163. app/documents/bundled/[cli]cremind channels.md +521 -0
  164. app/documents/bundled/[cli]cremind chat.md +193 -0
  165. app/documents/bundled/[cli]cremind config.md +334 -0
  166. app/documents/bundled/[cli]cremind conv.md +545 -0
  167. app/documents/bundled/[cli]cremind file-watchers.md +423 -0
  168. app/documents/bundled/[cli]cremind llm.md +368 -0
  169. app/documents/bundled/[cli]cremind me.md +100 -0
  170. app/documents/bundled/[cli]cremind proc.md +454 -0
  171. app/documents/bundled/[cli]cremind profile.md +342 -0
  172. app/documents/bundled/[cli]cremind setup.md +343 -0
  173. app/documents/bundled/[cli]cremind skill-events.md +387 -0
  174. app/documents/bundled/[cli]cremind system-vars.md +103 -0
  175. app/documents/bundled/[cli]cremind tools.md +405 -0
  176. app/documents/bundled/document.md +130 -0
  177. app/documents/parser.py +101 -0
  178. app/documents/sync.py +486 -0
  179. app/documents/watcher.py +111 -0
  180. app/embeddings/__init__.py +31 -0
  181. app/embeddings/base.py +19 -0
  182. app/embeddings/gemma.py +36 -0
  183. app/embeddings/me5.py +29 -0
  184. app/events/__init__.py +35 -0
  185. app/events/conversations_list_bus.py +68 -0
  186. app/events/embedding_state_bus.py +73 -0
  187. app/events/file_watcher_admin_bus.py +54 -0
  188. app/events/file_watcher_manager.py +528 -0
  189. app/events/file_watcher_runner.py +147 -0
  190. app/events/log_stream_bus.py +89 -0
  191. app/events/manager.py +290 -0
  192. app/events/notifications_buffer.py +73 -0
  193. app/events/notifications_bus.py +69 -0
  194. app/events/processes_bus.py +53 -0
  195. app/events/profile_stream_fanout.py +70 -0
  196. app/events/queue.py +202 -0
  197. app/events/runner.py +134 -0
  198. app/events/settings_state_bus.py +74 -0
  199. app/events/setup_progress_bus.py +74 -0
  200. app/events/skill_events_admin_bus.py +54 -0
  201. app/events/stream_bus.py +166 -0
  202. app/features/__init__.py +28 -0
  203. app/features/installer.py +256 -0
  204. app/features/manifest.py +221 -0
  205. app/installer/__init__.py +0 -0
  206. app/installer/__main__.py +102 -0
  207. app/installer/catalog.py +117 -0
  208. app/installer/output.py +75 -0
  209. app/installer/releases.py +122 -0
  210. app/installer/tui.py +459 -0
  211. app/lib/__init__.py +0 -0
  212. app/lib/embedding.py +25 -0
  213. app/lib/embedding_lifecycle.py +430 -0
  214. app/lib/exception.py +15 -0
  215. app/lib/llm/__init__.py +29 -0
  216. app/lib/llm/__main__.py +125 -0
  217. app/lib/llm/anthropic.py +452 -0
  218. app/lib/llm/base.py +64 -0
  219. app/lib/llm/exceptions.py +47 -0
  220. app/lib/llm/factory.py +252 -0
  221. app/lib/llm/github_copilot.py +93 -0
  222. app/lib/llm/groq.py +251 -0
  223. app/lib/llm/model_groups.py +116 -0
  224. app/lib/llm/ollama.py +250 -0
  225. app/lib/llm/openai.py +253 -0
  226. app/lib/llm/vertexai.py +282 -0
  227. app/lib/llm/vllm.py +250 -0
  228. app/lib/template.py +185 -0
  229. app/middleware/__init__.py +31 -0
  230. app/runtime.py +70 -0
  231. app/server.py +1243 -0
  232. app/services/__init__.py +30 -0
  233. app/services/manifest.py +206 -0
  234. app/services/provisioner/__init__.py +35 -0
  235. app/services/provisioner/base.py +98 -0
  236. app/services/provisioner/docker.py +370 -0
  237. app/services/provisioner/external.py +48 -0
  238. app/services/provisioner/native.py +101 -0
  239. app/setup/__init__.py +0 -0
  240. app/skills/__init__.py +25 -0
  241. app/skills/builtin/caldav-calendar/SKILL.md +163 -0
  242. app/skills/builtin/caldav-calendar/events/new_event/.gitkeep +0 -0
  243. app/skills/builtin/caldav-calendar/events/updated_event/.gitkeep +0 -0
  244. app/skills/builtin/caldav-calendar/scripts/.gitignore +4 -0
  245. app/skills/builtin/caldav-calendar/scripts/README.md +93 -0
  246. app/skills/builtin/caldav-calendar/scripts/__main__.py +20 -0
  247. app/skills/builtin/caldav-calendar/scripts/app/__init__.py +0 -0
  248. app/skills/builtin/caldav-calendar/scripts/app/caldav_client.py +151 -0
  249. app/skills/builtin/caldav-calendar/scripts/app/cli.py +166 -0
  250. app/skills/builtin/caldav-calendar/scripts/app/config.py +58 -0
  251. app/skills/builtin/caldav-calendar/scripts/app/formatter.py +83 -0
  252. app/skills/builtin/caldav-calendar/scripts/app/ical.py +269 -0
  253. app/skills/builtin/caldav-calendar/scripts/app/listener.py +402 -0
  254. app/skills/builtin/caldav-calendar/scripts/app/operations.py +318 -0
  255. app/skills/builtin/caldav-calendar/scripts/event_listener.py +20 -0
  256. app/skills/builtin/confluence/SKILL.md +95 -0
  257. app/skills/builtin/confluence/scripts/.gitignore +5 -0
  258. app/skills/builtin/confluence/scripts/__main__.py +17 -0
  259. app/skills/builtin/confluence/scripts/app/__init__.py +0 -0
  260. app/skills/builtin/confluence/scripts/app/atlassian/__init__.py +0 -0
  261. app/skills/builtin/confluence/scripts/app/atlassian/account_key.py +40 -0
  262. app/skills/builtin/confluence/scripts/app/atlassian/auth.py +300 -0
  263. app/skills/builtin/confluence/scripts/app/atlassian/discovery.py +79 -0
  264. app/skills/builtin/confluence/scripts/app/cli.py +193 -0
  265. app/skills/builtin/confluence/scripts/app/config.py +32 -0
  266. app/skills/builtin/confluence/scripts/app/confluence_api.py +155 -0
  267. app/skills/builtin/confluence/scripts/app/formatter.py +55 -0
  268. app/skills/builtin/gcalendar/SKILL.md +152 -0
  269. app/skills/builtin/gcalendar/events/event_changed/.gitkeep +0 -0
  270. app/skills/builtin/gcalendar/scripts/.gitignore +8 -0
  271. app/skills/builtin/gcalendar/scripts/__main__.py +21 -0
  272. app/skills/builtin/gcalendar/scripts/app/__init__.py +0 -0
  273. app/skills/builtin/gcalendar/scripts/app/cli.py +225 -0
  274. app/skills/builtin/gcalendar/scripts/app/config.py +38 -0
  275. app/skills/builtin/gcalendar/scripts/app/formatter.py +148 -0
  276. app/skills/builtin/gcalendar/scripts/app/gcal_api.py +115 -0
  277. app/skills/builtin/gcalendar/scripts/app/google/__init__.py +0 -0
  278. app/skills/builtin/gcalendar/scripts/app/google/account_key.py +40 -0
  279. app/skills/builtin/gcalendar/scripts/app/google/auth.py +324 -0
  280. app/skills/builtin/gcalendar/scripts/app/google/discovery.py +137 -0
  281. app/skills/builtin/gcalendar/scripts/app/google/golden_account_keys.json +13 -0
  282. app/skills/builtin/gcalendar/scripts/app/google/relay_client.py +113 -0
  283. app/skills/builtin/gcalendar/scripts/app/listener.py +310 -0
  284. app/skills/builtin/gcalendar/scripts/event_listener.py +21 -0
  285. app/skills/builtin/gcalendar/scripts/tests/test_account_key.py +40 -0
  286. app/skills/builtin/gcalendar/scripts/tests/test_link_interrupt.py +86 -0
  287. app/skills/builtin/gmail/SKILL.md +146 -0
  288. app/skills/builtin/gmail/events/new_email/.gitkeep +0 -0
  289. app/skills/builtin/gmail/scripts/.gitignore +8 -0
  290. app/skills/builtin/gmail/scripts/__main__.py +21 -0
  291. app/skills/builtin/gmail/scripts/app/__init__.py +0 -0
  292. app/skills/builtin/gmail/scripts/app/cli.py +214 -0
  293. app/skills/builtin/gmail/scripts/app/config.py +43 -0
  294. app/skills/builtin/gmail/scripts/app/formatter.py +121 -0
  295. app/skills/builtin/gmail/scripts/app/gmail_api.py +146 -0
  296. app/skills/builtin/gmail/scripts/app/google/__init__.py +0 -0
  297. app/skills/builtin/gmail/scripts/app/google/account_key.py +40 -0
  298. app/skills/builtin/gmail/scripts/app/google/auth.py +324 -0
  299. app/skills/builtin/gmail/scripts/app/google/discovery.py +137 -0
  300. app/skills/builtin/gmail/scripts/app/google/golden_account_keys.json +13 -0
  301. app/skills/builtin/gmail/scripts/app/google/relay_client.py +113 -0
  302. app/skills/builtin/gmail/scripts/app/listener.py +336 -0
  303. app/skills/builtin/gmail/scripts/event_listener.py +21 -0
  304. app/skills/builtin/gmail/scripts/tests/test_account_key.py +40 -0
  305. app/skills/builtin/gmail/scripts/tests/test_link_interrupt.py +86 -0
  306. app/skills/builtin/imap-email/SKILL.md +43 -0
  307. app/skills/builtin/imap-email/events/test.md +46 -0
  308. app/skills/builtin/imap-email/scripts/.gitignore +4 -0
  309. app/skills/builtin/imap-email/scripts/README.md +173 -0
  310. app/skills/builtin/imap-email/scripts/__main__.py +15 -0
  311. app/skills/builtin/imap-email/scripts/app/__init__.py +0 -0
  312. app/skills/builtin/imap-email/scripts/app/__main__.py +0 -0
  313. app/skills/builtin/imap-email/scripts/app/cli.py +196 -0
  314. app/skills/builtin/imap-email/scripts/app/config.py +54 -0
  315. app/skills/builtin/imap-email/scripts/app/formatter.py +93 -0
  316. app/skills/builtin/imap-email/scripts/app/imap_client.py +317 -0
  317. app/skills/builtin/imap-email/scripts/app/listener.py +211 -0
  318. app/skills/builtin/imap-email/scripts/app/message.py +187 -0
  319. app/skills/builtin/imap-email/scripts/app/operations.py +180 -0
  320. app/skills/builtin/imap-email/scripts/app/search.py +63 -0
  321. app/skills/builtin/imap-email/scripts/app/smtp_client.py +53 -0
  322. app/skills/builtin/imap-email/scripts/event_listener.py +15 -0
  323. app/skills/builtin/jira/SKILL.md +161 -0
  324. app/skills/builtin/jira/events/issue_changed/.gitkeep +0 -0
  325. app/skills/builtin/jira/scripts/.gitignore +9 -0
  326. app/skills/builtin/jira/scripts/__main__.py +17 -0
  327. app/skills/builtin/jira/scripts/app/__init__.py +0 -0
  328. app/skills/builtin/jira/scripts/app/atlassian/__init__.py +0 -0
  329. app/skills/builtin/jira/scripts/app/atlassian/account_key.py +40 -0
  330. app/skills/builtin/jira/scripts/app/atlassian/auth.py +300 -0
  331. app/skills/builtin/jira/scripts/app/atlassian/discovery.py +86 -0
  332. app/skills/builtin/jira/scripts/app/atlassian/relay_client.py +111 -0
  333. app/skills/builtin/jira/scripts/app/cli.py +240 -0
  334. app/skills/builtin/jira/scripts/app/config.py +58 -0
  335. app/skills/builtin/jira/scripts/app/formatter.py +112 -0
  336. app/skills/builtin/jira/scripts/app/jira_api.py +171 -0
  337. app/skills/builtin/jira/scripts/app/listener.py +345 -0
  338. app/skills/builtin/jira/scripts/event_listener.py +18 -0
  339. app/skills/env_file.py +58 -0
  340. app/skills/importer.py +252 -0
  341. app/skills/scanner.py +248 -0
  342. app/skills/sync.py +401 -0
  343. app/skills/tool.py +116 -0
  344. app/skills/watcher.py +105 -0
  345. app/static/ui/.built-at +1 -0
  346. app/static/ui/agent-avatar.png +0 -0
  347. app/static/ui/assets/AboutPage-Bay673ON.css +1 -0
  348. app/static/ui/assets/AboutPage-DGshkxnc.js +1 -0
  349. app/static/ui/assets/AgentsToolsSettings-Buh23J8B.css +1 -0
  350. app/static/ui/assets/AgentsToolsSettings-p5xpfP2c.js +5 -0
  351. app/static/ui/assets/ChannelPairingDialog-VjAnCvl0.css +1 -0
  352. app/static/ui/assets/ChannelPairingDialog-rxLnDlCb.js +1 -0
  353. app/static/ui/assets/ChannelsPage-BLnI--Mx.js +1 -0
  354. app/static/ui/assets/ChannelsPage-DzSDiaQI.css +1 -0
  355. app/static/ui/assets/ChannelsSettings-BrOCcfNG.css +1 -0
  356. app/static/ui/assets/ChannelsSettings-CsLEd6iP.js +1 -0
  357. app/static/ui/assets/DeploymentModeRadio-1FyYt8_E.js +1 -0
  358. app/static/ui/assets/DeploymentModeRadio-DGkSGHUG.css +1 -0
  359. app/static/ui/assets/DeveloperPage-DN9Mmz96.css +1 -0
  360. app/static/ui/assets/DeveloperPage-DajPl07Q.js +8 -0
  361. app/static/ui/assets/EmbeddingSettings-DosgfNo_.js +1 -0
  362. app/static/ui/assets/EmbeddingSettings-DsniVY84.css +1 -0
  363. app/static/ui/assets/LLMParametersForm-ZUnInzzp.css +1 -0
  364. app/static/ui/assets/LLMParametersForm.vue_vue_type_script_setup_true_lang-CsE2YrxL.js +6 -0
  365. app/static/ui/assets/LLMSettings-CaRMl8ne.js +1 -0
  366. app/static/ui/assets/LLMSettings-CxEW2H8a.css +1 -0
  367. app/static/ui/assets/LoginPage-DUOxp0NS.js +1 -0
  368. app/static/ui/assets/LoginPage-Dqz8ApJ_.css +1 -0
  369. app/static/ui/assets/ProcessList-BFfXkaXr.css +1 -0
  370. app/static/ui/assets/ProcessList-ClpH7PHX.js +14 -0
  371. app/static/ui/assets/ProcessTerminal-C7MLjalD.css +1 -0
  372. app/static/ui/assets/ProcessTerminal-S6EOvMIc.js +1 -0
  373. app/static/ui/assets/ProfileSelector-DRoyskoP.css +1 -0
  374. app/static/ui/assets/ProfileSelector-DTeMeRNk.js +1 -0
  375. app/static/ui/assets/ProfileSettings-Bm6z-Otq.js +1 -0
  376. app/static/ui/assets/ProfileSettings-Dph35mkV.css +1 -0
  377. app/static/ui/assets/ProviderConfigFields-CDHncpjj.css +1 -0
  378. app/static/ui/assets/ProviderConfigFields-zeugKg6x.js +1 -0
  379. app/static/ui/assets/SettingsPage-Cjg5Aw-5.css +1 -0
  380. app/static/ui/assets/SettingsPage-CuSRVBhY.js +1 -0
  381. app/static/ui/assets/SetupWizard-Cac9EXqk.css +1 -0
  382. app/static/ui/assets/SetupWizard-DRD5rUg_.js +12 -0
  383. app/static/ui/assets/SkillEventsPage-BISy34dp.css +1 -0
  384. app/static/ui/assets/SkillEventsPage-D3vXsDg2.js +11 -0
  385. app/static/ui/assets/UpdatesSettings-BCyobg-4.js +1 -0
  386. app/static/ui/assets/UpdatesSettings-BHLgMLzd.css +1 -0
  387. app/static/ui/assets/UserConfigSettings-CwqAU5ku.css +1 -0
  388. app/static/ui/assets/UserConfigSettings-De77aD0M.js +1 -0
  389. app/static/ui/assets/github-BfC0goYb.css +10 -0
  390. app/static/ui/assets/github-dark-BEHUn5zE.css +10 -0
  391. app/static/ui/assets/index-BBXNjI-t.css +32 -0
  392. app/static/ui/assets/index-Dz2VcS8u.js +199 -0
  393. app/static/ui/assets/useLLMModels-Ddq715w-.js +1 -0
  394. app/static/ui/assets/useServerRestart-DRMby3la.js +1 -0
  395. app/static/ui/index.html +17 -0
  396. app/static/ui/logo.ico +0 -0
  397. app/static/ui/logo.png +0 -0
  398. app/static/ui/tray-logo-64x64.png +0 -0
  399. app/static/ui-electron/.built-at +1 -0
  400. app/static/ui-electron/agent-avatar.png +0 -0
  401. app/static/ui-electron/assets/AboutPage-BYGxzwoO.js +1 -0
  402. app/static/ui-electron/assets/AboutPage-Bay673ON.css +1 -0
  403. app/static/ui-electron/assets/AgentsToolsSettings-Buh23J8B.css +1 -0
  404. app/static/ui-electron/assets/AgentsToolsSettings-khxOsBT1.js +5 -0
  405. app/static/ui-electron/assets/ChannelPairingDialog-CoVN4B3J.js +1 -0
  406. app/static/ui-electron/assets/ChannelPairingDialog-VjAnCvl0.css +1 -0
  407. app/static/ui-electron/assets/ChannelsPage-DAPF3fth.js +1 -0
  408. app/static/ui-electron/assets/ChannelsPage-DzSDiaQI.css +1 -0
  409. app/static/ui-electron/assets/ChannelsSettings-BlCM1-iv.js +1 -0
  410. app/static/ui-electron/assets/ChannelsSettings-BrOCcfNG.css +1 -0
  411. app/static/ui-electron/assets/DeploymentModeRadio-C4kqRD5H.js +1 -0
  412. app/static/ui-electron/assets/DeploymentModeRadio-DGkSGHUG.css +1 -0
  413. app/static/ui-electron/assets/DeveloperPage-CkaY7nr5.js +8 -0
  414. app/static/ui-electron/assets/DeveloperPage-DN9Mmz96.css +1 -0
  415. app/static/ui-electron/assets/EmbeddingSettings-BvjQwMTO.js +1 -0
  416. app/static/ui-electron/assets/EmbeddingSettings-DsniVY84.css +1 -0
  417. app/static/ui-electron/assets/LLMParametersForm-ZUnInzzp.css +1 -0
  418. app/static/ui-electron/assets/LLMParametersForm.vue_vue_type_script_setup_true_lang-C5rC0IrP.js +6 -0
  419. app/static/ui-electron/assets/LLMSettings-BoGhbAi7.js +1 -0
  420. app/static/ui-electron/assets/LLMSettings-CxEW2H8a.css +1 -0
  421. app/static/ui-electron/assets/LoginPage-DM4dC1XU.js +1 -0
  422. app/static/ui-electron/assets/LoginPage-Dqz8ApJ_.css +1 -0
  423. app/static/ui-electron/assets/ProcessList-BFfXkaXr.css +1 -0
  424. app/static/ui-electron/assets/ProcessList-Bnu8-YEp.js +14 -0
  425. app/static/ui-electron/assets/ProcessTerminal-C7MLjalD.css +1 -0
  426. app/static/ui-electron/assets/ProcessTerminal-DSc5DMgs.js +1 -0
  427. app/static/ui-electron/assets/ProfileSelector-BciT1BgV.js +1 -0
  428. app/static/ui-electron/assets/ProfileSelector-DRoyskoP.css +1 -0
  429. app/static/ui-electron/assets/ProfileSettings-CbPGdXWB.js +1 -0
  430. app/static/ui-electron/assets/ProfileSettings-Dph35mkV.css +1 -0
  431. app/static/ui-electron/assets/ProviderConfigFields-CDHncpjj.css +1 -0
  432. app/static/ui-electron/assets/ProviderConfigFields-COOeDNdG.js +1 -0
  433. app/static/ui-electron/assets/SettingsPage-Cjg5Aw-5.css +1 -0
  434. app/static/ui-electron/assets/SettingsPage-OiC78qq_.js +1 -0
  435. app/static/ui-electron/assets/SetupWizard-Cac9EXqk.css +1 -0
  436. app/static/ui-electron/assets/SetupWizard-hoYGAgWs.js +12 -0
  437. app/static/ui-electron/assets/SkillEventsPage-BISy34dp.css +1 -0
  438. app/static/ui-electron/assets/SkillEventsPage-BXkDOfhc.js +11 -0
  439. app/static/ui-electron/assets/UpdatesSettings-BHLgMLzd.css +1 -0
  440. app/static/ui-electron/assets/UpdatesSettings-CTZQO3Ek.js +1 -0
  441. app/static/ui-electron/assets/UserConfigSettings-CwqAU5ku.css +1 -0
  442. app/static/ui-electron/assets/UserConfigSettings-DQqBJp3I.js +1 -0
  443. app/static/ui-electron/assets/github-BfC0goYb.css +10 -0
  444. app/static/ui-electron/assets/github-dark-BEHUn5zE.css +10 -0
  445. app/static/ui-electron/assets/index-B0y39_LV.js +199 -0
  446. app/static/ui-electron/assets/index-BBXNjI-t.css +32 -0
  447. app/static/ui-electron/assets/useLLMModels-PmLutXyj.js +1 -0
  448. app/static/ui-electron/assets/useServerRestart-f9hu5znm.js +1 -0
  449. app/static/ui-electron/index.html +17 -0
  450. app/static/ui-electron/logo.ico +0 -0
  451. app/static/ui-electron/logo.png +0 -0
  452. app/static/ui-electron/tray-logo-64x64.png +0 -0
  453. app/storage/__init__.py +100 -0
  454. app/storage/_sync_base.py +77 -0
  455. app/storage/autostart_storage.py +142 -0
  456. app/storage/backup.py +93 -0
  457. app/storage/conversation_storage.py +760 -0
  458. app/storage/dynamic_config_storage.py +162 -0
  459. app/storage/event_subscription_storage.py +160 -0
  460. app/storage/file_watcher_storage.py +175 -0
  461. app/storage/migrations.py +218 -0
  462. app/storage/models.py +348 -0
  463. app/storage/tool_storage.py +437 -0
  464. app/system/__init__.py +0 -0
  465. app/system/restart.py +77 -0
  466. app/templates/PERSONA.md +1 -0
  467. app/templates/assistant.jinja +52 -0
  468. app/tools/__init__.py +54 -0
  469. app/tools/a2a/__init__.py +17 -0
  470. app/tools/a2a/auth.py +392 -0
  471. app/tools/a2a/connection.py +194 -0
  472. app/tools/a2a/tool.py +290 -0
  473. app/tools/base.py +198 -0
  474. app/tools/builtin/__init__.py +549 -0
  475. app/tools/builtin/adapter.py +658 -0
  476. app/tools/builtin/base.py +235 -0
  477. app/tools/builtin/browser.py +1240 -0
  478. app/tools/builtin/change_working_directory.py +344 -0
  479. app/tools/builtin/documentation_search.py +424 -0
  480. app/tools/builtin/exec_shell.py +2105 -0
  481. app/tools/builtin/exec_shell_autostart.py +376 -0
  482. app/tools/builtin/exec_shell_classifier.py +86 -0
  483. app/tools/builtin/exec_shell_input_mode.py +261 -0
  484. app/tools/builtin/exec_shell_process_inspect.py +227 -0
  485. app/tools/builtin/exec_shell_pty.py +485 -0
  486. app/tools/builtin/exec_shell_rtk.py +111 -0
  487. app/tools/builtin/gg_calendar.py +235 -0
  488. app/tools/builtin/gg_places.py +748 -0
  489. app/tools/builtin/markdown_converter.py +318 -0
  490. app/tools/builtin/message_detail.py +126 -0
  491. app/tools/builtin/register_file_watcher.py +617 -0
  492. app/tools/builtin/register_skill_event.py +393 -0
  493. app/tools/builtin/sleep.py +93 -0
  494. app/tools/builtin/system_file.py +1022 -0
  495. app/tools/builtin/tool.py +232 -0
  496. app/tools/builtin/weather.py +210 -0
  497. app/tools/config_manager.py +128 -0
  498. app/tools/ids.py +77 -0
  499. app/tools/intrinsic/__init__.py +27 -0
  500. app/tools/intrinsic/base.py +64 -0
  501. app/tools/intrinsic/casual_chat.py +24 -0
  502. app/tools/intrinsic/final_answer.py +29 -0
  503. app/tools/mcp/__init__.py +32 -0
  504. app/tools/mcp/mcp_agent_adapter.py +598 -0
  505. app/tools/mcp/mcp_auth.py +519 -0
  506. app/tools/mcp/mcp_connection.py +205 -0
  507. app/tools/mcp/mcp_remote_shim.py +85 -0
  508. app/tools/mcp/tool.py +395 -0
  509. app/tools/registry.py +624 -0
  510. app/types/__init__.py +32 -0
  511. app/types/__main__.py +244 -0
  512. app/upgrade/__init__.py +0 -0
  513. app/upgrade/channel.py +373 -0
  514. app/upgrade/detached.py +230 -0
  515. app/upgrade/manifest.py +450 -0
  516. app/upgrade/runner.py +765 -0
  517. app/upgrade/status.py +205 -0
  518. app/upgrade/version_filter.py +33 -0
  519. app/utils/__init__.py +13 -0
  520. app/utils/accuweather.py +314 -0
  521. app/utils/client_storage.py +211 -0
  522. app/utils/common.py +392 -0
  523. app/utils/context_storage.py +71 -0
  524. app/utils/event_parser.py +72 -0
  525. app/utils/formatting.py +52 -0
  526. app/utils/logger.py +140 -0
  527. app/utils/message_tokens.py +68 -0
  528. app/utils/persona.py +62 -0
  529. app/utils/skill_source.py +38 -0
  530. app/utils/task_context.py +13 -0
  531. app/utils/template.py +185 -0
  532. app/utils/working_directory.py +150 -0
  533. app/vectorstores/__init__.py +3 -0
  534. app/vectorstores/base.py +315 -0
  535. app/vectorstores/cache.py +200 -0
  536. app/vectorstores/chroma.py +447 -0
  537. app/vectorstores/factory.py +33 -0
  538. app/vectorstores/qdrant.py +365 -0
  539. cremind-0.0.1.dist-info/METADATA +207 -0
  540. cremind-0.0.1.dist-info/RECORD +543 -0
  541. cremind-0.0.1.dist-info/WHEEL +4 -0
  542. cremind-0.0.1.dist-info/entry_points.txt +2 -0
  543. cremind-0.0.1.dist-info/licenses/LICENSE +21 -0
app/__init__.py ADDED
File without changes
app/__main__.py ADDED
File without changes
app/__version__.py ADDED
@@ -0,0 +1,19 @@
1
+ """Single source of truth for the Cremind version.
2
+
3
+ Read by ``pyproject.toml`` (via ``tool.hatch.version``) and by the runtime
4
+ ``/version`` endpoint, the ``cremind version`` CLI, and the upgrader. Bump this
5
+ on release and the package metadata, the API response, and the CLI output
6
+ all move together.
7
+
8
+ Schema migrations are tracked separately by Alembic — see ``alembic/`` at the
9
+ repo root. ``MIN_SUPPORTED_UPGRADE_FROM`` is the oldest version this build
10
+ knows how to migrate from; the upgrader refuses to proceed when the live
11
+ install is older than this.
12
+
13
+ NOTE on ``"0.0.0"``: the upgrade floor accepts any install. Bump it the
14
+ next time Alembic introduces a migration that genuinely requires a minimum
15
+ schema version, not before.
16
+ """
17
+
18
+ __version__ = "0.0.1"
19
+ MIN_SUPPORTED_UPGRADE_FROM = "0.0.0"
app/agent/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+
2
+ from .executor import CremindAgentExecutor
3
+
4
+ __all__ = ['CremindAgentExecutor']
app/agent/agent.py ADDED
@@ -0,0 +1,352 @@
1
+ """Top-level Cremind agent.
2
+
3
+ Wraps the registry-driven :class:`ReasoningAgent` for each profile and
4
+ manages the per-profile "high" group LLM. Tool-card embeddings are kept
5
+ per-profile -- each profile gets its own Qdrant collection
6
+ ``tool_embeddings_<profile>`` and its own in-memory embedding table -- so
7
+ skill and tool visibility never leaks across profiles.
8
+
9
+ When a Qdrant vector store is available, tool embeddings are persisted so they
10
+ survive server restarts without re-calling the gRPC embedding service.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from typing import Any, AsyncGenerator, Iterable, List, Optional, TYPE_CHECKING
16
+
17
+ from app.agent.reasoning_agent import ReasoningAgent
18
+ from app.lib.embedding import LocalEmbeddings
19
+ from app.lib.llm import LLMProvider
20
+ from app.lib.llm.model_groups import ModelGroupManager
21
+ from app.storage import get_dynamic_config_storage
22
+ from app.storage.dynamic_config_storage import DynamicConfigStorage
23
+ from app.tools import ToolRegistry
24
+ from app.tools.base import ToolType
25
+ from app.types import EmbeddingTable, ReasoningStreamResponseType, ToolEmbeddingRecord
26
+ from app.utils import logger
27
+
28
+ if TYPE_CHECKING:
29
+ from app.vectorstores import VectorStore
30
+
31
+
32
+ def _tool_embeddings_collection(profile: str) -> str:
33
+ return f"tool_embeddings_{profile}"
34
+
35
+
36
+ def _card_to_embedding_text(card) -> str:
37
+ description = (card.description or "").strip()
38
+ skills = getattr(card, "skills", None) or []
39
+ skill_lines = []
40
+ for skill in skills:
41
+ sk_name = getattr(skill, "name", None) or getattr(skill, "id", None) or ""
42
+ sk_desc = (getattr(skill, "description", None) or "").strip()
43
+ if not sk_name and not sk_desc:
44
+ continue
45
+ skill_lines.append(f"{sk_name}: {sk_desc}" if sk_name else sk_desc)
46
+ if description and skill_lines:
47
+ return description + "\n\n" + "\n".join(skill_lines)
48
+ return description or "\n".join(skill_lines)
49
+
50
+
51
+ class CremindAgent:
52
+ """Per-profile reasoning entry point."""
53
+
54
+ def __init__(
55
+ self,
56
+ registry: ToolRegistry,
57
+ embedding: LocalEmbeddings | None,
58
+ runner: LLMProvider | None = None,
59
+ model_group_mgr: ModelGroupManager | None = None,
60
+ config_storage: DynamicConfigStorage | None = None,
61
+ vector_store: VectorStore | None = None,
62
+ conversation_storage: Any | None = None,
63
+ ):
64
+ self._runners: dict[str, LLMProvider] = {}
65
+ if runner is not None:
66
+ self._runners["admin"] = runner
67
+ self.registry = registry
68
+ self.embedding = embedding
69
+ self._model_group_mgr = model_group_mgr
70
+ self._config_storage = config_storage
71
+ self.vector_store = vector_store
72
+ self._conversation_storage = conversation_storage
73
+ self._embedding_tables: dict[str, EmbeddingTable] = {}
74
+
75
+ # Refresh embeddings whenever the registry mutates. The callback
76
+ # accepts an optional ``profile`` kwarg so skill-scoped changes only
77
+ # rebuild one table; global changes (builtin/a2a/mcp) rebuild all.
78
+ self.registry.set_change_callback(self.update_embeddings)
79
+
80
+ # ── embedding tables ────────────────────────────────────────────────
81
+
82
+ def _collect_tool_data(self, profile: str) -> dict[str, ToolEmbeddingRecord]:
83
+ """Extract tool card data for ``profile`` (skip stubs / hidden).
84
+
85
+ Records are keyed by ``tool_id`` (stable registry identity) and carry
86
+ filter metadata (``tool_type``, ``name``, ``enabled``) so the vector
87
+ store payload can be queried by type without joining back to the
88
+ registry. Embedding text is the card description plus one line per
89
+ sub-skill — storing the full ``AgentCard`` JSON would bloat the input
90
+ with protocol/transport fields that carry no retrieval signal.
91
+ """
92
+ agent_data: dict[str, ToolEmbeddingRecord] = {}
93
+ for tool in self.registry.tools_for_profile(profile):
94
+ if tool.hidden:
95
+ continue
96
+ if getattr(tool, "is_stub", False):
97
+ continue
98
+ card = tool.get_card()
99
+ if card is None:
100
+ continue
101
+ agent_data[tool.tool_id] = ToolEmbeddingRecord(
102
+ text=_card_to_embedding_text(card),
103
+ tool_id=tool.tool_id,
104
+ name=card.name,
105
+ tool_type=tool.tool_type.value,
106
+ enabled=self.registry.is_enabled_for_profile(tool, profile),
107
+ )
108
+ return agent_data
109
+
110
+ def _build_connected_embeddings(self, profile: str) -> Optional[EmbeddingTable]:
111
+ """Build the embedding table for ``profile``.
112
+
113
+ Uses the shared cache helper to load from Qdrant when available,
114
+ falling back to in-process embedding generation and persisting for
115
+ next time. Returns ``None`` when embedding is disabled — callers
116
+ treat that as "no similarity ranking available" and fall back to
117
+ showing every tool.
118
+ """
119
+ if self.embedding is None or self.vector_store is None:
120
+ return None
121
+
122
+ from app.vectorstores import get_or_build_embedding_table
123
+
124
+ agent_data = self._collect_tool_data(profile)
125
+ table = get_or_build_embedding_table(
126
+ vector_store=self.vector_store,
127
+ embedding=self.embedding,
128
+ data=agent_data,
129
+ collection_name=_tool_embeddings_collection(profile),
130
+ )
131
+ logger.debug(f"Tool card embeddings for '{profile}': {table.dataframe}")
132
+ return table
133
+
134
+ def embedding_table_for(self, profile: str) -> Optional[EmbeddingTable]:
135
+ """Return the profile's embedding table, building it lazily.
136
+
137
+ Returns ``None`` when embedding is disabled.
138
+ """
139
+ if self.embedding is None or self.vector_store is None:
140
+ return None
141
+ table = self._embedding_tables.get(profile)
142
+ if table is None:
143
+ built = self._build_connected_embeddings(profile)
144
+ if built is None:
145
+ return None
146
+ self._embedding_tables[profile] = built
147
+ table = built
148
+ return table
149
+
150
+ def update_embeddings(self, profile: str | None = None) -> None:
151
+ """Rebuild the embedding table(s) after tools are added/removed.
152
+
153
+ - ``profile`` given → rebuild only that profile's table (skill sync).
154
+ - ``profile is None`` → rebuild every profile we have already touched
155
+ (builtin / a2a / mcp mutation that could affect anyone).
156
+
157
+ No-op when embedding is disabled — pandas is in the embeddings
158
+ extras group and importing the cache helpers would crash on a
159
+ thin install.
160
+ """
161
+ if self.embedding is None or self.vector_store is None:
162
+ return
163
+
164
+ targets: Iterable[str]
165
+ if profile is not None:
166
+ targets = [profile]
167
+ else:
168
+ targets = list(self._embedding_tables.keys())
169
+
170
+ for p in targets:
171
+ built = self._build_connected_embeddings(p)
172
+ if built is None:
173
+ continue
174
+ self._embedding_tables[p] = built
175
+ logger.info(
176
+ f"Updated tool embeddings for '{p}' "
177
+ f"({len(self._embedding_tables[p])} entries)"
178
+ )
179
+
180
+ def drop_profile_embeddings(self, profile: str) -> None:
181
+ """Remove a profile's embedding table and its Qdrant collection."""
182
+ self._embedding_tables.pop(profile, None)
183
+ if self.vector_store is None:
184
+ return
185
+ try:
186
+ from app.vectorstores.qdrant import QdrantClient as QdrantVectorClient
187
+
188
+ client: QdrantVectorClient = self.vector_store._client # type: ignore[assignment]
189
+ collection = _tool_embeddings_collection(profile)
190
+ if client.collection_exists(collection):
191
+ client.delete_collection(collection)
192
+ logger.info(f"Dropped embedding collection '{collection}'")
193
+ except Exception: # noqa: BLE001
194
+ logger.exception(
195
+ f"Failed to drop embedding collection for profile '{profile}'"
196
+ )
197
+
198
+ # ── runners ─────────────────────────────────────────────────────────
199
+
200
+ def _ensure_runner(self, profile: str) -> LLMProvider:
201
+ """Create (or re-create) the LLM provider for ``profile`` from current config."""
202
+ if self._model_group_mgr is None:
203
+ self._model_group_mgr = ModelGroupManager(get_dynamic_config_storage())
204
+
205
+ if not self._model_group_mgr.config_storage.is_setup_complete():
206
+ raise ValueError("LLM provider is not configured. Run the setup wizard first.")
207
+
208
+ runner = self._model_group_mgr.create_llm_for_group("high", profile=profile)
209
+ self._runners[profile] = runner
210
+ return runner
211
+
212
+ def low_group_llm(self, profile: str) -> LLMProvider:
213
+ """Return the profile's 'low' group LLM provider for cheap auxiliary calls."""
214
+ if self._model_group_mgr is None:
215
+ self._model_group_mgr = ModelGroupManager(get_dynamic_config_storage())
216
+ return self._model_group_mgr.create_llm_for_group("low", profile=profile)
217
+
218
+ async def _resolve_allowed_skill_ids(
219
+ self, query: str, profile: str,
220
+ ) -> set[str] | None:
221
+ """Return the skill tool_ids permitted for this run.
222
+
223
+ - ``None`` → no filtering (manual mode, or automatic mode with any
224
+ failure that warrants falling back to the full skill list so the
225
+ user isn't silently left with zero skills).
226
+ - non-empty set → restrict skills to this set (automatic mode, vector
227
+ search succeeded).
228
+ """
229
+ storage = self._conversation_storage
230
+ if storage is None:
231
+ return None
232
+ try:
233
+ mode = await storage.get_skill_mode(profile)
234
+ except Exception: # noqa: BLE001
235
+ logger.exception(f"Failed to read skill_mode for profile '{profile}'")
236
+ return None
237
+ if mode != "automatic":
238
+ return None
239
+ if self.vector_store is None:
240
+ logger.warning(
241
+ f"Skill mode 'automatic' for profile '{profile}' but no vector "
242
+ f"store available; falling back to manual behavior."
243
+ )
244
+ return None
245
+ # Authoritative set of skills the user has enabled for this profile.
246
+ # The Qdrant payload also carries an ``enabled`` flag, but it's a
247
+ # cache; we intersect with the registry to guarantee we never return
248
+ # a skill the user has just disabled.
249
+ enabled_skill_ids = {
250
+ t.tool_id for t in self.registry.tools_for_profile(profile)
251
+ if t.tool_type is ToolType.SKILL
252
+ and self.registry.is_enabled_for_profile(t, profile)
253
+ }
254
+ if not enabled_skill_ids:
255
+ logger.debug(
256
+ f"Automatic skill mode for profile '{profile}': no enabled "
257
+ f"skills; nothing to search."
258
+ )
259
+ return set()
260
+ try:
261
+ results = self.vector_store.query(
262
+ query_text=query,
263
+ collection_name=_tool_embeddings_collection(profile),
264
+ embedding_function=self.embedding,
265
+ limit=10,
266
+ filter={"tool_type": ToolType.SKILL, "enabled": True},
267
+ )
268
+ except Exception: # noqa: BLE001
269
+ logger.exception(
270
+ f"Vector skill search failed for profile '{profile}'; "
271
+ f"falling back to manual behavior."
272
+ )
273
+ return None
274
+ allowed: set[str] = set()
275
+ for r in results or []:
276
+ metadata = r.get("metadata") or {}
277
+ tool_id = metadata.get("tool_id")
278
+ # Second line of defense: even if the Qdrant ``enabled`` payload
279
+ # is stale, only keep tool_ids the registry currently has enabled.
280
+ if tool_id and tool_id in enabled_skill_ids:
281
+ allowed.add(tool_id)
282
+ if not allowed:
283
+ logger.warning(
284
+ f"Vector skill search returned no enabled matches for profile "
285
+ f"'{profile}'; falling back to manual behavior."
286
+ )
287
+ return None
288
+ logger.debug(
289
+ f"Automatic skill mode for profile '{profile}': selected "
290
+ f"{len(allowed)} skill(s) via vector search: {sorted(allowed)}"
291
+ )
292
+ return allowed
293
+
294
+ async def run(
295
+ self,
296
+ query: str,
297
+ task_history: List[Any],
298
+ context_id: str | None,
299
+ profile: str,
300
+ reasoning: bool = True,
301
+ triggered_by_event: bool = False,
302
+ ) -> AsyncGenerator[ReasoningStreamResponseType, None]:
303
+ logger.debug(f"Running CremindAgent with query: {query} and profile: {profile}")
304
+
305
+ # Block runs while the vector embedding subsystem is still loading.
306
+ # If the user enabled embedding in the wizard, the model load is
307
+ # in flight and the agent must not respond until it's ready —
308
+ # otherwise embedding-dependent features (Automatic Skill Mode,
309
+ # Google Places filter, doc search) silently degrade.
310
+ from app.config.settings import BaseConfig
311
+ from app.config.embedding_state import embedding_state, EmbeddingStatus
312
+ from app.constants import ChatCompletionTypeEnum
313
+
314
+ if BaseConfig.is_embedding_enabled() and embedding_state.status is not EmbeddingStatus.READY:
315
+ status = embedding_state.status.value
316
+ err = embedding_state.error
317
+ if status == "initializing":
318
+ msg = (
319
+ "Vector embedding is still initializing. The agent will be "
320
+ "ready in a moment — please retry."
321
+ )
322
+ elif status == "failed":
323
+ msg = (
324
+ "Vector embedding initialization failed: "
325
+ f"{err or 'unknown error'}. Disable Vector Embedding in "
326
+ "Settings or check the server logs."
327
+ )
328
+ else:
329
+ msg = (
330
+ "Vector embedding is enabled but not ready "
331
+ f"(status: {status}). Please wait or check server logs."
332
+ )
333
+ logger.warning(f"Refusing agent run while embedding {status}: {err}")
334
+ yield {"type": ChatCompletionTypeEnum.DONE, "data": msg}
335
+ return
336
+
337
+ runner = self._ensure_runner(profile)
338
+ # Ensure this profile's embedding table is built (lazy).
339
+ self.embedding_table_for(profile)
340
+ allowed_skill_ids = await self._resolve_allowed_skill_ids(query, profile)
341
+ reasoning_agent = ReasoningAgent(
342
+ llm=runner,
343
+ registry=self.registry,
344
+ profile=profile,
345
+ context_id=context_id,
346
+ reasoning=reasoning,
347
+ allowed_skill_ids=allowed_skill_ids,
348
+ triggered_by_event=triggered_by_event,
349
+ )
350
+
351
+ async for result in reasoning_agent.run(query, task_history):
352
+ yield result
@@ -0,0 +1,40 @@
1
+ from typing import Any, Dict, List, Optional
2
+
3
+ from app.utils.logger import logger
4
+
5
+
6
+ class ReasoningContextStore:
7
+ """Centralized storage for reasoning agent contexts."""
8
+
9
+ _instance: Optional["ReasoningContextStore"] = None
10
+ _storage: Dict[str, Dict[str, Any]]
11
+
12
+ def __new__(cls) -> "ReasoningContextStore":
13
+ if cls._instance is None:
14
+ cls._instance = super().__new__(cls)
15
+ cls._instance._storage = {}
16
+ return cls._instance
17
+
18
+ def get_context(self, context_id: str) -> Optional[Dict[str, Any]]:
19
+ return self._storage.get(context_id)
20
+
21
+ def save_context(
22
+ self,
23
+ context_id: str,
24
+ steps: List[str],
25
+ step_count: int) -> None:
26
+ self._storage[context_id] = {
27
+ 'steps': steps.copy(),
28
+ 'step_count': step_count,
29
+ }
30
+ logger.info(
31
+ f"Saved context for context_id: {context_id} with {len(steps)} total steps")
32
+
33
+ def clear_context(self, context_id: str) -> None:
34
+ if context_id in self._storage:
35
+ del self._storage[context_id]
36
+ logger.info(f"Cleared context for context_id: {context_id}")
37
+
38
+ def clear_all_contexts(self) -> None:
39
+ self._storage.clear()
40
+ logger.info("Cleared all saved contexts")