devflow-engine 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (393) hide show
  1. devflow_engine/__init__.py +3 -0
  2. devflow_engine/agentic_prompts.py +100 -0
  3. devflow_engine/agentic_runtime.py +398 -0
  4. devflow_engine/api_key_flow_harness.py +539 -0
  5. devflow_engine/api_keys.py +357 -0
  6. devflow_engine/bootstrap/__init__.py +2 -0
  7. devflow_engine/bootstrap/provision_from_template.py +84 -0
  8. devflow_engine/cli/__init__.py +0 -0
  9. devflow_engine/cli/app.py +7270 -0
  10. devflow_engine/core/__init__.py +0 -0
  11. devflow_engine/core/config.py +86 -0
  12. devflow_engine/core/logging.py +29 -0
  13. devflow_engine/core/paths.py +45 -0
  14. devflow_engine/core/toml_kv.py +33 -0
  15. devflow_engine/devflow_event_worker.py +1292 -0
  16. devflow_engine/devflow_state.py +201 -0
  17. devflow_engine/devin2/__init__.py +9 -0
  18. devflow_engine/devin2/agent_definition.py +120 -0
  19. devflow_engine/devin2/pi_runner.py +204 -0
  20. devflow_engine/devin_orchestration.py +69 -0
  21. devflow_engine/docs/prompts/anti-patterns.md +42 -0
  22. devflow_engine/docs/prompts/devin-agent-prompt.md +55 -0
  23. devflow_engine/docs/prompts/devin2-agent-prompt.md +81 -0
  24. devflow_engine/docs/prompts/examples/devin-vapi-clone-reference-exchange.json +85 -0
  25. devflow_engine/doctor/__init__.py +2 -0
  26. devflow_engine/doctor/triage.py +140 -0
  27. devflow_engine/error/__init__.py +0 -0
  28. devflow_engine/error/remediation.py +21 -0
  29. devflow_engine/errors/error_solver_dag.py +522 -0
  30. devflow_engine/errors/runtime_observability.py +67 -0
  31. devflow_engine/idea/__init__.py +4 -0
  32. devflow_engine/idea/actors.py +481 -0
  33. devflow_engine/idea/agentic.py +465 -0
  34. devflow_engine/idea/analyze.py +93 -0
  35. devflow_engine/idea/devin_chat_dag.py +1 -0
  36. devflow_engine/idea/diff.py +99 -0
  37. devflow_engine/idea/drafts.py +446 -0
  38. devflow_engine/idea/idea_creation_dag.py +643 -0
  39. devflow_engine/idea/ideation_enrichment.py +355 -0
  40. devflow_engine/idea/ideation_enrichment_worker.py +19 -0
  41. devflow_engine/idea/paths.py +28 -0
  42. devflow_engine/idea/promote.py +53 -0
  43. devflow_engine/idea/redaction.py +27 -0
  44. devflow_engine/idea/repo_tools.py +1277 -0
  45. devflow_engine/idea/response_mode.py +30 -0
  46. devflow_engine/idea/story_pipeline.py +1585 -0
  47. devflow_engine/idea/sufficiency.py +376 -0
  48. devflow_engine/idea/traditional_stories.py +1257 -0
  49. devflow_engine/implementation/__init__.py +0 -0
  50. devflow_engine/implementation/alembic_preflight.py +700 -0
  51. devflow_engine/implementation/dag.py +8450 -0
  52. devflow_engine/implementation/green_gate.py +93 -0
  53. devflow_engine/implementation/prompts.py +108 -0
  54. devflow_engine/implementation/test_runtime.py +623 -0
  55. devflow_engine/integration/__init__.py +19 -0
  56. devflow_engine/integration/agentic.py +66 -0
  57. devflow_engine/integration/dag.py +3539 -0
  58. devflow_engine/integration/prompts.py +114 -0
  59. devflow_engine/integration/supabase_schema.sql +31 -0
  60. devflow_engine/integration/supabase_sync.py +177 -0
  61. devflow_engine/llm/__init__.py +1 -0
  62. devflow_engine/llm/cli_one_shot.py +84 -0
  63. devflow_engine/llm/cli_stream.py +371 -0
  64. devflow_engine/llm/execution_context.py +26 -0
  65. devflow_engine/llm/invoke.py +1322 -0
  66. devflow_engine/llm/provider_api.py +304 -0
  67. devflow_engine/llm/repo_knowledge.py +588 -0
  68. devflow_engine/llm_primitives.py +315 -0
  69. devflow_engine/orchestration.py +62 -0
  70. devflow_engine/planning/__init__.py +0 -0
  71. devflow_engine/planning/analyze_repo.py +92 -0
  72. devflow_engine/planning/render_drafts.py +133 -0
  73. devflow_engine/playground/__init__.py +0 -0
  74. devflow_engine/playground/hooks.py +26 -0
  75. devflow_engine/playwright_workflow/__init__.py +5 -0
  76. devflow_engine/playwright_workflow/dag.py +1317 -0
  77. devflow_engine/process/__init__.py +5 -0
  78. devflow_engine/process/dag.py +59 -0
  79. devflow_engine/project_registration/__init__.py +3 -0
  80. devflow_engine/project_registration/dag.py +1581 -0
  81. devflow_engine/project_registry.py +109 -0
  82. devflow_engine/prompts/devin/generic/prompt.md +6 -0
  83. devflow_engine/prompts/devin/ideation/prompt.md +263 -0
  84. devflow_engine/prompts/devin/ideation/scenarios.md +5 -0
  85. devflow_engine/prompts/devin/ideation_loop/prompt.md +6 -0
  86. devflow_engine/prompts/devin/insight/prompt.md +11 -0
  87. devflow_engine/prompts/devin/insight/scenarios.md +5 -0
  88. devflow_engine/prompts/devin/intake/prompt.md +15 -0
  89. devflow_engine/prompts/devin/iterate/prompt.md +12 -0
  90. devflow_engine/prompts/devin/shared/eval_doctrine.md +9 -0
  91. devflow_engine/prompts/devin/shared/principles.md +246 -0
  92. devflow_engine/prompts/devin_eval/assessment/prompt.md +18 -0
  93. devflow_engine/prompts/idea/api_ideation_agent/prompt.md +8 -0
  94. devflow_engine/prompts/idea/api_insight_agent/prompt.md +8 -0
  95. devflow_engine/prompts/idea/response_doctrine/prompt.md +18 -0
  96. devflow_engine/prompts/implementation/dependency_assessment/prompt.md +12 -0
  97. devflow_engine/prompts/implementation/green/green/prompt.md +11 -0
  98. devflow_engine/prompts/implementation/green/node_config/prompt.md +3 -0
  99. devflow_engine/prompts/implementation/green_review/outcome_review/prompt.md +5 -0
  100. devflow_engine/prompts/implementation/green_review/prior_run_review/prompt.md +5 -0
  101. devflow_engine/prompts/implementation/red/prompt.md +27 -0
  102. devflow_engine/prompts/implementation/redreview/prompt.md +23 -0
  103. devflow_engine/prompts/implementation/redreview_repair/prompt.md +16 -0
  104. devflow_engine/prompts/implementation/setupdoc/prompt.md +10 -0
  105. devflow_engine/prompts/implementation/story_planning/prompt.md +13 -0
  106. devflow_engine/prompts/implementation/test_design/prompt.md +27 -0
  107. devflow_engine/prompts/integration/README.md +185 -0
  108. devflow_engine/prompts/integration/green/example.md +67 -0
  109. devflow_engine/prompts/integration/green/green/prompt.md +10 -0
  110. devflow_engine/prompts/integration/green/node_config/prompt.md +42 -0
  111. devflow_engine/prompts/integration/green/past_prompts/20260417T212300/green/prompt.md +15 -0
  112. devflow_engine/prompts/integration/green/past_prompts/20260417T212300/node_config/prompt.md +42 -0
  113. devflow_engine/prompts/integration/green_enrich/example.md +79 -0
  114. devflow_engine/prompts/integration/green_enrich/green_enrich/prompt.md +9 -0
  115. devflow_engine/prompts/integration/green_enrich/node_config/prompt.md +41 -0
  116. devflow_engine/prompts/integration/green_enrich/past_prompts/20260417T212300/green_enrich/prompt.md +14 -0
  117. devflow_engine/prompts/integration/green_enrich/past_prompts/20260417T212300/node_config/prompt.md +41 -0
  118. devflow_engine/prompts/integration/red/code_repair/prompt.md +12 -0
  119. devflow_engine/prompts/integration/red/example.md +152 -0
  120. devflow_engine/prompts/integration/red/node_config/prompt.md +86 -0
  121. devflow_engine/prompts/integration/red/past_prompts/20260417T212300/code_repair/prompt.md +19 -0
  122. devflow_engine/prompts/integration/red/past_prompts/20260417T212300/node_config/prompt.md +84 -0
  123. devflow_engine/prompts/integration/red/past_prompts/20260417T212300/red/prompt.md +16 -0
  124. devflow_engine/prompts/integration/red/past_prompts/20260417T212300/red_repair/prompt.md +15 -0
  125. devflow_engine/prompts/integration/red/past_prompts/20260417T215032/code_repair/prompt.md +10 -0
  126. devflow_engine/prompts/integration/red/past_prompts/20260417T215032/node_config/prompt.md +84 -0
  127. devflow_engine/prompts/integration/red/past_prompts/20260417T215032/red_repair/prompt.md +11 -0
  128. devflow_engine/prompts/integration/red/red/prompt.md +11 -0
  129. devflow_engine/prompts/integration/red/red_repair/prompt.md +12 -0
  130. devflow_engine/prompts/integration/red_review/example.md +71 -0
  131. devflow_engine/prompts/integration/red_review/node_config/prompt.md +41 -0
  132. devflow_engine/prompts/integration/red_review/past_prompts/20260417T212300/node_config/prompt.md +41 -0
  133. devflow_engine/prompts/integration/red_review/past_prompts/20260417T212300/red_review/prompt.md +15 -0
  134. devflow_engine/prompts/integration/red_review/red_review/prompt.md +9 -0
  135. devflow_engine/prompts/integration/resolve/example.md +111 -0
  136. devflow_engine/prompts/integration/resolve/node_config/prompt.md +64 -0
  137. devflow_engine/prompts/integration/resolve/past_prompts/20260417T212300/node_config/prompt.md +64 -0
  138. devflow_engine/prompts/integration/resolve/past_prompts/20260417T212300/resolve_implicated_users/prompt.md +15 -0
  139. devflow_engine/prompts/integration/resolve/past_prompts/20260417T212300/resolve_side_effects/prompt.md +15 -0
  140. devflow_engine/prompts/integration/resolve/resolve_implicated_users/prompt.md +10 -0
  141. devflow_engine/prompts/integration/resolve/resolve_side_effects/prompt.md +10 -0
  142. devflow_engine/prompts/integration/validate/build_idea_acceptance_coverage/prompt.md +12 -0
  143. devflow_engine/prompts/integration/validate/code_repair/prompt.md +13 -0
  144. devflow_engine/prompts/integration/validate/example.md +143 -0
  145. devflow_engine/prompts/integration/validate/node_config/prompt.md +87 -0
  146. devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/code_repair/prompt.md +19 -0
  147. devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/node_config/prompt.md +67 -0
  148. devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/validate_enrich_gate/prompt.md +17 -0
  149. devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/validate_repair/prompt.md +16 -0
  150. devflow_engine/prompts/integration/validate/past_prompts/20260417T215032/code_repair/prompt.md +10 -0
  151. devflow_engine/prompts/integration/validate/past_prompts/20260417T215032/node_config/prompt.md +67 -0
  152. devflow_engine/prompts/integration/validate/past_prompts/20260417T215032/validate_repair/prompt.md +9 -0
  153. devflow_engine/prompts/integration/validate/validate_enrich_gate/prompt.md +10 -0
  154. devflow_engine/prompts/integration/validate/validate_repair/prompt.md +20 -0
  155. devflow_engine/prompts/integration/write_workflows/example.md +100 -0
  156. devflow_engine/prompts/integration/write_workflows/node_config/prompt.md +44 -0
  157. devflow_engine/prompts/integration/write_workflows/past_prompts/20260417T212300/node_config/prompt.md +44 -0
  158. devflow_engine/prompts/integration/write_workflows/past_prompts/20260417T212300/write_workflows/prompt.md +17 -0
  159. devflow_engine/prompts/integration/write_workflows/write_workflows/prompt.md +11 -0
  160. devflow_engine/prompts/iterate/README.md +7 -0
  161. devflow_engine/prompts/iterate/coder/prompt.md +11 -0
  162. devflow_engine/prompts/iterate/framer/prompt.md +11 -0
  163. devflow_engine/prompts/iterate/iterator/prompt.md +13 -0
  164. devflow_engine/prompts/iterate/observer/prompt.md +11 -0
  165. devflow_engine/prompts/recovery/diagnosis/prompt.md +7 -0
  166. devflow_engine/prompts/recovery/execution/prompt.md +8 -0
  167. devflow_engine/prompts/recovery/execution_verification/prompt.md +7 -0
  168. devflow_engine/prompts/recovery/failure_investigation/prompt.md +10 -0
  169. devflow_engine/prompts/recovery/preflight_health_repo_repair/prompt.md +8 -0
  170. devflow_engine/prompts/recovery/remediation_execution/prompt.md +11 -0
  171. devflow_engine/prompts/recovery/root_cause_investigation/prompt.md +12 -0
  172. devflow_engine/prompts/scope_idea/doctrine/prompt.md +7 -0
  173. devflow_engine/prompts/source_doc_eval/document/prompt.md +6 -0
  174. devflow_engine/prompts/source_doc_eval/targeted_mutation/prompt.md +9 -0
  175. devflow_engine/prompts/source_doc_mutation/domain_entities/prompt.md +6 -0
  176. devflow_engine/prompts/source_doc_mutation/product_brief/prompt.md +6 -0
  177. devflow_engine/prompts/source_doc_mutation/project_doc_coherence/prompt.md +7 -0
  178. devflow_engine/prompts/source_doc_mutation/project_doc_render/prompt.md +9 -0
  179. devflow_engine/prompts/source_doc_mutation/source_doc_coherence/prompt.md +5 -0
  180. devflow_engine/prompts/source_doc_mutation/source_doc_enrichment_coherence/prompt.md +6 -0
  181. devflow_engine/prompts/source_doc_mutation/user_workflows/prompt.md +6 -0
  182. devflow_engine/prompts/source_scope/doctrine/prompt.md +10 -0
  183. devflow_engine/prompts/ui_grounding/doctrine/prompt.md +7 -0
  184. devflow_engine/recovery/__init__.py +3 -0
  185. devflow_engine/recovery/dag.py +2609 -0
  186. devflow_engine/recovery/models.py +220 -0
  187. devflow_engine/refactor.py +93 -0
  188. devflow_engine/registry/__init__.py +1 -0
  189. devflow_engine/registry/cards.py +238 -0
  190. devflow_engine/registry/domain_normalize.py +60 -0
  191. devflow_engine/registry/effects.py +65 -0
  192. devflow_engine/registry/enforce_report.py +150 -0
  193. devflow_engine/registry/module_cards_classify.py +164 -0
  194. devflow_engine/registry/module_cards_draft.py +184 -0
  195. devflow_engine/registry/module_cards_gate.py +59 -0
  196. devflow_engine/registry/packages.py +347 -0
  197. devflow_engine/registry/pathways.py +323 -0
  198. devflow_engine/review/__init__.py +11 -0
  199. devflow_engine/review/dag.py +588 -0
  200. devflow_engine/review/review_story.py +67 -0
  201. devflow_engine/scope_idea/__init__.py +3 -0
  202. devflow_engine/scope_idea/agentic.py +39 -0
  203. devflow_engine/scope_idea/dag.py +1069 -0
  204. devflow_engine/scope_idea/models.py +175 -0
  205. devflow_engine/skills/builtins/devflow/queue_failure_investigation/SKILL.md +112 -0
  206. devflow_engine/skills/builtins/devflow/queue_idea_to_story/SKILL.md +120 -0
  207. devflow_engine/skills/builtins/devflow/queue_integration/SKILL.md +105 -0
  208. devflow_engine/skills/builtins/devflow/queue_recovery/SKILL.md +108 -0
  209. devflow_engine/skills/builtins/devflow/queue_runtime_core/SKILL.md +155 -0
  210. devflow_engine/skills/builtins/devflow/queue_story_implementation/SKILL.md +122 -0
  211. devflow_engine/skills/builtins/devin/idea_to_story_handoff/SKILL.md +120 -0
  212. devflow_engine/skills/builtins/devin/ideation/SKILL.md +168 -0
  213. devflow_engine/skills/builtins/devin/ideation/state-and-phrasing-reference.md +18 -0
  214. devflow_engine/skills/builtins/devin/insight/SKILL.md +22 -0
  215. devflow_engine/skills/registry.example.yaml +42 -0
  216. devflow_engine/source_doc_assumptions.py +291 -0
  217. devflow_engine/source_doc_mutation_dag.py +1606 -0
  218. devflow_engine/source_doc_mutation_eval.py +417 -0
  219. devflow_engine/source_doc_mutation_worker.py +25 -0
  220. devflow_engine/source_docs_schema.py +207 -0
  221. devflow_engine/source_docs_updater.py +309 -0
  222. devflow_engine/source_scope/__init__.py +15 -0
  223. devflow_engine/source_scope/agentic.py +45 -0
  224. devflow_engine/source_scope/dag.py +1626 -0
  225. devflow_engine/source_scope/models.py +177 -0
  226. devflow_engine/stores/__init__.py +0 -0
  227. devflow_engine/stores/execution_store.py +3534 -0
  228. devflow_engine/story/__init__.py +0 -0
  229. devflow_engine/story/contracts.py +160 -0
  230. devflow_engine/story/discovery.py +47 -0
  231. devflow_engine/story/evidence.py +118 -0
  232. devflow_engine/story/hashing.py +27 -0
  233. devflow_engine/story/implemented_queue_purge.py +148 -0
  234. devflow_engine/story/indexer.py +105 -0
  235. devflow_engine/story/io.py +20 -0
  236. devflow_engine/story/markdown_contracts.py +298 -0
  237. devflow_engine/story/reconciliation.py +408 -0
  238. devflow_engine/story/validate_stories.py +149 -0
  239. devflow_engine/story/validate_tests_story.py +512 -0
  240. devflow_engine/story/validation.py +133 -0
  241. devflow_engine/ui_grounding/__init__.py +11 -0
  242. devflow_engine/ui_grounding/agentic.py +31 -0
  243. devflow_engine/ui_grounding/dag.py +874 -0
  244. devflow_engine/ui_grounding/models.py +224 -0
  245. devflow_engine/ui_grounding/pencil_bridge.py +247 -0
  246. devflow_engine/vendor/__init__.py +0 -0
  247. devflow_engine/vendor/datalumina_genai/__init__.py +11 -0
  248. devflow_engine/vendor/datalumina_genai/core/__init__.py +0 -0
  249. devflow_engine/vendor/datalumina_genai/core/exceptions.py +9 -0
  250. devflow_engine/vendor/datalumina_genai/core/nodes/__init__.py +0 -0
  251. devflow_engine/vendor/datalumina_genai/core/nodes/agent.py +48 -0
  252. devflow_engine/vendor/datalumina_genai/core/nodes/agent_streaming_node.py +26 -0
  253. devflow_engine/vendor/datalumina_genai/core/nodes/base.py +89 -0
  254. devflow_engine/vendor/datalumina_genai/core/nodes/concurrent.py +30 -0
  255. devflow_engine/vendor/datalumina_genai/core/nodes/router.py +69 -0
  256. devflow_engine/vendor/datalumina_genai/core/schema.py +72 -0
  257. devflow_engine/vendor/datalumina_genai/core/task.py +52 -0
  258. devflow_engine/vendor/datalumina_genai/core/validate.py +139 -0
  259. devflow_engine/vendor/datalumina_genai/core/workflow.py +200 -0
  260. devflow_engine/worker.py +1086 -0
  261. devflow_engine/worker_guard.py +233 -0
  262. devflow_engine-1.0.0.dist-info/METADATA +235 -0
  263. devflow_engine-1.0.0.dist-info/RECORD +393 -0
  264. devflow_engine-1.0.0.dist-info/WHEEL +4 -0
  265. devflow_engine-1.0.0.dist-info/entry_points.txt +3 -0
  266. devin/__init__.py +6 -0
  267. devin/dag.py +58 -0
  268. devin/dag_two_arm.py +138 -0
  269. devin/devin_chat_scenario_catalog.json +588 -0
  270. devin/devin_eval.py +677 -0
  271. devin/nodes/__init__.py +0 -0
  272. devin/nodes/ideation/__init__.py +0 -0
  273. devin/nodes/ideation/node.py +195 -0
  274. devin/nodes/ideation/playground.py +267 -0
  275. devin/nodes/ideation/prompt.md +65 -0
  276. devin/nodes/ideation/scenarios/continue_refinement.py +13 -0
  277. devin/nodes/ideation/scenarios/continue_refinement_evals.py +18 -0
  278. devin/nodes/ideation/scenarios/idea_fits_existing_patterns.py +17 -0
  279. devin/nodes/ideation/scenarios/idea_fits_existing_patterns_evals.py +16 -0
  280. devin/nodes/ideation/scenarios/large_idea_split.py +4 -0
  281. devin/nodes/ideation/scenarios/large_idea_split_evals.py +17 -0
  282. devin/nodes/ideation/scenarios/source_documentation_added.py +4 -0
  283. devin/nodes/ideation/scenarios/source_documentation_added_evals.py +16 -0
  284. devin/nodes/ideation/scenarios/user_says_create_it.py +30 -0
  285. devin/nodes/ideation/scenarios/user_says_create_it_evals.py +23 -0
  286. devin/nodes/ideation/scenarios/vague_idea.py +16 -0
  287. devin/nodes/ideation/scenarios/vague_idea_evals.py +47 -0
  288. devin/nodes/ideation/tools.json +312 -0
  289. devin/nodes/insight/__init__.py +0 -0
  290. devin/nodes/insight/node.py +49 -0
  291. devin/nodes/insight/playground.py +154 -0
  292. devin/nodes/insight/prompt.md +61 -0
  293. devin/nodes/insight/scenarios/architecture_pattern_query.py +15 -0
  294. devin/nodes/insight/scenarios/architecture_pattern_query_evals.py +25 -0
  295. devin/nodes/insight/scenarios/codebase_exploration.py +15 -0
  296. devin/nodes/insight/scenarios/codebase_exploration_evals.py +23 -0
  297. devin/nodes/insight/scenarios/devin_ideation_routing.py +19 -0
  298. devin/nodes/insight/scenarios/devin_ideation_routing_evals.py +39 -0
  299. devin/nodes/insight/scenarios/devin_insight_routing.py +20 -0
  300. devin/nodes/insight/scenarios/devin_insight_routing_evals.py +40 -0
  301. devin/nodes/insight/scenarios/operational_debugging.py +15 -0
  302. devin/nodes/insight/scenarios/operational_debugging_evals.py +23 -0
  303. devin/nodes/insight/scenarios/operational_question.py +9 -0
  304. devin/nodes/insight/scenarios/operational_question_evals.py +8 -0
  305. devin/nodes/insight/scenarios/queue_status.py +15 -0
  306. devin/nodes/insight/scenarios/queue_status_evals.py +23 -0
  307. devin/nodes/insight/scenarios/source_doc_explanation.py +14 -0
  308. devin/nodes/insight/scenarios/source_doc_explanation_evals.py +21 -0
  309. devin/nodes/insight/scenarios/worker_state_check.py +15 -0
  310. devin/nodes/insight/scenarios/worker_state_check_evals.py +22 -0
  311. devin/nodes/insight/tools.json +126 -0
  312. devin/nodes/intake/__init__.py +0 -0
  313. devin/nodes/intake/node.py +27 -0
  314. devin/nodes/intake/playground.py +47 -0
  315. devin/nodes/intake/prompt.md +12 -0
  316. devin/nodes/intake/scenarios/ideation_routing.py +4 -0
  317. devin/nodes/intake/scenarios/ideation_routing_evals.py +5 -0
  318. devin/nodes/intake/scenarios/insight_routing.py +4 -0
  319. devin/nodes/intake/scenarios/insight_routing_evals.py +5 -0
  320. devin/nodes/iterate/README.md +44 -0
  321. devin/nodes/iterate/__init__.py +1 -0
  322. devin/nodes/iterate/_archived_design_stages/01-objectives-requirements.md +112 -0
  323. devin/nodes/iterate/_archived_design_stages/02-evals.md +131 -0
  324. devin/nodes/iterate/_archived_design_stages/03-tools-and-boundaries.md +110 -0
  325. devin/nodes/iterate/_archived_design_stages/04-harness-and-playground.md +32 -0
  326. devin/nodes/iterate/_archived_design_stages/05-prompt-deferred.md +11 -0
  327. devin/nodes/iterate/_archived_design_stages/coder_agent_design/01-objectives-requirements.md +20 -0
  328. devin/nodes/iterate/_archived_design_stages/coder_agent_design/02-evals.md +8 -0
  329. devin/nodes/iterate/_archived_design_stages/coder_agent_design/03-tools-and-boundaries.md +14 -0
  330. devin/nodes/iterate/_archived_design_stages/coder_agent_design/04-harness-and-playground.md +12 -0
  331. devin/nodes/iterate/_archived_design_stages/framer_agent_design/01-objectives-requirements.md +20 -0
  332. devin/nodes/iterate/_archived_design_stages/framer_agent_design/02-evals.md +8 -0
  333. devin/nodes/iterate/_archived_design_stages/framer_agent_design/03-tools-and-boundaries.md +13 -0
  334. devin/nodes/iterate/_archived_design_stages/framer_agent_design/04-harness-and-playground.md +12 -0
  335. devin/nodes/iterate/_archived_design_stages/iterator_agent_design/01-objectives-requirements.md +25 -0
  336. devin/nodes/iterate/_archived_design_stages/iterator_agent_design/02-evals.md +9 -0
  337. devin/nodes/iterate/_archived_design_stages/iterator_agent_design/03-tools-and-boundaries.md +14 -0
  338. devin/nodes/iterate/_archived_design_stages/iterator_agent_design/04-harness-and-playground.md +12 -0
  339. devin/nodes/iterate/_archived_design_stages/observer_agent_design/01-objectives-requirements.md +20 -0
  340. devin/nodes/iterate/_archived_design_stages/observer_agent_design/02-evals.md +8 -0
  341. devin/nodes/iterate/_archived_design_stages/observer_agent_design/03-tools-and-boundaries.md +14 -0
  342. devin/nodes/iterate/_archived_design_stages/observer_agent_design/04-harness-and-playground.md +13 -0
  343. devin/nodes/iterate/agent-roles.md +89 -0
  344. devin/nodes/iterate/agents/README.md +10 -0
  345. devin/nodes/iterate/artifacts.md +504 -0
  346. devin/nodes/iterate/contract.md +100 -0
  347. devin/nodes/iterate/eval-plan.md +74 -0
  348. devin/nodes/iterate/node.py +100 -0
  349. devin/nodes/iterate/pipeline/README.md +13 -0
  350. devin/nodes/iterate/playground-contract.md +76 -0
  351. devin/nodes/iterate/prompt.md +11 -0
  352. devin/nodes/iterate/scenarios/README.md +38 -0
  353. devin/nodes/iterate/scenarios/artifact-and-loop-scenarios.md +101 -0
  354. devin/nodes/iterate/scenarios/coder_artifact_alignment.py +32 -0
  355. devin/nodes/iterate/scenarios/coder_artifact_alignment_evals.py +45 -0
  356. devin/nodes/iterate/scenarios/coder_bounded_fix.py +27 -0
  357. devin/nodes/iterate/scenarios/coder_bounded_fix_evals.py +45 -0
  358. devin/nodes/iterate/scenarios/devin_iterate_routing.py +21 -0
  359. devin/nodes/iterate/scenarios/devin_iterate_routing_evals.py +36 -0
  360. devin/nodes/iterate/scenarios/framer_scope_boundary.py +25 -0
  361. devin/nodes/iterate/scenarios/framer_scope_boundary_evals.py +57 -0
  362. devin/nodes/iterate/scenarios/framer_task_framing.py +25 -0
  363. devin/nodes/iterate/scenarios/framer_task_framing_evals.py +58 -0
  364. devin/nodes/iterate/scenarios/iterate_error_fix.py +21 -0
  365. devin/nodes/iterate/scenarios/iterate_error_fix_evals.py +39 -0
  366. devin/nodes/iterate/scenarios/iterate_quick_change.py +21 -0
  367. devin/nodes/iterate/scenarios/iterate_quick_change_evals.py +35 -0
  368. devin/nodes/iterate/scenarios/iterate_to_idea_promotion.py +23 -0
  369. devin/nodes/iterate/scenarios/iterate_to_idea_promotion_evals.py +53 -0
  370. devin/nodes/iterate/scenarios/iterate_to_insight_reroute.py +23 -0
  371. devin/nodes/iterate/scenarios/iterate_to_insight_reroute_evals.py +53 -0
  372. devin/nodes/iterate/scenarios/observer_evidence_seam.py +28 -0
  373. devin/nodes/iterate/scenarios/observer_evidence_seam_evals.py +55 -0
  374. devin/nodes/iterate/scenarios/observer_repro_creation.py +28 -0
  375. devin/nodes/iterate/scenarios/observer_repro_creation_evals.py +45 -0
  376. devin/nodes/iterate/scenarios/routing-matrix.md +45 -0
  377. devin/nodes/shared/__init__.py +0 -0
  378. devin/nodes/shared/filemaker_expert.md +80 -0
  379. devin/nodes/shared/filemaker_expert.py +354 -0
  380. devin/nodes/shared/filemaker_expert_eval/runner.py +176 -0
  381. devin/nodes/shared/filemaker_expert_eval/scenarios.json +65 -0
  382. devin/nodes/shared/goldilocks_advisor_eval/runner.py +214 -0
  383. devin/nodes/shared/goldilocks_advisor_eval/scenarios.json +58 -0
  384. devin/nodes/shared/helpers.py +156 -0
  385. devin/nodes/shared/idea_compliance_advisor_eval/runner.py +252 -0
  386. devin/nodes/shared/idea_compliance_advisor_eval/scenarios.json +75 -0
  387. devin/nodes/shared/models.py +44 -0
  388. devin/nodes/shared/post.py +40 -0
  389. devin/nodes/shared/router.py +107 -0
  390. devin/nodes/shared/tools.py +191 -0
  391. devin/shared/devin-chat-rubric.md +237 -0
  392. devin/shared/devin-chat-scenario-suite.md +90 -0
  393. devin/shared/eval_doctrine.md +9 -0
