clawed 2.3.7__tar.gz → 2.3.9__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 (256) hide show
  1. clawed-2.3.7/README.md → clawed-2.3.9/PKG-INFO +122 -4
  2. clawed-2.3.7/PKG-INFO → clawed-2.3.9/README.md +46 -73
  3. {clawed-2.3.7 → clawed-2.3.9}/clawed/__init__.py +1 -1
  4. {clawed-2.3.7 → clawed-2.3.9}/clawed/_legacy_gateway.py +1 -1
  5. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent.py +24 -5
  6. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/core.py +3 -1
  7. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/generate_lesson_bundle.py +52 -8
  8. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/server.py +6 -2
  9. clawed-2.3.9/clawed/async_utils.py +22 -0
  10. {clawed-2.3.7 → clawed-2.3.9}/clawed/cli.py +2 -0
  11. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/generate.py +44 -9
  12. clawed-2.3.9/clawed/commands/train.py +258 -0
  13. {clawed-2.3.7 → clawed-2.3.9}/clawed/config.py +34 -6
  14. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/__init__.py +5 -4
  15. {clawed-2.3.7 → clawed-2.3.9}/clawed/export_docx.py +3 -21
  16. {clawed-2.3.7 → clawed-2.3.9}/clawed/export_pptx.py +3 -20
  17. clawed-2.3.9/clawed/failure_codes.py +22 -0
  18. {clawed-2.3.7 → clawed-2.3.9}/clawed/generation.py +201 -30
  19. {clawed-2.3.7 → clawed-2.3.9}/clawed/handlers/generate.py +1 -1
  20. {clawed-2.3.7 → clawed-2.3.9}/clawed/handlers/onboard.py +15 -5
  21. clawed-2.3.7/clawed/openclaw_plugin.py → clawed-2.3.9/clawed/hermes_plugin.py +1 -1
  22. {clawed-2.3.7 → clawed-2.3.9}/clawed/ingestor.py +1 -1
  23. {clawed-2.3.7 → clawed-2.3.9}/clawed/lesson.py +17 -1
  24. {clawed-2.3.7 → clawed-2.3.9}/clawed/llm.py +30 -26
  25. {clawed-2.3.7 → clawed-2.3.9}/clawed/mcp_server.py +1 -1
  26. clawed-2.3.9/clawed/multi_agent.py +302 -0
  27. clawed-2.3.9/clawed/openclaw_plugin.py +24 -0
  28. clawed-2.3.9/clawed/persona.py +166 -0
  29. clawed-2.3.9/clawed/prompts/multi_agent_researcher.txt +69 -0
  30. clawed-2.3.9/clawed/prompts/multi_agent_reviewer.txt +58 -0
  31. {clawed-2.3.7 → clawed-2.3.9}/clawed/quality.py +51 -0
  32. {clawed-2.3.7 → clawed-2.3.9}/clawed/scheduler.py +1 -1
  33. clawed-2.3.7/clawed/transports/openclaw.py → clawed-2.3.9/clawed/transports/hermes.py +15 -15
  34. clawed-2.3.9/clawed/transports/openclaw.py +11 -0
  35. {clawed-2.3.7 → clawed-2.3.9}/clawed/validation.py +24 -11
  36. {clawed-2.3.7 → clawed-2.3.9}/clawed/workspace.py +1 -1
  37. {clawed-2.3.7 → clawed-2.3.9}/pyproject.toml +18 -5
  38. clawed-2.3.7/clawed/persona.py +0 -85
  39. {clawed-2.3.7 → clawed-2.3.9}/.gitignore +0 -0
  40. {clawed-2.3.7 → clawed-2.3.9}/LICENSE +0 -0
  41. {clawed-2.3.7 → clawed-2.3.9}/clawed/__main__.py +0 -0
  42. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/__init__.py +0 -0
  43. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/approvals.py +0 -0
  44. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/autonomy.py +0 -0
  45. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/context.py +0 -0
  46. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/custom_tools.py +0 -0
  47. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/drive/__init__.py +0 -0
  48. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/drive/auth.py +0 -0
  49. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/drive/client.py +0 -0
  50. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/fake_llm.py +0 -0
  51. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/loop.py +0 -0
  52. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/memory/__init__.py +0 -0
  53. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/memory/curriculum.py +0 -0
  54. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/memory/curriculum_kb.py +0 -0
  55. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/memory/embeddings.py +0 -0
  56. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/memory/episodes.py +0 -0
  57. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/memory/identity.py +0 -0
  58. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/memory/loader.py +0 -0
  59. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/memory/preferences.py +0 -0
  60. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/planner.py +0 -0
  61. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/prompt.py +0 -0
  62. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/scheduler.py +0 -0
  63. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/__init__.py +0 -0
  64. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/base.py +0 -0
  65. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/configure_profile.py +0 -0
  66. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/curriculum_map.py +0 -0
  67. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/drive_create_doc.py +0 -0
  68. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/drive_create_slides.py +0 -0
  69. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/drive_list.py +0 -0
  70. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/drive_organize.py +0 -0
  71. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/drive_read.py +0 -0
  72. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/drive_upload.py +0 -0
  73. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/export_document.py +0 -0
  74. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/gap_analysis.py +0 -0
  75. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/generate_assessment.py +0 -0
  76. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/generate_lesson.py +0 -0
  77. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/generate_materials.py +0 -0
  78. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/generate_unit.py +0 -0
  79. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/ingest_materials.py +0 -0
  80. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/parent_comm.py +0 -0
  81. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/read_heartbeat.py +0 -0
  82. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/read_workspace.py +0 -0
  83. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/request_approval.py +0 -0
  84. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/schedule_task.py +0 -0
  85. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/search_lessons.py +0 -0
  86. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/search_my_materials.py +0 -0
  87. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/search_standards.py +0 -0
  88. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/student_insights.py +0 -0
  89. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/sub_packet.py +0 -0
  90. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/switch_model.py +0 -0
  91. {clawed-2.3.7 → clawed-2.3.9}/clawed/agent_core/tools/update_soul.py +0 -0
  92. {clawed-2.3.7 → clawed-2.3.9}/clawed/analytics.py +0 -0
  93. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/__init__.py +0 -0
  94. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/deps.py +0 -0
  95. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/__init__.py +0 -0
  96. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/chat.py +0 -0
  97. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/export.py +0 -0
  98. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/feedback.py +0 -0
  99. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/gateway_chat.py +0 -0
  100. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/generate.py +0 -0
  101. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/ingest.py +0 -0
  102. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/lessons.py +0 -0
  103. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/school.py +0 -0
  104. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/settings.py +0 -0
  105. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/routes/tools.py +0 -0
  106. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/static/app.js +0 -0
  107. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/static/style.css +0 -0
  108. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/static/widget.js +0 -0
  109. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/templates/analytics.html +0 -0
  110. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/templates/base.html +0 -0
  111. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/templates/dashboard.html +0 -0
  112. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/templates/generate.html +0 -0
  113. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/templates/index.html +0 -0
  114. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/templates/lesson.html +0 -0
  115. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/templates/profile.html +0 -0
  116. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/templates/settings.html +0 -0
  117. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/templates/stats.html +0 -0
  118. {clawed-2.3.7 → clawed-2.3.9}/clawed/api/templates/students.html +0 -0
  119. {clawed-2.3.7 → clawed-2.3.9}/clawed/assessment.py +0 -0
  120. {clawed-2.3.7 → clawed-2.3.9}/clawed/asset_registry.py +0 -0
  121. {clawed-2.3.7 → clawed-2.3.9}/clawed/auth/__init__.py +0 -0
  122. {clawed-2.3.7 → clawed-2.3.9}/clawed/auth/google_auth.py +0 -0
  123. {clawed-2.3.7 → clawed-2.3.9}/clawed/bot_state.py +0 -0
  124. {clawed-2.3.7 → clawed-2.3.9}/clawed/chat.py +0 -0
  125. {clawed-2.3.7 → clawed-2.3.9}/clawed/cli_chat.py +0 -0
  126. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/__init__.py +0 -0
  127. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/_helpers.py +0 -0
  128. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/bot.py +0 -0
  129. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/config.py +0 -0
  130. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/config_llm.py +0 -0
  131. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/config_profile.py +0 -0
  132. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/export.py +0 -0
  133. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/generate_assessment.py +0 -0
  134. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/generate_unit.py +0 -0
  135. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/queue.py +0 -0
  136. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/schedule_cmd.py +0 -0
  137. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/sub.py +0 -0
  138. {clawed-2.3.7 → clawed-2.3.9}/clawed/commands/workspace_cmd.py +0 -0
  139. {clawed-2.3.7 → clawed-2.3.9}/clawed/compile_slides.py +0 -0
  140. {clawed-2.3.7 → clawed-2.3.9}/clawed/compile_student.py +0 -0
  141. {clawed-2.3.7 → clawed-2.3.9}/clawed/compile_teacher.py +0 -0
  142. {clawed-2.3.7 → clawed-2.3.9}/clawed/corpus.py +0 -0
  143. {clawed-2.3.7 → clawed-2.3.9}/clawed/curriculum_map.py +0 -0
  144. {clawed-2.3.7 → clawed-2.3.9}/clawed/database.py +0 -0
  145. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_assessment.json +0 -0
  146. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_formative_assessment.json +0 -0
  147. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_lesson_materials.json +0 -0
  148. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_lesson_science_g6.json +0 -0
  149. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_lesson_social_studies_g8.json +0 -0
  150. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_master_content.json +0 -0
  151. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_pacing_guide.json +0 -0
  152. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_quiz.json +0 -0
  153. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_rubric.json +0 -0
  154. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_unit_plan.json +0 -0
  155. {clawed-2.3.7 → clawed-2.3.9}/clawed/demo/demo_year_map.json +0 -0
  156. {clawed-2.3.7 → clawed-2.3.9}/clawed/differentiation.py +0 -0
  157. {clawed-2.3.7 → clawed-2.3.9}/clawed/doc_export.py +0 -0
  158. {clawed-2.3.7 → clawed-2.3.9}/clawed/drive.py +0 -0
  159. {clawed-2.3.7 → clawed-2.3.9}/clawed/evaluation.py +0 -0
  160. {clawed-2.3.7 → clawed-2.3.9}/clawed/export_handout.py +0 -0
  161. {clawed-2.3.7 → clawed-2.3.9}/clawed/export_markdown.py +0 -0
  162. {clawed-2.3.7 → clawed-2.3.9}/clawed/export_pdf.py +0 -0
  163. {clawed-2.3.7 → clawed-2.3.9}/clawed/export_templates.py +0 -0
  164. {clawed-2.3.7 → clawed-2.3.9}/clawed/export_theme.py +0 -0
  165. {clawed-2.3.7 → clawed-2.3.9}/clawed/exporter.py +0 -0
  166. {clawed-2.3.7 → clawed-2.3.9}/clawed/feedback.py +0 -0
  167. {clawed-2.3.7 → clawed-2.3.9}/clawed/formats/__init__.py +0 -0
  168. {clawed-2.3.7 → clawed-2.3.9}/clawed/formats/flipchart.py +0 -0
  169. {clawed-2.3.7 → clawed-2.3.9}/clawed/formats/notebook.py +0 -0
  170. {clawed-2.3.7 → clawed-2.3.9}/clawed/formats/xbk.py +0 -0
  171. {clawed-2.3.7 → clawed-2.3.9}/clawed/gateway.py +0 -0
  172. {clawed-2.3.7 → clawed-2.3.9}/clawed/gateway_response.py +0 -0
  173. {clawed-2.3.7 → clawed-2.3.9}/clawed/generation_report.py +0 -0
  174. {clawed-2.3.7 → clawed-2.3.9}/clawed/handlers/__init__.py +0 -0
  175. {clawed-2.3.7 → clawed-2.3.9}/clawed/handlers/export.py +0 -0
  176. {clawed-2.3.7 → clawed-2.3.9}/clawed/handlers/feedback.py +0 -0
  177. {clawed-2.3.7 → clawed-2.3.9}/clawed/handlers/gaps.py +0 -0
  178. {clawed-2.3.7 → clawed-2.3.9}/clawed/handlers/ingest.py +0 -0
  179. {clawed-2.3.7 → clawed-2.3.9}/clawed/handlers/misc.py +0 -0
  180. {clawed-2.3.7 → clawed-2.3.9}/clawed/handlers/schedule.py +0 -0
  181. {clawed-2.3.7 → clawed-2.3.9}/clawed/handlers/standards.py +0 -0
  182. {clawed-2.3.7 → clawed-2.3.9}/clawed/image_pipeline.py +0 -0
  183. {clawed-2.3.7 → clawed-2.3.9}/clawed/improver.py +0 -0
  184. {clawed-2.3.7 → clawed-2.3.9}/clawed/io.py +0 -0
  185. {clawed-2.3.7 → clawed-2.3.9}/clawed/master_content.py +0 -0
  186. {clawed-2.3.7 → clawed-2.3.9}/clawed/materials.py +0 -0
  187. {clawed-2.3.7 → clawed-2.3.9}/clawed/memory_engine.py +0 -0
  188. {clawed-2.3.7 → clawed-2.3.9}/clawed/model_router.py +0 -0
  189. {clawed-2.3.7 → clawed-2.3.9}/clawed/models.py +0 -0
  190. {clawed-2.3.7 → clawed-2.3.9}/clawed/onboarding.py +0 -0
  191. {clawed-2.3.7 → clawed-2.3.9}/clawed/parent_comm.py +0 -0
  192. {clawed-2.3.7 → clawed-2.3.9}/clawed/persona_evolution.py +0 -0
  193. {clawed-2.3.7 → clawed-2.3.9}/clawed/planner.py +0 -0
  194. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/504_accommodations.txt +0 -0
  195. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/admin_lesson_plan.txt +0 -0
  196. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/assessment.txt +0 -0
  197. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/curriculum_gaps.txt +0 -0
  198. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/dbq_assessment.txt +0 -0
  199. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/differentiation.txt +0 -0
  200. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/formative_assessment.txt +0 -0
  201. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/iep_modification.txt +0 -0
  202. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/lesson_plan.txt +0 -0
  203. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/master_content.txt +0 -0
  204. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/pacing_guide.txt +0 -0
  205. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/parent_note.txt +0 -0
  206. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/persona_extract.txt +0 -0
  207. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/quiz.txt +0 -0
  208. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/rubric.txt +0 -0
  209. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/student_packet.txt +0 -0
  210. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/sub_packet.txt +0 -0
  211. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/summative_assessment.txt +0 -0
  212. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/tiered_assignments.txt +0 -0
  213. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/unit_plan.txt +0 -0
  214. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/worksheet.txt +0 -0
  215. {clawed-2.3.7 → clawed-2.3.9}/clawed/prompts/year_map.txt +0 -0
  216. {clawed-2.3.7 → clawed-2.3.9}/clawed/reading_report.py +0 -0
  217. {clawed-2.3.7 → clawed-2.3.9}/clawed/router.py +0 -0
  218. {clawed-2.3.7 → clawed-2.3.9}/clawed/sanitize.py +0 -0
  219. {clawed-2.3.7 → clawed-2.3.9}/clawed/school.py +0 -0
  220. {clawed-2.3.7 → clawed-2.3.9}/clawed/search.py +0 -0
  221. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/__init__.py +0 -0
  222. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/art.py +0 -0
  223. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/base.py +0 -0
  224. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/computer_science.py +0 -0
  225. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/ela.py +0 -0
  226. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/foreign_language.py +0 -0
  227. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/history.py +0 -0
  228. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/library.py +0 -0
  229. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/math.py +0 -0
  230. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/music.py +0 -0
  231. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/physical_education.py +0 -0
  232. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/science.py +0 -0
  233. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/social_studies.py +0 -0
  234. {clawed-2.3.7 → clawed-2.3.9}/clawed/skills/special_education.py +0 -0
  235. {clawed-2.3.7 → clawed-2.3.9}/clawed/slide_images.py +0 -0
  236. {clawed-2.3.7 → clawed-2.3.9}/clawed/standards.py +0 -0
  237. {clawed-2.3.7 → clawed-2.3.9}/clawed/state.py +0 -0
  238. {clawed-2.3.7 → clawed-2.3.9}/clawed/state_standards.py +0 -0
  239. {clawed-2.3.7 → clawed-2.3.9}/clawed/student_bot.py +0 -0
  240. {clawed-2.3.7 → clawed-2.3.9}/clawed/student_cli.py +0 -0
  241. {clawed-2.3.7 → clawed-2.3.9}/clawed/student_telegram_bot.py +0 -0
  242. {clawed-2.3.7 → clawed-2.3.9}/clawed/sub_packet.py +0 -0
  243. {clawed-2.3.7 → clawed-2.3.9}/clawed/task_queue.py +0 -0
  244. {clawed-2.3.7 → clawed-2.3.9}/clawed/templates_lib.py +0 -0
  245. {clawed-2.3.7 → clawed-2.3.9}/clawed/tools.py +0 -0
  246. {clawed-2.3.7 → clawed-2.3.9}/clawed/transports/__init__.py +0 -0
  247. {clawed-2.3.7 → clawed-2.3.9}/clawed/transports/cli.py +0 -0
  248. {clawed-2.3.7 → clawed-2.3.9}/clawed/transports/student_telegram.py +0 -0
  249. {clawed-2.3.7 → clawed-2.3.9}/clawed/transports/telegram.py +0 -0
  250. {clawed-2.3.7 → clawed-2.3.9}/clawed/transports/web.py +0 -0
  251. {clawed-2.3.7 → clawed-2.3.9}/clawed/tui.py +0 -0
  252. {clawed-2.3.7 → clawed-2.3.9}/clawed/tui_chat.py +0 -0
  253. {clawed-2.3.7 → clawed-2.3.9}/clawed/voice.py +0 -0
  254. {clawed-2.3.7 → clawed-2.3.9}/clawed/voice_check.py +0 -0
  255. {clawed-2.3.7 → clawed-2.3.9}/eduagent/__init__.py +0 -0
  256. {clawed-2.3.7 → clawed-2.3.9}/eduagent/_compat.py +0 -0
