clawed 2.3.2__tar.gz → 2.3.4__tar.gz

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 (232) hide show
  1. {clawed-2.3.2 → clawed-2.3.4}/PKG-INFO +1 -1
  2. {clawed-2.3.2 → clawed-2.3.4}/clawed/__init__.py +1 -1
  3. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/prompt.py +5 -1
  4. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/generate_lesson_bundle.py +69 -11
  5. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/ingest_materials.py +57 -0
  6. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/update_soul.py +11 -2
  7. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/generate.py +28 -0
  8. {clawed-2.3.2 → clawed-2.3.4}/clawed/handlers/ingest.py +48 -0
  9. {clawed-2.3.2 → clawed-2.3.4}/clawed/llm.py +26 -0
  10. {clawed-2.3.2 → clawed-2.3.4}/clawed/memory_engine.py +29 -0
  11. {clawed-2.3.2 → clawed-2.3.4}/clawed/models.py +36 -0
  12. clawed-2.3.4/clawed/persona_evolution.py +271 -0
  13. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/admin_lesson_plan.txt +5 -1
  14. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/lesson_plan.txt +5 -1
  15. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/persona_extract.txt +11 -1
  16. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/student_packet.txt +10 -0
  17. {clawed-2.3.2 → clawed-2.3.4}/clawed/reading_report.py +186 -2
  18. {clawed-2.3.2 → clawed-2.3.4}/clawed/slide_images.py +53 -15
  19. {clawed-2.3.2 → clawed-2.3.4}/clawed/sub_packet.py +7 -0
  20. clawed-2.3.4/clawed/voice_check.py +192 -0
  21. {clawed-2.3.2 → clawed-2.3.4}/clawed/workspace.py +110 -0
  22. {clawed-2.3.2 → clawed-2.3.4}/pyproject.toml +1 -1
  23. {clawed-2.3.2 → clawed-2.3.4}/.gitignore +0 -0
  24. {clawed-2.3.2 → clawed-2.3.4}/LICENSE +0 -0
  25. {clawed-2.3.2 → clawed-2.3.4}/README.md +0 -0
  26. {clawed-2.3.2 → clawed-2.3.4}/clawed/__main__.py +0 -0
  27. {clawed-2.3.2 → clawed-2.3.4}/clawed/_legacy_gateway.py +0 -0
  28. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent.py +0 -0
  29. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/__init__.py +0 -0
  30. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/approvals.py +0 -0
  31. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/autonomy.py +0 -0
  32. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/context.py +0 -0
  33. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/core.py +0 -0
  34. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/custom_tools.py +0 -0
  35. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/drive/__init__.py +0 -0
  36. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/drive/auth.py +0 -0
  37. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/drive/client.py +0 -0
  38. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/fake_llm.py +0 -0
  39. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/loop.py +0 -0
  40. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/memory/__init__.py +0 -0
  41. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/memory/curriculum.py +0 -0
  42. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/memory/curriculum_kb.py +0 -0
  43. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/memory/embeddings.py +0 -0
  44. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/memory/episodes.py +0 -0
  45. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/memory/identity.py +0 -0
  46. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/memory/loader.py +0 -0
  47. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/memory/preferences.py +0 -0
  48. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/planner.py +0 -0
  49. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/scheduler.py +0 -0
  50. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/__init__.py +0 -0
  51. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/base.py +0 -0
  52. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/configure_profile.py +0 -0
  53. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/curriculum_map.py +0 -0
  54. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/drive_create_doc.py +0 -0
  55. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/drive_create_slides.py +0 -0
  56. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/drive_list.py +0 -0
  57. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/drive_organize.py +0 -0
  58. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/drive_read.py +0 -0
  59. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/drive_upload.py +0 -0
  60. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/export_document.py +0 -0
  61. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/gap_analysis.py +0 -0
  62. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/generate_assessment.py +0 -0
  63. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/generate_lesson.py +0 -0
  64. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/generate_materials.py +0 -0
  65. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/generate_unit.py +0 -0
  66. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/parent_comm.py +0 -0
  67. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/read_heartbeat.py +0 -0
  68. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/read_workspace.py +0 -0
  69. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/request_approval.py +0 -0
  70. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/schedule_task.py +0 -0
  71. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/search_lessons.py +0 -0
  72. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/search_my_materials.py +0 -0
  73. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/search_standards.py +0 -0
  74. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/student_insights.py +0 -0
  75. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/sub_packet.py +0 -0
  76. {clawed-2.3.2 → clawed-2.3.4}/clawed/agent_core/tools/switch_model.py +0 -0
  77. {clawed-2.3.2 → clawed-2.3.4}/clawed/analytics.py +0 -0
  78. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/__init__.py +0 -0
  79. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/deps.py +0 -0
  80. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/__init__.py +0 -0
  81. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/chat.py +0 -0
  82. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/export.py +0 -0
  83. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/feedback.py +0 -0
  84. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/gateway_chat.py +0 -0
  85. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/generate.py +0 -0
  86. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/ingest.py +0 -0
  87. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/lessons.py +0 -0
  88. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/school.py +0 -0
  89. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/settings.py +0 -0
  90. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/routes/tools.py +0 -0
  91. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/server.py +0 -0
  92. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/static/app.js +0 -0
  93. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/static/style.css +0 -0
  94. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/static/widget.js +0 -0
  95. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/templates/analytics.html +0 -0
  96. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/templates/base.html +0 -0
  97. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/templates/dashboard.html +0 -0
  98. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/templates/generate.html +0 -0
  99. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/templates/index.html +0 -0
  100. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/templates/lesson.html +0 -0
  101. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/templates/profile.html +0 -0
  102. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/templates/settings.html +0 -0
  103. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/templates/stats.html +0 -0
  104. {clawed-2.3.2 → clawed-2.3.4}/clawed/api/templates/students.html +0 -0
  105. {clawed-2.3.2 → clawed-2.3.4}/clawed/assessment.py +0 -0
  106. {clawed-2.3.2 → clawed-2.3.4}/clawed/asset_registry.py +0 -0
  107. {clawed-2.3.2 → clawed-2.3.4}/clawed/auth/__init__.py +0 -0
  108. {clawed-2.3.2 → clawed-2.3.4}/clawed/auth/google_auth.py +0 -0
  109. {clawed-2.3.2 → clawed-2.3.4}/clawed/bot_state.py +0 -0
  110. {clawed-2.3.2 → clawed-2.3.4}/clawed/chat.py +0 -0
  111. {clawed-2.3.2 → clawed-2.3.4}/clawed/cli.py +0 -0
  112. {clawed-2.3.2 → clawed-2.3.4}/clawed/cli_chat.py +0 -0
  113. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/__init__.py +0 -0
  114. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/_helpers.py +0 -0
  115. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/bot.py +0 -0
  116. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/config.py +0 -0
  117. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/config_llm.py +0 -0
  118. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/config_profile.py +0 -0
  119. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/export.py +0 -0
  120. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/generate_assessment.py +0 -0
  121. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/generate_unit.py +0 -0
  122. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/queue.py +0 -0
  123. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/schedule_cmd.py +0 -0
  124. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/sub.py +0 -0
  125. {clawed-2.3.2 → clawed-2.3.4}/clawed/commands/workspace_cmd.py +0 -0
  126. {clawed-2.3.2 → clawed-2.3.4}/clawed/config.py +0 -0
  127. {clawed-2.3.2 → clawed-2.3.4}/clawed/corpus.py +0 -0
  128. {clawed-2.3.2 → clawed-2.3.4}/clawed/curriculum_map.py +0 -0
  129. {clawed-2.3.2 → clawed-2.3.4}/clawed/database.py +0 -0
  130. {clawed-2.3.2 → clawed-2.3.4}/clawed/demo/__init__.py +0 -0
  131. {clawed-2.3.2 → clawed-2.3.4}/clawed/demo/demo_assessment.json +0 -0
  132. {clawed-2.3.2 → clawed-2.3.4}/clawed/demo/demo_lesson_science_g6.json +0 -0
  133. {clawed-2.3.2 → clawed-2.3.4}/clawed/demo/demo_lesson_social_studies_g8.json +0 -0
  134. {clawed-2.3.2 → clawed-2.3.4}/clawed/demo/demo_unit_plan.json +0 -0
  135. {clawed-2.3.2 → clawed-2.3.4}/clawed/differentiation.py +0 -0
  136. {clawed-2.3.2 → clawed-2.3.4}/clawed/doc_export.py +0 -0
  137. {clawed-2.3.2 → clawed-2.3.4}/clawed/drive.py +0 -0
  138. {clawed-2.3.2 → clawed-2.3.4}/clawed/evaluation.py +0 -0
  139. {clawed-2.3.2 → clawed-2.3.4}/clawed/export_docx.py +0 -0
  140. {clawed-2.3.2 → clawed-2.3.4}/clawed/export_handout.py +0 -0
  141. {clawed-2.3.2 → clawed-2.3.4}/clawed/export_markdown.py +0 -0
  142. {clawed-2.3.2 → clawed-2.3.4}/clawed/export_pdf.py +0 -0
  143. {clawed-2.3.2 → clawed-2.3.4}/clawed/export_pptx.py +0 -0
  144. {clawed-2.3.2 → clawed-2.3.4}/clawed/export_templates.py +0 -0
  145. {clawed-2.3.2 → clawed-2.3.4}/clawed/export_theme.py +0 -0
  146. {clawed-2.3.2 → clawed-2.3.4}/clawed/exporter.py +0 -0
  147. {clawed-2.3.2 → clawed-2.3.4}/clawed/feedback.py +0 -0
  148. {clawed-2.3.2 → clawed-2.3.4}/clawed/formats/__init__.py +0 -0
  149. {clawed-2.3.2 → clawed-2.3.4}/clawed/formats/flipchart.py +0 -0
  150. {clawed-2.3.2 → clawed-2.3.4}/clawed/formats/notebook.py +0 -0
  151. {clawed-2.3.2 → clawed-2.3.4}/clawed/formats/xbk.py +0 -0
  152. {clawed-2.3.2 → clawed-2.3.4}/clawed/gateway.py +0 -0
  153. {clawed-2.3.2 → clawed-2.3.4}/clawed/gateway_response.py +0 -0
  154. {clawed-2.3.2 → clawed-2.3.4}/clawed/generation.py +0 -0
  155. {clawed-2.3.2 → clawed-2.3.4}/clawed/handlers/__init__.py +0 -0
  156. {clawed-2.3.2 → clawed-2.3.4}/clawed/handlers/export.py +0 -0
  157. {clawed-2.3.2 → clawed-2.3.4}/clawed/handlers/feedback.py +0 -0
  158. {clawed-2.3.2 → clawed-2.3.4}/clawed/handlers/gaps.py +0 -0
  159. {clawed-2.3.2 → clawed-2.3.4}/clawed/handlers/generate.py +0 -0
  160. {clawed-2.3.2 → clawed-2.3.4}/clawed/handlers/misc.py +0 -0
  161. {clawed-2.3.2 → clawed-2.3.4}/clawed/handlers/onboard.py +0 -0
  162. {clawed-2.3.2 → clawed-2.3.4}/clawed/handlers/schedule.py +0 -0
  163. {clawed-2.3.2 → clawed-2.3.4}/clawed/handlers/standards.py +0 -0
  164. {clawed-2.3.2 → clawed-2.3.4}/clawed/improver.py +0 -0
  165. {clawed-2.3.2 → clawed-2.3.4}/clawed/ingestor.py +0 -0
  166. {clawed-2.3.2 → clawed-2.3.4}/clawed/io.py +0 -0
  167. {clawed-2.3.2 → clawed-2.3.4}/clawed/lesson.py +0 -0
  168. {clawed-2.3.2 → clawed-2.3.4}/clawed/materials.py +0 -0
  169. {clawed-2.3.2 → clawed-2.3.4}/clawed/mcp_server.py +0 -0
  170. {clawed-2.3.2 → clawed-2.3.4}/clawed/model_router.py +0 -0
  171. {clawed-2.3.2 → clawed-2.3.4}/clawed/onboarding.py +0 -0
  172. {clawed-2.3.2 → clawed-2.3.4}/clawed/openclaw_plugin.py +0 -0
  173. {clawed-2.3.2 → clawed-2.3.4}/clawed/parent_comm.py +0 -0
  174. {clawed-2.3.2 → clawed-2.3.4}/clawed/persona.py +0 -0
  175. {clawed-2.3.2 → clawed-2.3.4}/clawed/planner.py +0 -0
  176. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/504_accommodations.txt +0 -0
  177. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/assessment.txt +0 -0
  178. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/curriculum_gaps.txt +0 -0
  179. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/dbq_assessment.txt +0 -0
  180. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/differentiation.txt +0 -0
  181. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/formative_assessment.txt +0 -0
  182. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/iep_modification.txt +0 -0
  183. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/pacing_guide.txt +0 -0
  184. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/parent_note.txt +0 -0
  185. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/quiz.txt +0 -0
  186. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/rubric.txt +0 -0
  187. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/sub_packet.txt +0 -0
  188. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/summative_assessment.txt +0 -0
  189. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/tiered_assignments.txt +0 -0
  190. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/unit_plan.txt +0 -0
  191. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/worksheet.txt +0 -0
  192. {clawed-2.3.2 → clawed-2.3.4}/clawed/prompts/year_map.txt +0 -0
  193. {clawed-2.3.2 → clawed-2.3.4}/clawed/quality.py +0 -0
  194. {clawed-2.3.2 → clawed-2.3.4}/clawed/router.py +0 -0
  195. {clawed-2.3.2 → clawed-2.3.4}/clawed/sanitize.py +0 -0
  196. {clawed-2.3.2 → clawed-2.3.4}/clawed/scheduler.py +0 -0
  197. {clawed-2.3.2 → clawed-2.3.4}/clawed/school.py +0 -0
  198. {clawed-2.3.2 → clawed-2.3.4}/clawed/search.py +0 -0
  199. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/__init__.py +0 -0
  200. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/art.py +0 -0
  201. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/base.py +0 -0
  202. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/computer_science.py +0 -0
  203. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/ela.py +0 -0
  204. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/foreign_language.py +0 -0
  205. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/history.py +0 -0
  206. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/library.py +0 -0
  207. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/math.py +0 -0
  208. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/music.py +0 -0
  209. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/physical_education.py +0 -0
  210. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/science.py +0 -0
  211. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/social_studies.py +0 -0
  212. {clawed-2.3.2 → clawed-2.3.4}/clawed/skills/special_education.py +0 -0
  213. {clawed-2.3.2 → clawed-2.3.4}/clawed/standards.py +0 -0
  214. {clawed-2.3.2 → clawed-2.3.4}/clawed/state.py +0 -0
  215. {clawed-2.3.2 → clawed-2.3.4}/clawed/state_standards.py +0 -0
  216. {clawed-2.3.2 → clawed-2.3.4}/clawed/student_bot.py +0 -0
  217. {clawed-2.3.2 → clawed-2.3.4}/clawed/student_cli.py +0 -0
  218. {clawed-2.3.2 → clawed-2.3.4}/clawed/student_telegram_bot.py +0 -0
  219. {clawed-2.3.2 → clawed-2.3.4}/clawed/task_queue.py +0 -0
  220. {clawed-2.3.2 → clawed-2.3.4}/clawed/templates_lib.py +0 -0
  221. {clawed-2.3.2 → clawed-2.3.4}/clawed/tools.py +0 -0
  222. {clawed-2.3.2 → clawed-2.3.4}/clawed/transports/__init__.py +0 -0
  223. {clawed-2.3.2 → clawed-2.3.4}/clawed/transports/cli.py +0 -0
  224. {clawed-2.3.2 → clawed-2.3.4}/clawed/transports/openclaw.py +0 -0
  225. {clawed-2.3.2 → clawed-2.3.4}/clawed/transports/student_telegram.py +0 -0
  226. {clawed-2.3.2 → clawed-2.3.4}/clawed/transports/telegram.py +0 -0
  227. {clawed-2.3.2 → clawed-2.3.4}/clawed/transports/web.py +0 -0
  228. {clawed-2.3.2 → clawed-2.3.4}/clawed/tui.py +0 -0
  229. {clawed-2.3.2 → clawed-2.3.4}/clawed/tui_chat.py +0 -0
  230. {clawed-2.3.2 → clawed-2.3.4}/clawed/voice.py +0 -0
  231. {clawed-2.3.2 → clawed-2.3.4}/eduagent/__init__.py +0 -0
  232. {clawed-2.3.2 → clawed-2.3.4}/eduagent/_compat.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clawed