@@ -0,0 +1,224 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any, Literal
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ GroundingStatus = Literal[
8
+ "grounded_ready",
9
+ "grounded_with_generated_artifacts",
10
+ "pass_with_assumptions",
11
+ "needs_ui_review",
12
+ "blocked_missing_ui_grounding",
13
+ ]
14
+ SurfaceClassification = Literal[
15
+ "grounded_existing",
16
+ "grounded_partial",
17
+ "grounded_with_generated_artifacts",
18
+ "missing_reference",
19
+ "non_ui_or_backend_only",
20
+ ]
21
+ ReferenceType = Literal[
22
+ "implemented_ui",
23
+ "design_doc",
24
+ "pencil_artifact",
25
+ "wireframe_package",
26
+ "screenshot_spec",
27
+ ]
28
+
29
+
30
+ class UIGroundingContextArtifact(BaseModel):
31
+ project_id: str
32
+ idea_id: str
33
+ idea_title: str
34
+ idea_summary: str
35
+ idea_path: str | None = None
36
+ story_paths: list[str] = Field(default_factory=list)
37
+ story_summaries: list[str] = Field(default_factory=list)
38
+ design_paths: list[str] = Field(default_factory=list)
39
+ repo_root: str
40
+ upstream_refs: list[str] = Field(default_factory=list)
41
+
42
+
43
+ class DerivedUISurface(BaseModel):
44
+ surface_id: str
45
+ name: str
46
+ actor: str = "user"
47
+ jobs: list[str] = Field(default_factory=list)
48
+ ui_bearing: bool = True
49
+ confidence: str = "medium"
50
+ rationale: str
51
+ source_refs: list[str] = Field(default_factory=list)
52
+
53
+
54
+ class UISurfaceDerivationArtifact(BaseModel):
55
+ project_id: str
56
+ idea_id: str
57
+ surfaces: list[DerivedUISurface] = Field(default_factory=list)
58
+ derivation_notes: list[str] = Field(default_factory=list)
59
+
60
+
61
+ class UIReferenceInventoryItem(BaseModel):
62
+ reference_id: str
63
+ reference_type: ReferenceType
64
+ path: str
65
+ surface_labels: list[str] = Field(default_factory=list)
66
+ provenance: list[str] = Field(default_factory=list)
67
+ approval_status: str = "unknown"
68
+
69
+
70
+ class UIReferenceInventoryArtifact(BaseModel):
71
+ project_id: str
72
+ idea_id: str
73
+ references: list[UIReferenceInventoryItem] = Field(default_factory=list)
74
+ inventory_notes: list[str] = Field(default_factory=list)
75
+
76
+
77
+ class CodeDesignGeneratedReference(BaseModel):
78
+ surface_id: str
79
+ source_paths: list[str] = Field(default_factory=list)
80
+ generated_reference_id: str
81
+ generated_anchor: str
82
+ generation_kind: Literal["full_screen", "partial_screen", "supporting_extraction"] = "full_screen"
83
+ review_needed: bool = False
84
+ normalized_reference: UIReferenceInventoryItem
85
+
86
+
87
+ class CodeDesignInventoryArtifact(BaseModel):
88
+ project_id: str
89
+ idea_id: str
90
+ status: Literal[
91
+ "not_requested",
92
+ "skipped_preflight_not_ready",
93
+ "skipped_no_missing_surfaces",
94
+ "skipped_no_relevant_implemented_ui",
95
+ "generated",
96
+ ]
97
+ target_surface_ids: list[str] = Field(default_factory=list)
98
+ generated_references: list[CodeDesignGeneratedReference] = Field(default_factory=list)
99
+ notes: list[str] = Field(default_factory=list)
100
+
101
+
102
+ class UIGroundingSurfaceResult(BaseModel):
103
+ surface_id: str
104
+ name: str
105
+ classification: SurfaceClassification
106
+ matched_reference_ids: list[str] = Field(default_factory=list)
107
+ supporting_paths: list[str] = Field(default_factory=list)
108
+ assumptions: list[str] = Field(default_factory=list)
109
+ unresolved_questions: list[str] = Field(default_factory=list)
110
+ next_required_action: str
111
+
112
+
113
+ class UIGroundingReportArtifact(BaseModel):
114
+ project_id: str
115
+ idea_id: str
116
+ status: GroundingStatus
117
+ surfaces: list[UIGroundingSurfaceResult] = Field(default_factory=list)
118
+ summary: str
119
+ assumptions: list[str] = Field(default_factory=list)
120
+ next_actions: list[str] = Field(default_factory=list)
121
+
122
+
123
+ class UIGapReportArtifact(BaseModel):
124
+ project_id: str
125
+ idea_id: str
126
+ missing_surfaces: list[str] = Field(default_factory=list)
127
+ reasons: list[str] = Field(default_factory=list)
128
+ recommendation: str
129
+ blocked: bool = True
130
+
131
+
132
+ UIScreenSurfaceClass = Literal[
133
+ "admin_web",
134
+ "field_tablet",
135
+ "customer_secure_link",
136
+ "customer_portal",
137
+ "internal_support_tool",
138
+ "general_web",
139
+ "non_ui_or_backend_only",
140
+ ]
141
+ UIScreenPlatform = Literal[
142
+ "web_desktop",
143
+ "web_mobile_responsive",
144
+ "tablet",
145
+ "multi_platform",
146
+ "not_applicable",
147
+ ]
148
+ UIScreenFidelity = Literal["low", "medium", "high"]
149
+ UIScreenAudience = Literal["internal_exploration", "customer_review", "implementation_handoff"]
150
+
151
+
152
+ class UIStructureScreenItem(BaseModel):
153
+ surface_id: str
154
+ screen_id: str
155
+ name: str
156
+ surface_class: UIScreenSurfaceClass
157
+ platform: UIScreenPlatform = "web_desktop"
158
+ actor: str = "user"
159
+ journey_stage: str
160
+ required: bool = True
161
+ source_refs: list[str] = Field(default_factory=list)
162
+ grounding_refs: list[str] = Field(default_factory=list)
163
+ target_fidelity: UIScreenFidelity = "medium"
164
+ target_audience: UIScreenAudience = "customer_review"
165
+ confidence: str = "medium"
166
+ confidence_reason: str = "Derived from UI grounding status and source wording."
167
+ open_questions: list[str] = Field(default_factory=list)
168
+ assumption_tags: list[str] = Field(default_factory=list)
169
+ notes: list[str] = Field(default_factory=list)
170
+ flow_id: str = "primary"
171
+ shell_id: str | None = None
172
+ variant_ids: list[str] = Field(default_factory=list)
173
+ dependency_screen_ids: list[str] = Field(default_factory=list)
174
+
175
+
176
+ class UIStructureContractArtifact(BaseModel):
177
+ project_id: str
178
+ idea_id: str
179
+ status: Literal["ready_for_generation", "needs_ui_review", "non_ui_only"]
180
+ default_minimum_fidelity: UIScreenFidelity = "medium"
181
+ primary_audience: UIScreenAudience = "customer_review"
182
+ screens: list[UIStructureScreenItem] = Field(default_factory=list)
183
+ flow_order: list[str] = Field(default_factory=list)
184
+ shared_shells: list[dict[str, Any]] = Field(default_factory=list)
185
+ structural_notes: list[str] = Field(default_factory=list)
186
+ unresolved_questions: list[str] = Field(default_factory=list)
187
+
188
+
189
+ class UIFlowMapArtifact(BaseModel):
190
+ project_id: str
191
+ idea_id: str
192
+ flows: list[dict[str, Any]] = Field(default_factory=list)
193
+
194
+
195
+ class UIScreenRelationshipsArtifact(BaseModel):
196
+ project_id: str
197
+ idea_id: str
198
+ relationships: list[dict[str, Any]] = Field(default_factory=list)
199
+
200
+
201
+ class UIGenerationManifestArtifact(BaseModel):
202
+ project_id: str
203
+ idea_id: str
204
+ primary_audience: UIScreenAudience = "customer_review"
205
+ default_minimum_fidelity: UIScreenFidelity = "medium"
206
+ review_packet_outputs: list[str] = Field(default_factory=list)
207
+ screen_generation_items: list[dict[str, Any]] = Field(default_factory=list)
208
+
209
+
210
+ class GroundedStoryReferencePatchArtifact(BaseModel):
211
+ project_id: str
212
+ idea_id: str
213
+ target_refs: list[str] = Field(default_factory=list)
214
+ attached_ui_anchors: list[dict[str, Any]] = Field(default_factory=list)
215
+ supporting_evidence_refs: list[str] = Field(default_factory=list)
216
+ origin: Literal["existing_ui", "generated_ui", "mixed"] = "existing_ui"
217
+
218
+
219
+ class UIGroundingDagSummary(BaseModel):
220
+ exit_code: int
221
+ run_id: str
222
+ pipeline_dir: str
223
+ message: str
224
+ outcome: dict[str, Any]
@@ -0,0 +1,247 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import shutil
6
+ import subprocess
7
+ import time
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from pydantic import BaseModel, Field
12
+
13
+ from ..stores.execution_store import ExecutionStore
14
+
15
+ DEFAULT_PENCIL_APP_PATH = Path("/Applications/Pencil.app")
16
+ DEFAULT_LAUNCH_TIMEOUT_SECONDS = 15.0
17
+ DEFAULT_MCP_TIMEOUT_SECONDS = 15.0
18
+ DEFAULT_ARTIFACT_PATH = Path(".devflow/ui_grounding/pencil_preflight.json")
19
+
20
+
21
+ class PencilMCPProbeResult(BaseModel):
22
+ server_path: str | None = None
23
+ initialize_sent: bool = False
24
+ initialize_acknowledged: bool = False
25
+ server_name: str | None = None
26
+ server_version: str | None = None
27
+ protocol_version: str | None = None
28
+ error: str | None = None
29
+
30
+
31
+ class PencilPreflightArtifact(BaseModel):
32
+ ok: bool
33
+ status: str
34
+ repo_root: str
35
+ artifact_path: str
36
+ pencil_app_path: str
37
+ app_exists: bool
38
+ process_running_before: bool
39
+ launched: bool = False
40
+ process_running_after: bool = False
41
+ mcp: PencilMCPProbeResult = Field(default_factory=PencilMCPProbeResult)
42
+ checked_at_epoch: float
43
+ errors: list[str] = Field(default_factory=list)
44
+
45
+
46
+ class PencilPreflightResult(BaseModel):
47
+ exit_code: int
48
+ message: str
49
+ artifact_path: str
50
+ artifact: PencilPreflightArtifact
51
+
52
+
53
+ def _write_json(path: Path, payload: dict[str, Any]) -> None:
54
+ path.parent.mkdir(parents=True, exist_ok=True)
55
+ path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
56
+
57
+
58
+ def _artifact_path(repo_root: Path, artifact_path: Path | None) -> Path:
59
+ if artifact_path is not None:
60
+ return artifact_path if artifact_path.is_absolute() else repo_root / artifact_path
61
+ return repo_root / DEFAULT_ARTIFACT_PATH
62
+
63
+
64
+ def resolve_pencil_app_path(app_path: Path | None = None) -> Path:
65
+ override = app_path or (Path(os.environ["DEVFLOW_PENCIL_APP_PATH"]) if os.environ.get("DEVFLOW_PENCIL_APP_PATH") else None)
66
+ return override or DEFAULT_PENCIL_APP_PATH
67
+
68
+
69
+ def _pgrep_name_candidates(app_path: Path) -> list[str]:
70
+ names = [app_path.stem]
71
+ if app_path.stem.endswith('.app'):
72
+ names.append(app_path.stem[:-4])
73
+ return [name for name in names if name]
74
+
75
+
76
+ def is_pencil_running(app_path: Path) -> bool:
77
+ for name in _pgrep_name_candidates(app_path):
78
+ cp = subprocess.run(["pgrep", "-x", name], capture_output=True, text=True, check=False)
79
+ if cp.returncode == 0 and cp.stdout.strip():
80
+ return True
81
+ return False
82
+
83
+
84
+ def launch_pencil(app_path: Path) -> None:
85
+ subprocess.run(["open", "-a", str(app_path)], capture_output=True, text=True, check=True)
86
+
87
+
88
+ def ensure_pencil_running(app_path: Path, *, timeout_seconds: float = DEFAULT_LAUNCH_TIMEOUT_SECONDS) -> tuple[bool, bool]:
89
+ was_running = is_pencil_running(app_path)
90
+ launched = False
91
+ if not was_running:
92
+ launch_pencil(app_path)
93
+ launched = True
94
+ deadline = time.monotonic() + timeout_seconds
95
+ while time.monotonic() < deadline:
96
+ if is_pencil_running(app_path):
97
+ break
98
+ time.sleep(0.25)
99
+ return was_running, is_pencil_running(app_path) and launched
100
+
101
+
102
+ def locate_mcp_server(app_path: Path) -> Path | None:
103
+ bundled = app_path / "Contents" / "Resources" / "app.asar.unpacked" / "out" / "mcp-server-darwin-arm64"
104
+ return bundled if bundled.exists() else None
105
+
106
+
107
+ def probe_pencil_mcp(*, app_path: Path, timeout_seconds: float = DEFAULT_MCP_TIMEOUT_SECONDS) -> PencilMCPProbeResult:
108
+ server_path = locate_mcp_server(app_path)
109
+ if server_path is None:
110
+ return PencilMCPProbeResult(error="bundled Pencil MCP server not found")
111
+ if not os.access(server_path, os.X_OK):
112
+ return PencilMCPProbeResult(server_path=str(server_path), error="bundled Pencil MCP server is not executable")
113
+
114
+ req = {
115
+ "jsonrpc": "2.0",
116
+ "id": 1,
117
+ "method": "initialize",
118
+ "params": {
119
+ "protocolVersion": "2024-11-05",
120
+ "capabilities": {},
121
+ "clientInfo": {"name": "devflow-engine", "version": "1.0.0"},
122
+ },
123
+ }
124
+ try:
125
+ cp = subprocess.run(
126
+ [str(server_path), "-app", str(app_path)],
127
+ input=json.dumps(req) + "\n",
128
+ capture_output=True,
129
+ text=True,
130
+ check=False,
131
+ timeout=timeout_seconds,
132
+ )
133
+ except subprocess.TimeoutExpired:
134
+ return PencilMCPProbeResult(server_path=str(server_path), initialize_sent=True, error="timed out waiting for MCP initialize response")
135
+ except Exception as exc:
136
+ return PencilMCPProbeResult(server_path=str(server_path), initialize_sent=True, error=f"failed to run bundled MCP server: {exc}")
137
+
138
+ stdout_lines = [line.strip() for line in cp.stdout.splitlines() if line.strip()]
139
+ for line in stdout_lines:
140
+ try:
141
+ payload = json.loads(line)
142
+ except json.JSONDecodeError:
143
+ continue
144
+ if payload.get("id") != 1:
145
+ continue
146
+ if payload.get("jsonrpc") != "2.0":
147
+ continue
148
+ if "result" in payload and isinstance(payload["result"], dict):
149
+ result = payload["result"]
150
+ server_info = result.get("serverInfo") or {}
151
+ return PencilMCPProbeResult(
152
+ server_path=str(server_path),
153
+ initialize_sent=True,
154
+ initialize_acknowledged=True,
155
+ server_name=server_info.get("name"),
156
+ server_version=server_info.get("version"),
157
+ protocol_version=result.get("protocolVersion"),
158
+ )
159
+ if "error" in payload:
160
+ return PencilMCPProbeResult(server_path=str(server_path), initialize_sent=True, error=json.dumps(payload["error"], sort_keys=True))
161
+
162
+ detail = cp.stderr.strip() or stdout_lines[-1] if stdout_lines else "no initialize response received"
163
+ return PencilMCPProbeResult(server_path=str(server_path), initialize_sent=True, error=detail)
164
+
165
+
166
+ def run_pencil_preflight(*, repo_root: Path, store: ExecutionStore | None = None, app_path: Path | None = None, artifact_path: Path | None = None) -> PencilPreflightResult:
167
+ resolved_app_path = resolve_pencil_app_path(app_path)
168
+ resolved_artifact_path = _artifact_path(repo_root, artifact_path)
169
+ errors: list[str] = []
170
+ process_running_before = is_pencil_running(resolved_app_path) if shutil.which("pgrep") else False
171
+
172
+ artifact = PencilPreflightArtifact(
173
+ ok=False,
174
+ status="starting",
175
+ repo_root=str(repo_root),
176
+ artifact_path=str(resolved_artifact_path),
177
+ pencil_app_path=str(resolved_app_path),
178
+ app_exists=resolved_app_path.exists(),
179
+ process_running_before=process_running_before,
180
+ checked_at_epoch=time.time(),
181
+ )
182
+
183
+ if not artifact.app_exists:
184
+ artifact.status = "not_installed"
185
+ errors.append(f"Pencil.app not found at {resolved_app_path}")
186
+ artifact.errors = errors
187
+ _write_json(resolved_artifact_path, artifact.model_dump())
188
+ return PencilPreflightResult(exit_code=2, message=json.dumps({"status": artifact.status, "artifact_path": str(resolved_artifact_path)}) + "\n", artifact_path=str(resolved_artifact_path), artifact=artifact)
189
+
190
+ try:
191
+ before_running = is_pencil_running(resolved_app_path)
192
+ artifact.process_running_before = before_running
193
+ launched = False
194
+ if not before_running:
195
+ launch_pencil(resolved_app_path)
196
+ launched = True
197
+ deadline = time.monotonic() + DEFAULT_LAUNCH_TIMEOUT_SECONDS
198
+ while time.monotonic() < deadline:
199
+ if is_pencil_running(resolved_app_path):
200
+ break
201
+ time.sleep(0.25)
202
+ artifact.launched = launched
203
+ artifact.process_running_after = is_pencil_running(resolved_app_path)
204
+ if not artifact.process_running_after:
205
+ artifact.status = "launch_failed"
206
+ errors.append("Pencil.app is not running after launch attempt")
207
+ else:
208
+ artifact.mcp = probe_pencil_mcp(app_path=resolved_app_path)
209
+ if artifact.mcp.initialize_acknowledged:
210
+ artifact.ok = True
211
+ artifact.status = "ready"
212
+ else:
213
+ artifact.status = "mcp_unavailable"
214
+ if artifact.mcp.error:
215
+ errors.append(artifact.mcp.error)
216
+ except subprocess.CalledProcessError as exc:
217
+ artifact.status = "launch_failed"
218
+ errors.append(exc.stderr.strip() or exc.stdout.strip() or str(exc))
219
+ except Exception as exc:
220
+ artifact.status = "error"
221
+ errors.append(str(exc))
222
+
223
+ artifact.errors = errors
224
+ _write_json(resolved_artifact_path, artifact.model_dump())
225
+
226
+ if store is not None:
227
+ run_id = store.create_run(
228
+ dag_id="ui_grounding_pencil_preflight",
229
+ dag_version="v1",
230
+ root_correlation_id=f"pencil_preflight:{resolved_app_path}",
231
+ config={"repo_root": str(repo_root), "pencil_app_path": str(resolved_app_path)},
232
+ )
233
+ store.mark_run_started(run_id=run_id)
234
+ store.add_artifact(
235
+ run_id=run_id,
236
+ node_exec_id=None,
237
+ kind="ui_grounding.pencil_preflight",
238
+ uri=str(resolved_artifact_path),
239
+ metadata=artifact.model_dump(),
240
+ content_type="application/json",
241
+ byte_size=resolved_artifact_path.stat().st_size,
242
+ )
243
+ store.mark_run_finished(run_id=run_id, status="succeeded" if artifact.ok else "failed")
244
+
245
+ exit_code = 0 if artifact.ok else 2
246
+ message = json.dumps({"status": artifact.status, "artifact_path": str(resolved_artifact_path)}, sort_keys=True) + "\n"
247
+ return PencilPreflightResult(exit_code=exit_code, message=message, artifact_path=str(resolved_artifact_path), artifact=artifact)
File without changes
@@ -0,0 +1,11 @@
1
+ """Vendored subset of Datalumina GenAI.
2
+
3
+ This package is intentionally vendored to keep DevFlow Engine self-contained.
4
+ Only the workflow/DAG engine components used by DevFlow are included.
5
+ """
6
+
7
+ from .core.workflow import Workflow
8
+ from .core.schema import WorkflowSchema
9
+ from .core.validate import WorkflowValidator
10
+
11
+ __all__ = ["Workflow", "WorkflowSchema", "WorkflowValidator"]
@@ -0,0 +1,9 @@
1
+ import logging
2
+
3
+
4
+ class LangfuseAuthenticationError(Exception):
5
+ """Raised when Langfuse authentication fails."""
6
+
7
+ def __init__(self, message: str = "Failed to authenticate with Langfuse."):
8
+ logging.error(message)
9
+ super().__init__(message)
@@ -0,0 +1,48 @@
1
+ """Agent node (vendored stub).
2
+
3
+ Upstream Datalumina GenAI includes deep integrations (OpenAI/Anthropic/Bedrock/etc).
4
+ DevFlow Engine does not require those dependencies for its CLI-first workflow engine.
5
+
6
+ This stub preserves the public class names used by the workflow runner.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ from abc import ABC, abstractmethod
12
+ from dataclasses import dataclass
13
+ from typing import Any, Optional
14
+
15
+ from pydantic import BaseModel
16
+
17
+ from .base import Node
18
+ from ..task import TaskContext
19
+
20
+
21
+ @dataclass
22
+ class AgentConfig:
23
+ """Placeholder config for compatibility."""
24
+
25
+ instructions: Optional[str] = None
26
+ output_type: Any = str
27
+
28
+
29
+ class AgentNode(Node, ABC):
30
+ """A minimal async node interface.
31
+
32
+ Subclasses are expected to implement `process` and may use `task_context.event`
33
+ and `task_context.nodes` for state.
34
+ """
35
+
36
+ class DepsType(BaseModel):
37
+ pass
38
+
39
+ class OutputType(BaseModel):
40
+ pass
41
+
42
+ @abstractmethod
43
+ def get_agent_config(self) -> AgentConfig: # pragma: no cover
44
+ raise NotImplementedError
45
+
46
+ @abstractmethod
47
+ async def process(self, task_context: TaskContext) -> TaskContext: # pragma: no cover
48
+ raise NotImplementedError
@@ -0,0 +1,26 @@
1
+ """Streaming agent node (vendored stub).
2
+
3
+ DevFlow Engine does not ship with LLM providers; streaming is optional.
4
+ This stub allows workflows to type-check and run without extra dependencies.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from abc import ABC, abstractmethod
10
+ from typing import Any, AsyncIterator, Dict
11
+
12
+ from .agent import AgentNode
13
+ from ..task import TaskContext
14
+
15
+
16
+ class AgentStreamingNode(AgentNode, ABC):
17
+ """A node that can yield intermediate events."""
18
+
19
+ @abstractmethod
20
+ async def process(self, task_context: TaskContext) -> TaskContext: # pragma: no cover
21
+ raise NotImplementedError
22
+
23
+ async def stream(self, task_context: TaskContext) -> AsyncIterator[Dict[str, Any]]:
24
+ # Default behaviour: run `process` and yield one terminal event.
25
+ result = await self.process(task_context)
26
+ yield {"type": "result", "data": result.model_dump()}
@@ -0,0 +1,89 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Type, Optional
3
+
4
+ from pydantic import BaseModel
5
+
6
+ from ..task import TaskContext
7
+
8
+ """
9
+ Base Node Module
10
+
11
+ This module defines the foundational Node class that all workflow nodes inherit from.
12
+ It implements the Chain of Responsibility pattern, allowing nodes to process tasks
13
+ sequentially and pass results to the next node in the chain.
14
+ """
15
+
16
+
17
+ class Node(ABC):
18
+ class OutputType(BaseModel):
19
+ """
20
+ OutputType class for representing structured outputs for Nodes.
21
+ """
22
+
23
+ pass
24
+
25
+ def __init__(self, task_context: TaskContext = None):
26
+ """
27
+ The constructor is used to initialize the class with a provided TaskContext
28
+ instance or without any context.
29
+
30
+ Parameters:
31
+ task_context (TaskContext, optional): Context associated with the task.
32
+ Defaults to None.
33
+ """
34
+ self.task_context = task_context
35
+
36
+ def save_output(self, output: BaseModel):
37
+ """
38
+ Saves the output of a task node into the task context, associating it with the
39
+ node's name for future reference.
40
+
41
+ Args:
42
+ output (BaseModel): The model instance representing the result of the task
43
+ to be stored in the task_context.
44
+ """
45
+ self.task_context.nodes[self.node_name] = output
46
+
47
+ def get_output(self, node_class: Type["Node"]) -> Optional[OutputType]:
48
+ """
49
+ Retrieves the output associated with a specific node class from the task context.
50
+
51
+ Parameters:
52
+ node_class: Type[Node]
53
+ The class of the node whose output is to be retrieved.
54
+
55
+ Returns:
56
+ Optional[OutputType]
57
+ The output associated with the specified node class if it exists, otherwise None.
58
+ """
59
+ return self.task_context.nodes.get(node_class.__name__, None)
60
+
61
+ @property
62
+ def node_name(self) -> str:
63
+ """Gets the name of the node.
64
+
65
+ Returns:
66
+ String name derived from the class name
67
+ """
68
+ return self.__class__.__name__
69
+
70
+ @abstractmethod
71
+ async def process(self, task_context: TaskContext) -> TaskContext:
72
+ """Processes the task context in the responsibility chain.
73
+
74
+ This method implements the Chain of Responsibility pattern's handle
75
+ method. Each node in the workflow processes the task and passes it
76
+ to the next node through the workflow orchestrator.
77
+
78
+ Args:
79
+ task_context: The shared context object passed through the workflow
80
+
81
+ Returns:
82
+ Updated TaskContext with this node's processing results
83
+
84
+ Note:
85
+ Implementations should:
86
+ 1. Process the task according to their specific responsibility
87
+ 2. Store results using the save_output method
88
+ """
89
+ pass
@@ -0,0 +1,30 @@
1
+ import asyncio
2
+ from abc import ABC, abstractmethod
3
+
4
+ from .base import Node
5
+ from ..schema import NodeConfig
6
+ from ..task import TaskContext
7
+
8
+
9
+ class ConcurrentNode(Node, ABC):
10
+ """
11
+ Base class for nodes that execute other nodes concurrently using asyncio.
12
+
13
+ This class provides a method to execute a list of nodes concurrently on a single thread,
14
+ using asyncio.gather. This ensures that I/O-bound operations can proceed in parallel
15
+ without blocking the main thread or event loop.
16
+
17
+ Subclasses must implement the `process` method to define the specific logic of the concurrent node.
18
+ """
19
+
20
+ async def execute_nodes_concurrently(self, task_context: TaskContext):
21
+ node_config: NodeConfig = task_context.metadata["nodes"][self.__class__]
22
+ coroutines = [
23
+ node(task_context).process(task_context)
24
+ for node in node_config.concurrent_nodes
25
+ ]
26
+ return await asyncio.gather(*coroutines)
27
+
28
+ @abstractmethod
29
+ async def process(self, task_context: TaskContext) -> TaskContext:
30
+ pass