@@ -1,18 +1,136 @@
1
+ Metadata-Version: 2.4
2
+ Name: clawed
3
+ Version: 2.3.9
4
+ Summary: Free AI lesson planner for teachers. Learns your teaching voice from your curriculum files and generates complete lesson packages. Open source, runs locally, no subscription.
5
+ Project-URL: Homepage, https://sirhanmacx.github.io/Claw-ED
6
+ Project-URL: Documentation, https://github.com/SirhanMacx/Claw-ED#readme
7
+ Project-URL: Repository, https://github.com/SirhanMacx/Claw-ED
8
+ Project-URL: Bug Tracker, https://github.com/SirhanMacx/Claw-ED/issues
9
+ Project-URL: Changelog, https://github.com/SirhanMacx/Claw-ED/blob/main/CHANGELOG.md
10
+ Project-URL: PyPI, https://pypi.org/project/clawed/
11
+ Author: Jon Maccarello & Claw-ED contributors
12
+ License-Expression: MIT
13
+ License-File: LICENSE
14
+ Keywords: ai,ai-for-teachers,claw-ed,clawed,curriculum,edtech,education,hermes-agent,k12,lesson-plan-generator,lesson-planner,lesson-planning,lesson-plans,open-source-education,pedagogy,teacher-tools,teachers,teaching,teaching-assistant
15
+ Classifier: Development Status :: 3 - Alpha
16
+ Classifier: Environment :: Console
17
+ Classifier: Intended Audience :: Education
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.10
22
+ Classifier: Programming Language :: Python :: 3.11
23
+ Classifier: Programming Language :: Python :: 3.12
24
+ Classifier: Topic :: Education
25
+ Classifier: Topic :: Education :: Computer Aided Instruction (CAI)
26
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
27
+ Requires-Python: >=3.10
28
+ Requires-Dist: apscheduler<4.0,>=3.10.0
29
+ Requires-Dist: fastapi<1.0,>=0.110.0
30
+ Requires-Dist: httpx<1.0,>=0.25.0
31
+ Requires-Dist: jinja2>=3.1.0
32
+ Requires-Dist: json-repair>=0.30.0
33
+ Requires-Dist: lxml>=4.9.0
34
+ Requires-Dist: mcp>=1.0.0
35
+ Requires-Dist: pydantic<3.0,>=2.0.0
36
+ Requires-Dist: pymupdf>=1.23.0
37
+ Requires-Dist: python-docx>=1.0.0
38
+ Requires-Dist: python-multipart>=0.0.6
39
+ Requires-Dist: python-pptx>=0.6.21
40
+ Requires-Dist: pyyaml<7.0,>=6.0
41
+ Requires-Dist: reportlab>=4.0.0
42
+ Requires-Dist: rich>=13.0.0
43
+ Requires-Dist: sse-starlette>=1.6.0
44
+ Requires-Dist: typer<1.0,>=0.9.0
45
+ Requires-Dist: uvicorn[standard]>=0.27.0
46
+ Provides-Extra: all
47
+ Requires-Dist: faster-whisper>=0.10.0; extra == 'all'
48
+ Requires-Dist: keyring>=24.0.0; extra == 'all'
49
+ Requires-Dist: onnxruntime>=1.16.0; extra == 'all'
50
+ Requires-Dist: qrcode[pil]>=7.0; extra == 'all'
51
+ Requires-Dist: textual>=0.56.0; extra == 'all'
52
+ Requires-Dist: uvicorn[standard]>=0.27.0; extra == 'all'
53
+ Provides-Extra: dev
54
+ Requires-Dist: apscheduler<4.0,>=3.10.0; extra == 'dev'
55
+ Requires-Dist: faster-whisper>=0.10.0; extra == 'dev'
56
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
57
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
58
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
59
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
60
+ Provides-Extra: google
61
+ Requires-Dist: google-api-python-client>=2.0.0; extra == 'google'
62
+ Requires-Dist: google-auth-oauthlib>=1.0.0; extra == 'google'
63
+ Provides-Extra: keyring
64
+ Requires-Dist: keyring>=24.0.0; extra == 'keyring'
65
+ Provides-Extra: memory
66
+ Requires-Dist: onnxruntime>=1.16.0; extra == 'memory'
67
+ Provides-Extra: pdf
68
+ Requires-Dist: weasyprint>=60.0; extra == 'pdf'
69
+ Provides-Extra: qr
70
+ Requires-Dist: qrcode[pil]>=7.0; extra == 'qr'
71
+ Provides-Extra: tui
72
+ Requires-Dist: textual>=0.56.0; extra == 'tui'
73
+ Provides-Extra: voice
74
+ Requires-Dist: faster-whisper>=0.10.0; extra == 'voice'
75
+ Description-Content-Type: text/markdown
76
+
1
77
  # Claw-ED