3
- Version: 2.3.2
3
+ Version: 2.3.4
4
4
  Summary: Claw-ED — personal AI teaching agent. Learns your voice, works while you sleep.
5
5
  Project-URL: Homepage, https://github.com/SirhanMacx/Claw-ED
6
6
  Project-URL: Documentation, https://github.com/SirhanMacx/Claw-ED#readme
@@ -17,7 +17,7 @@ if hasattr(sys.stderr, "reconfigure"):
17
17
  except Exception:
18
18
  pass
19
19
 
20
- __version__ = "2.3.2"
20
+ __version__ = "2.3.4"
21
21
  __author__ = "Jon Maccarello & Claw-ED contributors"
22
22
  __description__ = "Personal AI teaching agent. Learns your voice, works while you sleep."
23
23
 
@@ -91,7 +91,11 @@ def build_system_prompt(
91
91
  " 'Building your lesson package now — plan, handout, and slides coming up.'\n"
92
92
  "The teacher should always know you're working, not stuck.\n"
93
93
  "1. Read SOUL.md to know your voice and values\n"
94
- "2. Search the teacher's curriculum files for relevant prior work\n"
94
+ "2. **MANDATORY: Before calling generate_lesson_bundle, ALWAYS call "
95
+ "search_my_materials first** with the lesson topic. This is non-negotiable. "
96
+ "The teacher has uploaded materials — if you skip this step, you will "
97
+ "generate generic content instead of building on their prior work. "
98
+ "Tell the teacher what you found before generating.\n"
95
99
  "3. Generate complete packages (lesson plan + student handout + slideshow) "
96
100
  "using generate_lesson_bundle\n"
97
101
  "4. Never ask 'want me to create materials?' -- just create them\n"
@@ -22,7 +22,10 @@ class GenerateLessonBundleTool:
22
22
  "description": (
23
23
  "Generate a COMPLETE teaching package for a topic: "
24
24
  "a lesson plan (DOCX), a student handout (DOCX), and "
25
- "a slideshow (PPTX). All three files are created at once."
25
+ "a slideshow (PPTX). All three files are created at once. "
26
+ "IMPORTANT: Always call search_my_materials FIRST to find "
27
+ "the teacher's existing materials on this topic before "
28
+ "calling this tool."
26
29
  ),
27
30
  "parameters": {
28
31
  "type": "object",
@@ -232,6 +235,23 @@ class GenerateLessonBundleTool:
232
235
  except Exception:
233
236
  pass # Review is best-effort, don't block on failure
234
237
 
238
+ # ── Voice validation ──────────────────────────────────────────
239
+ voice_notes: list[str] = []
240
+ try:
241
+ from clawed.voice_check import check_voice_match
242
+
243
+ voice_result = check_voice_match(
244
+ persona=persona,
245
+ do_now=lesson.do_now,
246
+ direct_instruction_opening=lesson.direct_instruction[:500] if lesson.direct_instruction else "",
247
+ )
248
+ if not voice_result.passed:
249
+ for issue in voice_result.issues:
250
+ voice_notes.append(issue)
251
+ logger.info("Voice check issue: %s", issue)
252
+ except Exception as e:
253
+ logger.debug("Voice check failed: %s", e)
254
+
235
255
  # ── Generate student packet + admin plan in parallel ──────────
236
256
  import asyncio
237
257
 
@@ -323,19 +343,57 @@ class GenerateLessonBundleTool:
323
343
  logger.error("PPTX export failed: %s", e)
324
344
  errors.append(f"Slideshow PPTX failed: {e}")
325
345
 
326
- # ── Build response ───────────────────────────────────────────
327
- lines = [f"Generated teaching package for: {lesson.title}\n"]
328
- if generated_files:
329
- lines.append("Files created:")
330
- for f in generated_files:
331
- lines.append(f" - {f}")
332
- if kb_context:
333
- lines.append("\nReferenced your existing materials on this topic.")
334
- if errors:
335
- lines.append("\nErrors:")
346
+ # ── Build honest response ─────────────────────────────────────
347
+ used_fallback_packet = not student_packet and any("Student packet" in s for s in side_effects)
348
+
349
+ lines = []
350
+
351
+ if len(generated_files) == 3 and not errors:
352
+ lines.append(f"Complete teaching package for: {lesson.title}")
353
+ lines.append("All three files ready to print:")
354
+ for se in side_effects:
355
+ lines.append(f" - {se}")
356
+ elif generated_files:
357
+ lines.append(f"Generated {len(generated_files)} of 3 files for: {lesson.title}")
358
+ for se in side_effects:
359
+ lines.append(f" - {se}")
360
+ if errors:
361
+ lines.append("")
362
+ for err in errors:
363
+ clean_err = str(err).split("\n")[0][:200]
364
+ lines.append(f" Could not generate: {clean_err}")
365
+ lines.append("Want me to try the failed item(s) again?")
366
+ else:
367
+ lines.append(f"Failed to generate teaching package for: {lesson.title}")
336
368
  for err in errors:
337
369
  lines.append(f" - {err}")
338
370
 
371
+ if used_fallback_packet:
372
+ lines.append("")
373
+ lines.append(
374
+ "Note: The student packet was generated using a simpler method — "
375
+ "it may not have full graphic organizers. Let me know if you'd like me to regenerate it."
376
+ )
377
+
378
+ if kb_context:
379
+ lines.append("\nReferenced your existing materials on this topic.")
380
+
381
+ # Self-review findings
382
+ try:
383
+ if review and not review.get("passed", True) and review.get("issues"):
384
+ lines.append("")
385
+ lines.append("Quality notes:")
386
+ for issue in review["issues"][:3]:
387
+ lines.append(f" - {issue}")
388
+ except NameError:
389
+ pass
390
+
391
+ if voice_notes:
392
+ lines.append("\nVoice match notes:")
393
+ for note in voice_notes:
394
+ lines.append(f" - {note}")
395
+ lines.append("Want me to adjust the lesson to better match your voice?")
396
+
339
397
  return ToolResult(
340
398
  text="\n".join(lines),
341
399
  files=generated_files,
@@ -65,7 +65,31 @@ class IngestMaterialsTool:
65
65
  from clawed.persona import extract_persona, save_persona
66
66
 
67
67
  persona = await extract_persona(docs, context.config)
68
+ # Override LLM-inferred name with configured teacher name
69
+ try:
70
+ if context.config and context.config.teacher_profile and context.config.teacher_profile.name:
71
+ persona.name = f"{context.config.teacher_profile.name} Teaching Persona"
72
+ except Exception:
73
+ pass
74
+ try:
75
+ _id_path = Path.home() / ".eduagent" / "workspace" / "identity.md"
76
+ if _id_path.exists():
77
+ import re as _re
78
+ _id_content = _id_path.read_text(encoding="utf-8")
79
+ _name_match = _re.match(r"^#\s+(.+)", _id_content)
80
+ if _name_match:
81
+ _tname = _name_match.group(1).strip()
82
+ if _tname and _tname != "Teacher":
83
+ persona.name = f"{_tname} Teaching Persona"
84
+ except Exception:
85
+ pass
68
86
  save_persona(persona, Path.home() / ".eduagent")
87
+ # Track persona changes for evolution
88
+ try:
89
+ from clawed.persona_evolution import record_ingestion_changes
90
+ record_ingestion_changes(old_persona=None, new_persona=persona)
91
+ except Exception:
92
+ pass
69
93
  except Exception:
70
94
  pass
71
95
 
@@ -129,6 +153,39 @@ class IngestMaterialsTool:
129
153
  except Exception as e:
130
154
  logger.debug("KB indexing failed: %s", e)
131
155
 
156
+ # Register assets for file-level search
157
+ try:
158
+ from clawed.asset_registry import AssetRegistry
159
+ registry = AssetRegistry()
160
+ asset_count = 0
161
+ for doc in docs:
162
+ doc_type_val = (
163
+ doc.doc_type.value
164
+ if hasattr(doc.doc_type, "value")
165
+ else str(doc.doc_type)
166
+ )
167
+ extraction = None
168
+ if doc.source_path:
169
+ try:
170
+ from clawed.ingestor import extract_rich
171
+ extraction = extract_rich(Path(doc.source_path))
172
+ except Exception:
173
+ pass
174
+ aid = registry.register_asset(
175
+ teacher_id=context.teacher_id,
176
+ source_path=doc.source_path or "",
177
+ title=doc.title,
178
+ doc_type=doc_type_val,
179
+ text=doc.content,
180
+ extraction=extraction,
181
+ )
182
+ if aid:
183
+ asset_count += 1
184
+ if asset_count:
185
+ summary += f" ({asset_count} files catalogued for search)"
186
+ except Exception as e:
187
+ logger.debug("Asset registration failed: %s", e)
188
+
132
189
  # Update SOUL.md with what we learned
133
190
  try:
134
191
  soul_path = Path.home() / ".eduagent" / "workspace" / "SOUL.md"
@@ -3,7 +3,6 @@ from __future__ import annotations
3
3
 
4
4
  import logging
5
5
  from datetime import date
6
- from pathlib import Path
7
6
  from typing import Any
8
7
 
9
8
  from clawed.agent_core.context import AgentContext, ToolResult
@@ -92,7 +91,9 @@ class UpdateSoulTool:
92
91
  text=f"Unknown section '{section_key}'. Valid sections: {valid}"
93
92
  )
94
93
 
95
- soul_path = Path.home() / ".eduagent" / "workspace" / "SOUL.md"
94
+ from clawed.workspace import SOUL_PATH
95
+
96
+ soul_path = SOUL_PATH
96
97
  soul_path.parent.mkdir(parents=True, exist_ok=True)
97
98
 
98
99
  # Read or create SOUL.md
@@ -104,6 +105,14 @@ class UpdateSoulTool:
104
105
  # Build the datestamped entry
105
106
  entry = f"\n\n*({date.today().isoformat()})* {content}\n"
106
107
 
108
+ # Check for duplicate before writing
109
+ from clawed.workspace import _deduplicate_entry
110
+
111
+ if _deduplicate_entry(current, content, header):
112
+ return ToolResult(
113
+ text=f"Observation already exists in SOUL.md section '{section_key}' — skipping duplicate.",
114
+ )
115
+
107
116
  # Insert after the section header
108
117
  if header in current:
109
118
  current = current.replace(header, header + entry, 1)
@@ -130,8 +130,36 @@ def ingest(
130
130
  persona = _run_async(extract_persona(documents))
131
131
  progress.update(task, description="Persona extracted!")
132
132
 
133
+ # Override LLM-inferred name with configured teacher name
134
+ try:
135
+ cfg = AppConfig.load()
136
+ if cfg.teacher_profile and cfg.teacher_profile.name:
137
+ persona.name = f"{cfg.teacher_profile.name} Teaching Persona"
138
+ except Exception:
139
+ pass
140
+ # Also check identity.md
141
+ try:
142
+ identity_path = Path.home() / ".eduagent" / "workspace" / "identity.md"
143
+ if identity_path.exists():
144
+ import re
145
+ content = identity_path.read_text(encoding="utf-8")
146
+ name_match = re.match(r"^#\s+(.+)", content)
147
+ if name_match:
148
+ teacher_name = name_match.group(1).strip()
149
+ if teacher_name and teacher_name != "Teacher":
150
+ persona.name = f"{teacher_name} Teaching Persona"
151
+ except Exception:
152
+ pass
153
+
133
154
  out = save_persona(persona, _output_dir())
134
155
 
156
+ # Track persona changes for evolution
157
+ try:
158
+ from clawed.persona_evolution import record_ingestion_changes
159
+ record_ingestion_changes(old_persona=None, new_persona=persona)
160
+ except Exception:
161
+ pass
162
+
135
163
  # Index documents into curriculum knowledge base for KB search
136
164
  kb_msg = ""
137
165
  try:
@@ -60,6 +60,25 @@ class IngestHandler:
60
60
  try:
61
61
  from clawed.models import AppConfig
62
62
  persona = await extract_persona(documents, AppConfig.load())
63
+ # Override LLM-inferred name with configured teacher name
64
+ try:
65
+ config = AppConfig.load()
66
+ if config.teacher_profile and config.teacher_profile.name:
67
+ persona.name = f"{config.teacher_profile.name} Teaching Persona"
68
+ except Exception:
69
+ pass
70
+ try:
71
+ _id_path = Path.home() / ".eduagent" / "workspace" / "identity.md"
72
+ if _id_path.exists():
73
+ import re as _re
74
+ _id_content = _id_path.read_text(encoding="utf-8")
75
+ _name_match = _re.match(r"^#\s+(.+)", _id_content)
76
+ if _name_match:
77
+ _tname = _name_match.group(1).strip()
78
+ if _tname and _tname != "Teacher":
79
+ persona.name = f"{_tname} Teaching Persona"
80
+ except Exception:
81
+ pass
63
82
  from clawed.persona import save_persona
64
83
  save_persona(persona, Path.home() / ".eduagent")
65
84
  style_info = f"\nLearned teaching style: {persona.teaching_style}"
@@ -97,6 +116,35 @@ class IngestHandler:
97
116
  except Exception as e:
98
117
  logger.debug("KB indexing skipped: %s", e)
99
118
 
119
+ # Register assets (files, images, YouTube links) for search
120
+ try:
121
+ from clawed.asset_registry import AssetRegistry
122
+ registry = AssetRegistry()
123
+ asset_count = 0
124
+ for doc in documents:
125
+ doc_type_val = doc.doc_type.value if hasattr(doc.doc_type, "value") else str(doc.doc_type)
126
+ extraction = None
127
+ if doc.source_path:
128
+ try:
129
+ from clawed.ingestor import extract_rich
130
+ extraction = extract_rich(Path(doc.source_path))
131
+ except Exception:
132
+ pass
133
+ aid = registry.register_asset(
134
+ teacher_id=teacher_id,
135
+ source_path=doc.source_path or "",
136
+ title=doc.title,
137
+ doc_type=doc_type_val,
138
+ text=doc.content,
139
+ extraction=extraction,
140
+ )
141
+ if aid:
142
+ asset_count += 1
143
+ if asset_count:
144
+ kb_info += f" ({asset_count} files catalogued with images and links)"
145
+ except Exception as e:
146
+ logger.debug("Asset registration skipped: %s", e)
147
+
100
148
  return GatewayResponse(
101
149
  text=f"Ingested {len(documents)} document(s).{style_info}{kb_info}"
102
150
  )
@@ -293,10 +293,36 @@ class LLMClient:
293
293
 
294
294
  prompt_path = Path(__file__).parent / "prompts" / "student_packet.txt"
295
295
  prompt_template = prompt_path.read_text(encoding="utf-8")
296
+
297
+ # Build handout style block from persona context
298
+ import re as _re
299
+ handout_style = ""
300
+ if persona_context:
301
+ hs_match = _re.search(
302
+ r"=== Handout Style ===\n(.+?)(?:\n===|\Z)",
303
+ persona_context, _re.DOTALL,
304
+ )
305
+ if hs_match:
306
+ handout_style = hs_match.group(1).strip()
307
+
308
+ if handout_style:
309
+ handout_style_block = (
310
+ f"This teacher's handout style: {handout_style}. "
311
+ "Match this format. If the teacher uses guided notes, include them. "
312
+ "If they use graphic organizers, lead with those. If they prefer "
313
+ "dense source packets, make the sources the centerpiece. "
314
+ "Don't impose a format the teacher wouldn't recognize as their own."
315
+ )
316
+ else:
317
+ handout_style_block = (
318
+ "No specific handout style detected — use the default format below."
319
+ )
320
+
296
321
  prompt = (
297
322
  prompt_template
298
323
  .replace("{lesson_json}", lesson_json[:6000])
299
324
  .replace("{persona}", persona_context)
325
+ .replace("{handout_style_block}", handout_style_block)
300
326
  )
301
327
 
302
328
  system = (
@@ -397,6 +397,35 @@ def process_feedback(
397
397
  except Exception as e:
398
398
  logger.debug("Drift detection failed: %s", e)
399
399
 
400
+ # Check if persona evolution should trigger
401
+ try:
402
+ from clawed.persona_evolution import apply_confirmed_changes, get_confirmed_changes
403
+ confirmed = get_confirmed_changes()
404
+ if confirmed:
405
+ from clawed.commands._helpers import persona_path
406
+ from clawed.persona import load_persona
407
+ pp = persona_path()
408
+ if pp.exists():
409
+ current_persona = load_persona(pp)
410
+ updated, descriptions = apply_confirmed_changes(current_persona)
411
+ if descriptions:
412
+ pp.write_text(updated.model_dump_json(indent=2), encoding="utf-8")
413
+ # Log to SOUL.md
414
+ from clawed.workspace import SOUL_PATH
415
+ if SOUL_PATH.exists():
416
+ soul_content = SOUL_PATH.read_text(encoding="utf-8")
417
+ stamp = datetime.now(timezone.utc).strftime("%Y-%m-%d")
418
+ for desc in descriptions:
419
+ entry = f"\n\n*({stamp})* Fingerprint updated: {desc}\n"
420
+ marker = "## Agent Observations"
421
+ soul_content = soul_content.replace(
422
+ marker, marker + entry, 1
423
+ )
424
+ SOUL_PATH.write_text(soul_content, encoding="utf-8")
425
+ logger.info("Persona evolution applied: %s", "; ".join(descriptions))
426
+ except Exception as e:
427
+ logger.debug("Persona evolution check failed: %s", e)
428
+
400
429
  return applied
401
430
 
402
431
 
@@ -201,6 +201,11 @@ class TeacherPersona(BaseModel):
201
201
  'Always ends DI with "here is where it gets interesting"',
202
202
  'Uses physical movement — students walk to corners for opinion spectrums'."""
203
203
 
204
+ handout_style: str = ""
205
+ """Description of the teacher's handout/worksheet style, e.g.
206
+ 'Dense text packets with primary source excerpts and marginal annotations'
207
+ or 'Graphic organizer-heavy with minimal text, always includes an image hook'."""
208
+
204
209
  def to_prompt_context(self) -> str:
205
210
  """Serialize persona into a string for LLM prompt injection."""
206
211
  lines = [
@@ -250,6 +255,10 @@ class TeacherPersona(BaseModel):
250
255
  for move in self.signature_moves:
251
256
  lines.append(f"- {move}")
252
257
 
258
+ if self.handout_style:
259
+ lines.append(f"\n=== Handout Style ===\n{self.handout_style}")
260
+ lines.append("Student packets must match this format.")
261
+
253
262
  if self.voice_examples:
254
263
  lines.append("")
255
264
  lines.append("=== Voice Examples (write like this) ===")
@@ -479,6 +488,15 @@ class WorksheetItem(BaseModel):
479
488
  answer_key: str = ""
480
489
  point_value: int = 1
481
490
 
491
+ @field_validator("point_value", mode="before")
492
+ @classmethod
493
+ def _coerce_point_value(cls, v):
494
+ if isinstance(v, str):
495
+ import re
496
+ match = re.match(r"(\d+)", v.strip())
497
+ return int(match.group(1)) if match else 1
498
+ return v
499
+
482
500
 
483
501
  class AssessmentQuestion(BaseModel):
484
502
  """A single assessment question."""
@@ -490,6 +508,15 @@ class AssessmentQuestion(BaseModel):
490
508
  correct_answer: str = ""
491
509
  point_value: int = 1
492
510
 
511
+ @field_validator("point_value", mode="before")
512
+ @classmethod
513
+ def _coerce_point_value(cls, v):
514
+ if isinstance(v, str):
515
+ import re
516
+ match = re.match(r"(\d+)", v.strip())
517
+ return int(match.group(1)) if match else 1
518
+ return v
519
+
493
520
 
494
521
  class RubricCriterion(BaseModel):
495
522
  """A single rubric criterion with levels."""
@@ -665,6 +692,15 @@ class SummativeQuestion(BaseModel):
665
692
  point_value: int = 1
666
693
  standard_aligned: str = ""
667
694
 
695
+ @field_validator("point_value", mode="before")
696
+ @classmethod
697
+ def _coerce_point_value(cls, v):
698
+ if isinstance(v, str):
699
+ import re
700
+ match = re.match(r"(\d+)", v.strip())
701
+ return int(match.group(1)) if match else 1
702
+ return v
703
+
668
704
 
669
705
  class SummativeAssessment(BaseModel):
670
706
  """Unit test — mix of MC, short answer, DBQ/essay aligned to all unit objectives."""