2
78
 
3
79
  Your personal AI teaching agent. Runs on your machine, learns your voice, works while you sleep.
4
80
 
5
- Built on the OpenClaw agent framework. Open source. MIT license.
81
+ Built on the Hermes Agent framework (NousResearch). Open source. MIT license.
6
82
 
7
83
  <p align="center">
8
- <a href="https://pypi.org/project/clawed/"><img src="https://img.shields.io/pypi/v/clawed?color=blue" alt="PyPI"></a>
9
- <a href="https://python.org"><img src="https://img.shields.io/badge/Python-3.10+-blue" alt="Python 3.10+"></a>
84
+ <a href="https://pypi.org/project/clawed/"><img src="https://img.shields.io/pypi/v/clawed?color=blue" alt="PyPI version"></a>
85
+ <a href="https://pypi.org/project/clawed/"><img src="https://img.shields.io/pypi/pyversions/clawed" alt="Python versions"></a>
10
86
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-green" alt="MIT License"></a>
11
87
  <a href="https://github.com/SirhanMacx/Claw-ED/stargazers"><img src="https://img.shields.io/github/stars/SirhanMacx/Claw-ED" alt="GitHub stars"></a>
88
+ <a href="https://pepy.tech/project/clawed"><img src="https://static.pepy.tech/badge/clawed" alt="Downloads"></a>
12
89
  </p>
13
90
 
14
91
  ---
15
92
 
93
+ ## What's new in v2.3.9
94
+
95
+ **Multi-agent lesson generation.** Instead of one LLM call doing everything, `--multi-agent` spawns a team of three specialized agents: a Researcher who finds primary sources and historical context, a Writer who drafts the lesson in your voice, and a Reviewer who scores quality on voice fidelity, pedagogy, and differentiation — sending it back for revision if any dimension scores below 7/10. The result: higher-quality lessons with better sources and stronger voice matching.
96
+
97
+ ```bash
98
+ clawed lesson "The Missouri Compromise" -g 8 --multi-agent
99
+ ```
100
+
101
+ **Claude Code integration.** Claw-ED now auto-reads OAuth tokens from Claude Code's credential store (`~/.claude/.credentials.json`). If you have Claude Code installed, Claw-ED just works — no separate API key setup needed, and tokens auto-refresh. Claw-ED also works as an MCP server that Claude Code can use directly:
102
+
103
+ ```bash
104
+ clawed mcp-server # Add to Claude Code as an MCP tool
105
+ ```
106
+
107
+ **Continuous improvement pipeline.** The new `clawed train` command lets your AI fleet (or you) continuously improve lesson quality:
108
+
109
+ ```bash
110
+ clawed train --drive # Ingest new files from Google Drive, refine persona
111
+ clawed train --path ./files # Ingest local curriculum files
112
+ clawed train --benchmark -n 5 # Generate 5 lessons and score them
113
+ clawed train --full # Drive ingest + benchmark
114
+ ```
115
+
116
+ Persona refinement is now incremental — new voice markers merge with existing ones instead of overwriting. Your teaching identity gets richer over time.
117
+
118
+ **OAuth auth fix.** All Anthropic API calls now correctly detect OAuth tokens and use Bearer authentication with Claude Code identity headers. Fixes the 401 errors that affected fleet agents and Claw-ED direct usage.
119
+
120
+ ---
121
+
122
+ ## What's new in v2.3.8
123
+
124
+ **No more silent failures.** Every step of lesson generation now reports what happened — persona loading, material search, quality review, voice matching. If something fails, you'll know exactly what and why, with structured NLAH failure codes. Quality review runs automatically on every generated lesson and fails closed: if the review itself crashes, it reports failure instead of silently passing.
125
+
126
+ **Stricter quality gates.** Lessons now require at least 6 guided notes, 3 exit ticket questions, and 2 primary sources with actual text. Topic drift is caught automatically. Voice match scoring compares generated lessons against your teaching persona.
127
+
128
+ **Safer onboarding.** Teacher names and subjects are validated and truncated. Invalid grade levels get a re-prompt instead of being silently accepted. Demo mode can be forced with `CLAWED_DEMO=1` for presentations.
129
+
130
+ **Async cleanup.** Background ingestion no longer risks crashing on Python 3.12+ from nested event loops. The fix is shared across all async call sites.
131
+
132
+ ---
133
+
16
134
  ## What's new in v2.3.7
17
135
 
18
136
  **Real images in every lesson.** Image specs are now required for every primary source and instruction section across all subjects. The LLM generates specific search queries ("Thomas Nast Boss Tweed political cartoon 1871") instead of leaving the field blank. Teacher images are found first using a three-stage progressive search (full query, individual keywords, subject fallback) with filename-weighted scoring across up to 150 candidates. External sources (Library of Congress, Wikimedia Commons, Unsplash) fill in the rest with subject-aware routing.
@@ -35,7 +153,7 @@ Built on the OpenClaw agent framework. Open source. MIT license.
35
153
 
36
154
  ## What is this?
37
155
 
38
- Claw-ED is a personal AI agent for teachers. It uses the same architecture as other OpenClaw agents -- SOUL.md for identity, layered memory, a workspace, pulse jobs, tool use, and autonomous operation. The difference is what it knows: your lesson plans, your teaching style, your standards, your students.
156
+ Claw-ED is a personal AI agent for teachers. It uses the same architecture as Hermes Agent -- SOUL.md for identity, layered memory, a workspace, cron jobs, tool use, and autonomous operation. The difference is what it knows: your lesson plans, your teaching style, your standards, your students.
39
157
 
40
158
  You feed it your curriculum files and it learns your voice. Not a generic "teacher tone" -- your actual patterns, your vocabulary, the way you structure a Do Now or frame an essential question. Then it works: drafting lessons that sound like you wrote them, organizing your Google Drive, answering student questions in your voice, prepping your week before you wake up.
41
159
 
@@ -1,87 +1,60 @@
1
- Metadata-Version: 2.4
2
- Name: clawed
3
- Version: 2.3.7
4
- Summary: Claw-ED — personal AI teaching agent. Learns your voice, works while you sleep.
5
- Project-URL: Homepage, https://github.com/SirhanMacx/Claw-ED
6
- Project-URL: Documentation, https://github.com/SirhanMacx/Claw-ED#readme
7
- Project-URL: Issues, https://github.com/SirhanMacx/Claw-ED/issues
8
- Author: Jon Maccarello & Claw-ED contributors
9
- License-Expression: MIT
10
- License-File: LICENSE
11
- Keywords: ai,claw-ed,clawed,education,lesson-plans,teachers,teaching
12
- Classifier: Development Status :: 3 - Alpha
13
- Classifier: Intended Audience :: Education
14
- Classifier: License :: OSI Approved :: MIT License
15
- Classifier: Programming Language :: Python :: 3
16
- Classifier: Programming Language :: Python :: 3.10
17
- Classifier: Programming Language :: Python :: 3.11
18
- Classifier: Programming Language :: Python :: 3.12
19
- Classifier: Topic :: Education
20
- Requires-Python: >=3.10
21
- Requires-Dist: apscheduler<4.0,>=3.10.0
22
- Requires-Dist: fastapi<1.0,>=0.110.0
23
- Requires-Dist: httpx<1.0,>=0.25.0
24
- Requires-Dist: jinja2>=3.1.0
25
- Requires-Dist: json-repair>=0.30.0
26
- Requires-Dist: lxml>=4.9.0
27
- Requires-Dist: mcp>=1.0.0
28
- Requires-Dist: pydantic<3.0,>=2.0.0
29
- Requires-Dist: pymupdf>=1.23.0
30
- Requires-Dist: python-docx>=1.0.0
31
- Requires-Dist: python-multipart>=0.0.6
32
- Requires-Dist: python-pptx>=0.6.21
33
- Requires-Dist: pyyaml<7.0,>=6.0
34
- Requires-Dist: reportlab>=4.0.0
35
- Requires-Dist: rich>=13.0.0
36
- Requires-Dist: sse-starlette>=1.6.0
37
- Requires-Dist: typer<1.0,>=0.9.0
38
- Requires-Dist: uvicorn[standard]>=0.27.0
39
- Provides-Extra: all
40
- Requires-Dist: faster-whisper>=0.10.0; extra == 'all'
41
- Requires-Dist: keyring>=24.0.0; extra == 'all'
42
- Requires-Dist: onnxruntime>=1.16.0; extra == 'all'
43
- Requires-Dist: qrcode[pil]>=7.0; extra == 'all'
44
- Requires-Dist: textual>=0.56.0; extra == 'all'
45
- Requires-Dist: uvicorn[standard]>=0.27.0; extra == 'all'
46
- Provides-Extra: dev
47
- Requires-Dist: apscheduler<4.0,>=3.10.0; extra == 'dev'
48
- Requires-Dist: faster-whisper>=0.10.0; extra == 'dev'
49
- Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
50
- Requires-Dist: pytest-cov>=4.0; extra == 'dev'
51
- Requires-Dist: pytest>=7.0.0; extra == 'dev'
52
- Requires-Dist: ruff>=0.1.0; extra == 'dev'
53
- Provides-Extra: google
54
- Requires-Dist: google-api-python-client>=2.0.0; extra == 'google'
55
- Requires-Dist: google-auth-oauthlib>=1.0.0; extra == 'google'
56
- Provides-Extra: keyring
57
- Requires-Dist: keyring>=24.0.0; extra == 'keyring'
58
- Provides-Extra: memory
59
- Requires-Dist: onnxruntime>=1.16.0; extra == 'memory'
60
- Provides-Extra: pdf
61
- Requires-Dist: weasyprint>=60.0; extra == 'pdf'
62
- Provides-Extra: qr
63
- Requires-Dist: qrcode[pil]>=7.0; extra == 'qr'
64
- Provides-Extra: tui
65
- Requires-Dist: textual>=0.56.0; extra == 'tui'
66
- Provides-Extra: voice
67
- Requires-Dist: faster-whisper>=0.10.0; extra == 'voice'
68
- Description-Content-Type: text/markdown
69
-
70
1
  # Claw-ED
71
2
 
72
3
  Your personal AI teaching agent. Runs on your machine, learns your voice, works while you sleep.
73
4
 
74
- Built on the OpenClaw agent framework. Open source. MIT license.
5
+ Built on the Hermes Agent framework (NousResearch). Open source. MIT license.
75
6
 
76
7
  <p align="center">
77
- <a href="https://pypi.org/project/clawed/"><img src="https://img.shields.io/pypi/v/clawed?color=blue" alt="PyPI"></a>
78
- <a href="https://python.org"><img src="https://img.shields.io/badge/Python-3.10+-blue" alt="Python 3.10+"></a>
8
+ <a href="https://pypi.org/project/clawed/"><img src="https://img.shields.io/pypi/v/clawed?color=blue" alt="PyPI version"></a>
9
+ <a href="https://pypi.org/project/clawed/"><img src="https://img.shields.io/pypi/pyversions/clawed" alt="Python versions"></a>
79
10
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-green" alt="MIT License"></a>
80
11
  <a href="https://github.com/SirhanMacx/Claw-ED/stargazers"><img src="https://img.shields.io/github/stars/SirhanMacx/Claw-ED" alt="GitHub stars"></a>
12
+ <a href="https://pepy.tech/project/clawed"><img src="https://static.pepy.tech/badge/clawed" alt="Downloads"></a>
81
13
  </p>
82
14
 
83
15
  ---
84
16
 
17
+ ## What's new in v2.3.9
18
+
19
+ **Multi-agent lesson generation.** Instead of one LLM call doing everything, `--multi-agent` spawns a team of three specialized agents: a Researcher who finds primary sources and historical context, a Writer who drafts the lesson in your voice, and a Reviewer who scores quality on voice fidelity, pedagogy, and differentiation — sending it back for revision if any dimension scores below 7/10. The result: higher-quality lessons with better sources and stronger voice matching.
20
+
21
+ ```bash
22
+ clawed lesson "The Missouri Compromise" -g 8 --multi-agent
23
+ ```
24
+
25
+ **Claude Code integration.** Claw-ED now auto-reads OAuth tokens from Claude Code's credential store (`~/.claude/.credentials.json`). If you have Claude Code installed, Claw-ED just works — no separate API key setup needed, and tokens auto-refresh. Claw-ED also works as an MCP server that Claude Code can use directly:
26
+
27
+ ```bash
28
+ clawed mcp-server # Add to Claude Code as an MCP tool
29
+ ```
30
+
31
+ **Continuous improvement pipeline.** The new `clawed train` command lets your AI fleet (or you) continuously improve lesson quality:
32
+
33
+ ```bash
34
+ clawed train --drive # Ingest new files from Google Drive, refine persona
35
+ clawed train --path ./files # Ingest local curriculum files
36
+ clawed train --benchmark -n 5 # Generate 5 lessons and score them
37
+ clawed train --full # Drive ingest + benchmark
38
+ ```
39
+
40
+ Persona refinement is now incremental — new voice markers merge with existing ones instead of overwriting. Your teaching identity gets richer over time.
41
+
42
+ **OAuth auth fix.** All Anthropic API calls now correctly detect OAuth tokens and use Bearer authentication with Claude Code identity headers. Fixes the 401 errors that affected fleet agents and Claw-ED direct usage.
43
+
44
+ ---
45
+
46
+ ## What's new in v2.3.8
47
+
48
+ **No more silent failures.** Every step of lesson generation now reports what happened — persona loading, material search, quality review, voice matching. If something fails, you'll know exactly what and why, with structured NLAH failure codes. Quality review runs automatically on every generated lesson and fails closed: if the review itself crashes, it reports failure instead of silently passing.
49
+
50
+ **Stricter quality gates.** Lessons now require at least 6 guided notes, 3 exit ticket questions, and 2 primary sources with actual text. Topic drift is caught automatically. Voice match scoring compares generated lessons against your teaching persona.
51
+
52
+ **Safer onboarding.** Teacher names and subjects are validated and truncated. Invalid grade levels get a re-prompt instead of being silently accepted. Demo mode can be forced with `CLAWED_DEMO=1` for presentations.
53
+
54
+ **Async cleanup.** Background ingestion no longer risks crashing on Python 3.12+ from nested event loops. The fix is shared across all async call sites.
55
+
56
+ ---
57
+
85
58
  ## What's new in v2.3.7
86
59
 
87
60
  **Real images in every lesson.** Image specs are now required for every primary source and instruction section across all subjects. The LLM generates specific search queries ("Thomas Nast Boss Tweed political cartoon 1871") instead of leaving the field blank. Teacher images are found first using a three-stage progressive search (full query, individual keywords, subject fallback) with filename-weighted scoring across up to 150 candidates. External sources (Library of Congress, Wikimedia Commons, Unsplash) fill in the rest with subject-aware routing.
@@ -104,7 +77,7 @@ Built on the OpenClaw agent framework. Open source. MIT license.
104
77
 
105
78
  ## What is this?
106
79
 
107
- Claw-ED is a personal AI agent for teachers. It uses the same architecture as other OpenClaw agents -- SOUL.md for identity, layered memory, a workspace, pulse jobs, tool use, and autonomous operation. The difference is what it knows: your lesson plans, your teaching style, your standards, your students.
80
+ Claw-ED is a personal AI agent for teachers. It uses the same architecture as Hermes Agent -- SOUL.md for identity, layered memory, a workspace, cron jobs, tool use, and autonomous operation. The difference is what it knows: your lesson plans, your teaching style, your standards, your students.
108
81
 
109
82
  You feed it your curriculum files and it learns your voice. Not a generic "teacher tone" -- your actual patterns, your vocabulary, the way you structure a Do Now or frame an essential question. Then it works: drafting lessons that sound like you wrote them, organizing your Google Drive, answering student questions in your voice, prepping your week before you wake up.
110
83
 
@@ -17,7 +17,7 @@ if hasattr(sys.stderr, "reconfigure"):
17
17
  except Exception:
18
18
  pass
19
19
 
20
- __version__ = "2.3.7"
20
+ __version__ = "2.3.9"
21
21
  __author__ = "Jon Maccarello & Claw-ED contributors"
22
22
  __description__ = "Personal AI teaching agent. Learns your voice, works while you sleep."
23
23
 
@@ -350,7 +350,7 @@ class Gateway:
350
350
 
351
351
  async def _status_response(self, teacher_id: str) -> GatewayResponse:
352
352
  try:
353
- from clawed.openclaw_plugin import _show_status
353
+ from clawed.hermes_plugin import _show_status
354
354
  from clawed.state import TeacherSession
355
355
  session = TeacherSession.load(teacher_id)
356
356
  return GatewayResponse(text=_show_status(session))
@@ -13,6 +13,29 @@ from __future__ import annotations
13
13
 
14
14
  import json
15
15
  import logging
16
+
17
+
18
+ def _anthropic_headers(api_key: str) -> dict[str, str]:
19
+ """Build Anthropic API headers, auto-detecting OAuth vs regular API keys.
20
+
21
+ OAuth tokens (sk-ant-oat01-*) need Bearer auth + Claude Code identity
22
+ headers. Regular API keys (sk-ant-api*) use x-api-key.
23
+ """
24
+ is_oauth = api_key.startswith("sk-ant-") and not api_key.startswith("sk-ant-api")
25
+ if is_oauth:
26
+ return {
27
+ "authorization": f"Bearer {api_key}",
28
+ "anthropic-version": "2023-06-01",
29
+ "anthropic-beta": "interleaved-thinking-2025-05-14,claude-code-20250219,oauth-2025-04-20",
30
+ "user-agent": "claude-cli/1.0.0 (external, cli)",
31
+ "x-app": "cli",
32
+ "content-type": "application/json",
33
+ }
34
+ return {
35
+ "x-api-key": api_key,
36
+ "anthropic-version": "2023-06-01",
37
+ "content-type": "application/json",
38
+ }
16
39
  from typing import Any
17
40
 
18
41
  from clawed.models import AppConfig, LLMProvider
@@ -137,11 +160,7 @@ async def _anthropic_with_tools(
137
160
  async with httpx.AsyncClient(timeout=120.0) as client:
138
161
  resp = await client.post(
139
162
  "https://api.anthropic.com/v1/messages",
140
- headers={
141
- "x-api-key": api_key,
142
- "anthropic-version": "2023-06-01",
143
- "content-type": "application/json",
144
- },
163
+ headers=_anthropic_headers(api_key),
145
164
  json={
146
165
  "model": config.anthropic_model,
147
166
  "max_tokens": 4096,
@@ -339,7 +339,9 @@ class Gateway:
339
339
  # 2a. Load SOUL.md if available
340
340
  soul_context = ""
341
341
  try:
342
- soul_path = Path.home() / ".eduagent" / "workspace" / "SOUL.md"
342
+ import os
343
+ data_dir = os.environ.get("EDUAGENT_DATA_DIR", str(Path.home() / ".eduagent"))
344
+ soul_path = Path(data_dir) / "workspace" / "SOUL.md"
343
345
  if soul_path.exists():
344
346
  soul_context = soul_path.read_text(encoding="utf-8")[:2000]
345
347
  except Exception:
@@ -6,6 +6,7 @@ from pathlib import Path
6
6
  from typing import Any
7
7
 
8
8
  from clawed.agent_core.context import AgentContext, ToolResult
9
+ from clawed.failure_codes import FailureCode
9
10
 
10
11
  logger = logging.getLogger(__name__)
11
12
 
@@ -89,14 +90,18 @@ class GenerateLessonBundleTool:
89
90
  f"this usually takes 2-4 minutes. I'll send everything when it's ready!"
90
91
  )
91
92
 
93
+ from clawed.generation_report import GenerationReport
94
+ report = GenerationReport()
95
+
92
96
  # ── Load config & persona from context ───────────────────────
93
97
  config = context.config
94
98
  persona = TeacherPersona()
95
99
  if context.persona:
96
100
  try:
97
101
  persona = TeacherPersona(**context.persona)
98
- except Exception:
99
- pass
102
+ except Exception as e:
103
+ logger.warning("NLAH_FAILURE=%s: %s", FailureCode.PERSONA_PARSE_ERROR, e)
104
+ report.warnings.append(f"[{FailureCode.PERSONA_PARSE_ERROR}] Could not parse persona: {e}")
100
105
 
101
106
  # ── Load state standards if teacher profile has a state ───────
102
107
  state = ""
@@ -127,7 +132,8 @@ class GenerateLessonBundleTool:
127
132
  len(assets), len(yt_links), topic,
128
133
  )
129
134
  except Exception as e:
130
- logger.debug("Asset search failed: %s", e)
135
+ logger.warning("NLAH_FAILURE=%s: %s", FailureCode.ASSET_SEARCH_FAILED, e)
136
+ report.warnings.append(f"[{FailureCode.ASSET_SEARCH_FAILED}] Asset search failed: {e}")
131
137
 
132
138
  # KB chunk-level search (text excerpts)
133
139
  try:
@@ -162,7 +168,8 @@ class GenerateLessonBundleTool:
162
168
  )
163
169
  logger.info("KB search found %d relevant chunks for '%s'", len(kb_parts), topic)
164
170
  except Exception as e:
165
- logger.debug("KB search failed: %s", e)
171
+ logger.warning("NLAH_FAILURE=%s: %s", FailureCode.KB_SEARCH_FAILED, e)
172
+ report.warnings.append(f"[{FailureCode.KB_SEARCH_FAILED}] KB search failed: {e}")
166
173
 
167
174
  # ── Build a UnitPlan with standards ──────────────────────────
168
175
  description = f"Introduction to {topic}"
@@ -205,14 +212,12 @@ class GenerateLessonBundleTool:
205
212
  teacher_materials=kb_prompt_section,
206
213
  )
207
214
  except Exception as e:
208
- return ToolResult(text=f"Failed to generate lesson: {e}")
215
+ logger.error("NLAH_FAILURE=%s: %s", FailureCode.API_FAILURE, e)
216
+ return ToolResult(text=f"[{FailureCode.API_FAILURE}] Failed to generate lesson: {type(e).__name__}")
209
217
 
210
218
  # ── Validate ──────────────────────────────────────────────────
211
- from clawed.generation_report import GenerationReport
212
219
  from clawed.validation import check_self_contained, validate_alignment, validate_master_content
213
220
 
214
- report = GenerationReport()
215
-
216
221
  mc_errors = validate_master_content(master, topic)
217
222
  for err in mc_errors:
218
223
  report.warnings.append(err)
@@ -283,6 +288,45 @@ class GenerateLessonBundleTool:
283
288
  logger.error("Slides compile failed: %s", e)
284
289
  errors.append(f"Slideshow PPTX failed: {e}")
285
290
 
291
+ # ── Quality review (NLAH Stage 4 — non-blocking) ────────────
292
+ try:
293
+ from clawed.llm import LLMClient
294
+ from clawed.quality import score_voice_match
295
+
296
+ llm = LLMClient(config=config)
297
+ master_json = master.model_dump_json(indent=2)[:3000]
298
+ review = await llm.review_lesson_package(
299
+ lesson_json=master_json,
300
+ standards_present=bool(standards_list),
301
+ has_handout=len(generated_files) >= 2,
302
+ has_slideshow=len(generated_files) >= 3,
303
+ )
304
+ report.quality_review_passed = review.get("passed", False)
305
+ report.quality_review_issues = review.get("issues", [])
306
+ if not report.quality_review_passed:
307
+ for issue in report.quality_review_issues:
308
+ report.warnings.append(f"[REVIEW] {issue}")
309
+ logger.info("Quality review: FAILED — %d issues", len(report.quality_review_issues))
310
+ else:
311
+ logger.info("Quality review: PASSED")
312
+
313
+ # Voice match scoring
314
+ persona_ctx = persona.to_prompt_context() if persona else ""
315
+ all_text = " ".join(s.content for s in master.direct_instruction)
316
+ voice_score = await score_voice_match(all_text, persona_ctx, llm)
317
+ report.voice_check_passed = voice_score >= 3.0
318
+ if voice_score < 3.0:
319
+ report.warnings.append(
320
+ f"[{FailureCode.VOICE_MISMATCH}] Voice match score: {voice_score:.1f}/5.0"
321
+ )
322
+ logger.warning("Voice match: %.1f/5.0 — below threshold", voice_score)
323
+ else:
324
+ logger.info("Voice match: %.1f/5.0", voice_score)
325
+ except Exception as e:
326
+ logger.warning("Quality review/voice check failed: %s", e)
327
+ report.quality_review_passed = False
328
+ report.quality_review_issues = [f"Review failed: {type(e).__name__}"]
329
+
286
330
  # ── Build response ─────────────────────────────────────────────
287
331
  lines = []
288
332
 
@@ -266,7 +266,9 @@ def create_app() -> FastAPI:
266
266
  filter_html = ""
267
267
  if all_subjects:
268
268
  opts = "".join(
269
- f"<option value='{html_mod.escape(s)}' {'selected' if s == subject_filter else ''}>{html_mod.escape(s)}</option>"
269
+ f"<option value='{html_mod.escape(s)}'"
270
+ f" {'selected' if s == subject_filter else ''}"
271
+ f">{html_mod.escape(s)}</option>"
270
272
  for s in all_subjects
271
273
  )
272
274
  filter_html += (
@@ -275,7 +277,9 @@ def create_app() -> FastAPI:
275
277
  )
276
278
  if all_grades:
277
279
  opts = "".join(
278
- f"<option value='{html_mod.escape(g)}' {'selected' if g == grade_filter else ''}>{html_mod.escape(g)}</option>"
280
+ f"<option value='{html_mod.escape(g)}'"
281
+ f" {'selected' if g == grade_filter else ''}"
282
+ f">{html_mod.escape(g)}</option>"
279
283
  for g in all_grades
280
284
  )
281
285
  filter_html += (
@@ -0,0 +1,22 @@
1
+ """Shared async utility for running coroutines from sync or async contexts."""
2
+ from __future__ import annotations
3
+
4
+ import asyncio
5
+
6
+
7
+ def run_async_safe(coro):
8
+ """Run an async coroutine, handling both sync and async calling contexts.
9
+
10
+ When called from inside a running event loop (e.g., agent_core tools),
11
+ uses a thread to avoid nested asyncio.run() errors. When called from
12
+ plain sync code (CLI), uses asyncio.run() directly.
13
+ """
14
+ try:
15
+ asyncio.get_running_loop()
16
+ # We're inside an event loop — run in a worker thread
17
+ import concurrent.futures
18
+ with concurrent.futures.ThreadPoolExecutor(max_workers=1) as pool:
19
+ return pool.submit(asyncio.run, coro).result(timeout=30)
20
+ except RuntimeError:
21
+ # No running loop — safe to use asyncio.run()
22
+ return asyncio.run(coro)
@@ -39,6 +39,7 @@ from clawed.commands.generate import generate_app
39
39
  from clawed.commands.queue import queue_app
40
40
  from clawed.commands.schedule_cmd import schedule_app
41
41
  from clawed.commands.sub import sub_app
42
+ from clawed.commands.train import train_app
42
43
  from clawed.commands.workspace_cmd import workspace_app
43
44
 
44
45
  # ── Build the main app ──────────────────────────────────────────────────
@@ -241,6 +242,7 @@ app.add_typer(class_app, name="class")
241
242
  app.add_typer(queue_app, name="queue")
242
243
  app.add_typer(workspace_app, name="workspace")
243
244
  app.add_typer(schedule_app, name="schedule")
245
+ app.add_typer(train_app, name="train")
244
246
 
245
247
  # ── Register top-level commands from sub-modules ────────────────────────
246
248
  # Commands from generate_app, export_app, and bot_app are registered as
@@ -298,6 +298,10 @@ def lesson(
298
298
  homework: bool = typer.Option(
299
299
  True, "--homework/--no-homework", help="Include homework"
300
300
  ),
301
+ multi_agent: bool = typer.Option(
302
+ False, "--multi-agent/--no-multi-agent",
303
+ help="Use multi-agent pipeline (researcher→writer→reviewer) for higher quality",
304
+ ),
301
305
  fmt: str = typer.Option("markdown", "--format", "-f", help="Export format: markdown, pptx, docx, pdf, handout"),
302
306
  ):
303
307
  """Generate a detailed daily lesson plan.
@@ -306,6 +310,9 @@ def lesson(
306
310
  Standalone mode (no unit plan needed):
307
311
  clawed lesson "The American Revolution" --grade 8 --subject "social studies"
308
312
 
313
+ Multi-agent mode (higher quality, 3x slower):
314
+ clawed lesson "The Missouri Compromise" -g 8 --multi-agent
315
+
309
316
  From a unit plan:
310
317
  clawed lesson "Photosynthesis" --unit-file output/unit_photosynthesis.json -n 1
311
318
  """
@@ -388,18 +395,46 @@ def lesson(
388
395
 
389
396
  with _safe_progress(console=console) as progress:
390
397
  task = progress.add_task(
391
- f"Generating lesson {lesson_num}...", total=None
398
+ f"Generating lesson {lesson_num}{' [multi-agent]' if multi_agent else ''}...",
399
+ total=None,
392
400
  )
393
401
  try:
394
- daily = _run_async(
395
- generate_lesson(
396
- lesson_number=lesson_num,
397
- unit=unit_plan,
398
- persona=persona,
399
- include_homework=homework,
400
- teacher_materials=kb_prompt_section,
402
+ if multi_agent:
403
+ # Multi-agent pipeline: researcher → writer → reviewer
404
+ from clawed.multi_agent import multi_agent_generate_master_content
405
+ from clawed.compile_teacher import compile_teacher_view
406
+ console.print("[dim]Using multi-agent pipeline (researcher→writer→reviewer)...[/dim]")
407
+ master = _run_async(
408
+ multi_agent_generate_master_content(
409
+ topic=topic,
410
+ grade=grade,
411
+ subject=subject,
412
+ persona=persona,
413
+ config=None,
414
+ unit_context=kb_prompt_section,
415
+ )
416
+ )
417
+ if master is None:
418
+ console.print("[yellow]Multi-agent returned None, falling back to single-agent...[/yellow]")
419
+ daily = _run_async(
420
+ generate_lesson(
421
+ lesson_number=lesson_num, unit=unit_plan,
422
+ persona=persona, include_homework=homework,
423
+ teacher_materials=kb_prompt_section,
424
+ )
425
+ )
426
+ else:
427
+ daily = compile_teacher_view(master)
428
+ else:
429
+ daily = _run_async(
430
+ generate_lesson(
431
+ lesson_number=lesson_num,
432
+ unit=unit_plan,
433
+ persona=persona,
434
+ include_homework=homework,
435
+ teacher_materials=kb_prompt_section,
436
+ )
401
437
  )
402
- )
403
438
  except (RuntimeError, ValueError) as e:
404
439
  console.print(f"[red]Generation failed:[/red] {e}")
405
440
  console.print("[dim]Run with --debug for full details[/dim]")