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,201 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import subprocess
6
+ from datetime import UTC, datetime
7
+ from typing import Any
8
+ from urllib.request import Request, urlopen
9
+
10
+
11
+ def _keychain_get(service: str, account: str) -> str | None:
12
+ try:
13
+ proc = subprocess.run(
14
+ ["security", "find-generic-password", "-s", service, "-a", account, "-w"],
15
+ capture_output=True,
16
+ text=True,
17
+ check=False,
18
+ timeout=10,
19
+ )
20
+ except Exception:
21
+ return None
22
+ if proc.returncode != 0:
23
+ return None
24
+ value = proc.stdout.strip()
25
+ return value or None
26
+
27
+
28
+ def _resolve_supabase_rest_config() -> tuple[str, str] | None:
29
+ if os.environ.get("PYTEST_CURRENT_TEST"):
30
+ return None
31
+ url = (
32
+ os.environ.get("DEVFLOW_SUPABASE_URL")
33
+ or os.environ.get("SUPABASE_URL")
34
+ or _keychain_get("Supabase URL", "Clarity")
35
+ )
36
+ key = (
37
+ os.environ.get("DEVFLOW_SUPABASE_SERVICE_KEY")
38
+ or os.environ.get("SUPABASE_SERVICE_ROLE_KEY")
39
+ or os.environ.get("SUPABASE_SERVICE_KEY")
40
+ or _keychain_get("Supabase Service Key", "Clarity")
41
+ )
42
+ if not url or not key:
43
+ return None
44
+ return url.rstrip("/"), key
45
+
46
+
47
+ def _postgrest_request(*, method: str, url: str, key: str, body: Any | None = None, prefer: str | None = None) -> Any:
48
+ payload = None if body is None else json.dumps(body).encode("utf-8")
49
+ req = Request(url, data=payload, method=method)
50
+ req.add_header("apikey", key)
51
+ req.add_header("Authorization", f"Bearer {key}")
52
+ if body is not None:
53
+ req.add_header("Content-Type", "application/json")
54
+ if prefer:
55
+ req.add_header("Prefer", prefer)
56
+ with urlopen(req, timeout=30) as resp:
57
+ raw = resp.read().decode("utf-8")
58
+ return json.loads(raw) if raw else None
59
+
60
+
61
+ def _is_uuid_like(value: str | None) -> bool:
62
+ if not value:
63
+ return False
64
+ import re
65
+
66
+ pattern = r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"
67
+ return bool(re.fullmatch(pattern, value.strip()))
68
+
69
+
70
+ def _resolve_dfs_project_id(*, url: str, key: str, project_id: str, display_path: str | None) -> str:
71
+ value = str(project_id or '').strip()
72
+ if _is_uuid_like(value):
73
+ return value
74
+ display_value = str(display_path or '').strip()
75
+ idea_id = None
76
+ if display_value.startswith('idea:'):
77
+ candidate = display_value.split(':', 1)[1].strip()
78
+ if candidate.startswith('idea_'):
79
+ idea_id = candidate
80
+ elif display_value.startswith('story:'):
81
+ candidate = display_value.split(':', 1)[1].strip()
82
+ if candidate.startswith('STORY:idea:'):
83
+ parts = candidate.split(':')
84
+ if len(parts) >= 3 and parts[2].startswith('idea_'):
85
+ idea_id = parts[2]
86
+ if not idea_id:
87
+ return value
88
+ try:
89
+ lookup_url = f"{url}/rest/v1/devflow_project_ideas?select=project_id&idea_id=eq.{idea_id}&limit=1"
90
+ rows = _postgrest_request(method='GET', url=lookup_url, key=key)
91
+ except Exception:
92
+ return value
93
+ if isinstance(rows, list) and rows:
94
+ resolved = str((rows[0] or {}).get('project_id') or '').strip()
95
+ if resolved:
96
+ return resolved
97
+ return value
98
+
99
+
100
+ def publish_devflow_state(
101
+ *,
102
+ project_id: str,
103
+ run_id: str | None,
104
+ current_state: str,
105
+ current_status: str,
106
+ run_summary: str,
107
+ error_message: str | None = None,
108
+ display: str = "project",
109
+ display_path: str | None = None,
110
+ ) -> None:
111
+ config = _resolve_supabase_rest_config()
112
+ if config is None:
113
+ return
114
+ url, key = config
115
+ resolved_project_id = _resolve_dfs_project_id(url=url, key=key, project_id=project_id, display_path=display_path)
116
+ row = {
117
+ "project_id": resolved_project_id,
118
+ "run_id": run_id,
119
+ "current_state": current_state,
120
+ "current_status": current_status,
121
+ "error_code": None,
122
+ "error_message": error_message,
123
+ "display": display,
124
+ "display_path": display_path,
125
+ "run_summary": run_summary,
126
+ "updated_at": datetime.now(UTC).isoformat(),
127
+ }
128
+ try:
129
+ _postgrest_request(
130
+ method="POST",
131
+ url=f"{url}/rest/v1/devflow_state?on_conflict=project_id",
132
+ key=key,
133
+ body=row,
134
+ prefer="resolution=merge-duplicates",
135
+ )
136
+ except Exception:
137
+ return
138
+
139
+
140
+ def fetch_story_statuses_from_supabase(*, story_ids: list[str]) -> dict[str, str]:
141
+ """Return Supabase story statuses keyed by story_id for the requested story ids."""
142
+ config = _resolve_supabase_rest_config()
143
+ if config is None:
144
+ return {}
145
+ normalized = [str(story_id or "").strip() for story_id in story_ids]
146
+ wanted = sorted({story_id for story_id in normalized if story_id})
147
+ if not wanted:
148
+ return {}
149
+
150
+ url, key = config
151
+ rows_by_story_id: dict[str, str] = {}
152
+ try:
153
+ from urllib.parse import quote
154
+
155
+ batch_size = 100
156
+ for offset in range(0, len(wanted), batch_size):
157
+ batch = wanted[offset : offset + batch_size]
158
+ encoded_values = ",".join(quote(f'"{story_id}"', safe="") for story_id in batch)
159
+ rows = _postgrest_request(
160
+ method="GET",
161
+ url=(
162
+ f"{url}/rest/v1/devflow_idea_stories?select=story_id,status"
163
+ f"&story_id=in.({encoded_values})"
164
+ ),
165
+ key=key,
166
+ )
167
+ if not isinstance(rows, list):
168
+ continue
169
+ for row in rows:
170
+ if not isinstance(row, dict):
171
+ continue
172
+ story_id = str(row.get("story_id") or "").strip()
173
+ status = str(row.get("status") or "").strip()
174
+ if story_id:
175
+ rows_by_story_id[story_id] = status
176
+ except Exception:
177
+ return {}
178
+ return rows_by_story_id
179
+
180
+
181
+ def update_story_status_in_supabase(*, story_id: str, status: str) -> None:
182
+ """Mirror story implementation status to Supabase devflow_idea_stories."""
183
+ config = _resolve_supabase_rest_config()
184
+ if config is None:
185
+ return
186
+ url, key = config
187
+ try:
188
+ from urllib.parse import quote
189
+
190
+ row = {
191
+ "status": status,
192
+ "updated_at": datetime.now(UTC).isoformat(),
193
+ }
194
+ _postgrest_request(
195
+ method="PATCH",
196
+ url=f"{url}/rest/v1/devflow_idea_stories?story_id=eq.{quote(story_id)}",
197
+ key=key,
198
+ body=row,
199
+ )
200
+ except Exception:
201
+ return # non-fatal — local state is source of truth
@@ -0,0 +1,9 @@
1
+ """Isolated Devin 2.0 agent-first prompt helpers and PI-backed execution seam."""
2
+
3
+ from .pi_runner import (
4
+ Devin2PiRunnerError,
5
+ Devin2PiRunResult,
6
+ run_devin2_pi_agent,
7
+ )
8
+
9
+ __all__ = ["Devin2PiRunResult", "Devin2PiRunnerError", "run_devin2_pi_agent"]
@@ -0,0 +1,120 @@
1
+ from __future__ import annotations
2
+
3
+ from importlib.resources import files
4
+ from pathlib import Path
5
+ from typing import Any, Literal
6
+
7
+ from pydantic import BaseModel
8
+
9
+ _REPO_ROOT = Path(__file__).resolve().parents[3]
10
+ _DEVIN2_PROMPT_PATH = _REPO_ROOT / "docs" / "prompts" / "devin2-agent-prompt.md"
11
+ _PROJECT_JOURNAL_RELATIVE_DIR = ".devflow/journal"
12
+
13
+
14
+ class Devin2AgentPromptPayload(BaseModel):
15
+ agent_name: str
16
+ route_arm: Literal["ideation", "insight", "iterate", "neither"]
17
+ prompt_path: str
18
+ prompt_markdown: str
19
+ project_journal: dict[str, Any]
20
+ separation_contract: dict[str, Any]
21
+
22
+
23
+ def devin2_agent_prompt_path() -> Path:
24
+ if _DEVIN2_PROMPT_PATH.exists():
25
+ return _DEVIN2_PROMPT_PATH
26
+ return Path(str(files("devflow_engine").joinpath("docs", "prompts", "devin2-agent-prompt.md")))
27
+
28
+
29
+ def load_devin2_agent_prompt() -> str:
30
+ return devin2_agent_prompt_path().read_text(encoding="utf-8").strip()
31
+
32
+
33
+ def build_devin2_agent_prompt_payload(
34
+ *,
35
+ repo_root: Path,
36
+ route_arm: Literal["ideation", "insight", "iterate"],
37
+ ) -> dict[str, Any]:
38
+ journal_root = repo_root / _PROJECT_JOURNAL_RELATIVE_DIR
39
+ return Devin2AgentPromptPayload(
40
+ agent_name="Devin 2.0",
41
+ route_arm=route_arm,
42
+ prompt_path=str(devin2_agent_prompt_path()),
43
+ prompt_markdown=load_devin2_agent_prompt(),
44
+ project_journal={
45
+ "relative_dir": _PROJECT_JOURNAL_RELATIVE_DIR,
46
+ "absolute_dir": str(journal_root),
47
+ "entry_pattern": ".devflow/journal/YYYY-MM-DD.md",
48
+ "write_rule": (
49
+ "Persist material assumptions, decisions, and continuity notes here "
50
+ "when they matter across turns or later execution."
51
+ ),
52
+ },
53
+ separation_contract={
54
+ "baseline_path": "docs/prompts/devin-agent-prompt.md",
55
+ "v2_path": "docs/prompts/devin2-agent-prompt.md",
56
+ "prompt_role": "Defines Devin 2.0's conversational stance and ownership split.",
57
+ "operational_guidance_role": (
58
+ "Supplies turn-specific workflow rules, route constraints, and execution caveats."
59
+ ),
60
+ "runtime_contract_role": "Defines the JSON output schema and return contract only.",
61
+ },
62
+ ).model_dump()
63
+
64
+
65
+ def build_inline_agent_prompt_payload(
66
+ *,
67
+ prompt_text: str,
68
+ route_arm: Literal["ideation", "insight", "iterate", "neither"],
69
+ ) -> dict[str, Any]:
70
+ return {
71
+ "agent_name": "inline_response_agent",
72
+ "route_arm": route_arm,
73
+ "prompt_text": str(prompt_text).strip(),
74
+ }
75
+
76
+
77
+ def build_response_prompt_payload(
78
+ *,
79
+ stage_name: str,
80
+ context_payload: dict[str, Any],
81
+ operational_guidance: list[str],
82
+ output_model: type[BaseModel],
83
+ agent_prompt: dict[str, Any],
84
+ ) -> dict[str, Any]:
85
+ return {
86
+ "task": stage_name,
87
+ "agent_prompt": agent_prompt,
88
+ "operational_guidance": list(operational_guidance),
89
+ "context": context_payload,
90
+ "runtime_contract": {
91
+ "output_schema": output_model.model_json_schema(),
92
+ "return_format": "json_only",
93
+ },
94
+ }
95
+
96
+
97
+ def build_artifact_reference_response_prompt_payload(
98
+ *,
99
+ stage_name: str,
100
+ operational_guidance: list[str],
101
+ output_model: type[BaseModel],
102
+ agent_prompt: dict[str, Any],
103
+ artifact_path: Path,
104
+ ) -> dict[str, Any]:
105
+ return {
106
+ "task": stage_name,
107
+ "agent_prompt": agent_prompt,
108
+ "operational_guidance": list(operational_guidance)
109
+ + [
110
+ "The full context was persisted to disk because the prompt exceeded size limits.",
111
+ f"Read context from artifact_path={artifact_path}",
112
+ ],
113
+ "context_artifact": {
114
+ "artifact_path": str(artifact_path),
115
+ },
116
+ "runtime_contract": {
117
+ "output_schema": output_model.model_json_schema(),
118
+ "return_format": "json_only",
119
+ },
120
+ }
@@ -0,0 +1,204 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+ from typing import Any, Literal
8
+
9
+ from pydantic import BaseModel, ValidationError
10
+
11
+ from ..idea.traditional_stories import _extract_json
12
+ from ..llm.invoke import (
13
+ LlmInvocationRequest,
14
+ LlmInvocationResult,
15
+ invoke_llm,
16
+ resolve_api_tier_request_overrides,
17
+ resolve_canonical_light_tier_model,
18
+ )
19
+ from .agent_definition import (
20
+ build_artifact_reference_response_prompt_payload,
21
+ build_devin2_agent_prompt_payload,
22
+ build_response_prompt_payload,
23
+ )
24
+
25
+ _PI_PROVIDER = "pi"
26
+ _PI_BASE_CMD = "pi"
27
+ _PI_DELIVERY = "argument"
28
+ _PI_DEVFLOW_TOOLS_EXT = str(Path.home() / ".pi/agent/extensions/devflow-tools.ts")
29
+ _PI_BASE_CMD_WITH_DEVFLOW_TOOLS = f"pi -e {_PI_DEVFLOW_TOOLS_EXT}"
30
+ _MAX_PROMPT_CHARS = 120_000
31
+ _PI_MODEL_ALIASES: dict[tuple[str | None, str], str] = {
32
+ ("minimax", "MiniMax Token 2.7"): "MiniMax-M2.7",
33
+ }
34
+
35
+
36
+ @dataclass(frozen=True)
37
+ class Devin2PiRunResult:
38
+ response_model: BaseModel
39
+ prompt_payload: dict[str, Any]
40
+ invocation: LlmInvocationResult
41
+
42
+
43
+ class Devin2PiRunnerError(RuntimeError):
44
+ """Raised when the Devin 2.0 PI harness fails or returns invalid output."""
45
+
46
+
47
+ def _persist_context_artifact(*, repo_root: Path, stage_name: str, context_payload: dict[str, Any]) -> Path:
48
+ artifact_root = repo_root / ".devflow" / "agent_debug" / "devin2_context_artifacts"
49
+ artifact_root.mkdir(parents=True, exist_ok=True)
50
+ safe_stage_name = re.sub(r"[^A-Za-z0-9_.-]+", "_", stage_name).strip("._") or "stage"
51
+ artifact_path = artifact_root / f"{safe_stage_name}.json"
52
+ artifact_path.write_text(json.dumps(context_payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
53
+ return artifact_path
54
+
55
+
56
+ def _extract_response_json(stdout: str) -> Any:
57
+ extracted = _extract_json(stdout)
58
+ if extracted is None:
59
+ raise Devin2PiRunnerError("Devin 2.0 PI harness returned no JSON payload.")
60
+ try:
61
+ return json.loads(extracted)
62
+ except json.JSONDecodeError as exc:
63
+ raise Devin2PiRunnerError(f"Devin 2.0 PI harness returned invalid JSON: {exc}") from exc
64
+
65
+
66
+ def _build_devin2_prompt_payload(
67
+ *,
68
+ repo_root: Path,
69
+ route_arm: Literal["ideation", "insight", "iterate"],
70
+ stage_name: str,
71
+ context_payload: dict[str, Any],
72
+ operational_guidance: list[str],
73
+ output_model: type[BaseModel],
74
+ ) -> dict[str, Any]:
75
+ agent_prompt = build_devin2_agent_prompt_payload(repo_root=repo_root, route_arm=route_arm)
76
+ prompt_payload = build_response_prompt_payload(
77
+ stage_name=stage_name,
78
+ context_payload=context_payload,
79
+ operational_guidance=operational_guidance,
80
+ output_model=output_model,
81
+ agent_prompt=agent_prompt,
82
+ )
83
+ serialized = json.dumps(prompt_payload, indent=2, sort_keys=True)
84
+ if len(serialized) <= _MAX_PROMPT_CHARS:
85
+ return prompt_payload
86
+
87
+ artifact_path = _persist_context_artifact(
88
+ repo_root=repo_root,
89
+ stage_name=stage_name,
90
+ context_payload=context_payload,
91
+ )
92
+ return build_artifact_reference_response_prompt_payload(
93
+ stage_name=stage_name,
94
+ operational_guidance=operational_guidance,
95
+ output_model=output_model,
96
+ agent_prompt=agent_prompt,
97
+ artifact_path=artifact_path,
98
+ )
99
+
100
+
101
+
102
+
103
+ def _normalize_pi_model_name(*, provider: str | None, model: str | None) -> str | None:
104
+ normalized = str(model or "").strip()
105
+ if not normalized:
106
+ return None
107
+ return _PI_MODEL_ALIASES.get((provider, normalized), normalized)
108
+
109
+
110
+ def _resolve_pi_model_spec() -> str | None:
111
+ provider: str | None = None
112
+ model: str | None = None
113
+ try:
114
+ overrides = resolve_api_tier_request_overrides(tier="light")
115
+ provider = str(overrides.get("provider") or "").strip().lower() or None
116
+ model = str(overrides.get("model") or "").strip() or None
117
+ except Exception:
118
+ model = resolve_canonical_light_tier_model()
119
+ normalized_model = _normalize_pi_model_name(provider=provider, model=model)
120
+ if provider and normalized_model and "/" not in normalized_model:
121
+ return f"{provider}/{normalized_model}"
122
+ return normalized_model
123
+
124
+ def run_devin2_pi_agent(
125
+ *,
126
+ repo_root: Path,
127
+ stage_name: str,
128
+ route_arm: Literal["ideation", "insight", "iterate"],
129
+ context_payload: dict[str, Any],
130
+ operational_guidance: list[str],
131
+ output_model: type[BaseModel],
132
+ timeout_seconds: int | None = None,
133
+ ) -> Devin2PiRunResult:
134
+ """Run the Devin 2.0 prompt payload through the PI CLI harness.
135
+
136
+ This seam hard-pins the execution transport to the PI binary itself while
137
+ explicitly passing the canonical light-tier model from the user-managed
138
+ Supabase row ``devflow_settings.settings.tiers.light`` (falling back only
139
+ to the synced global DevFlow view when Supabase is unavailable). That keeps
140
+ Devin 2.0 PI runs off repo-local / legacy local config resolution.
141
+ """
142
+ repo_root.mkdir(parents=True, exist_ok=True)
143
+ prompt_payload = _build_devin2_prompt_payload(
144
+ repo_root=repo_root,
145
+ route_arm=route_arm,
146
+ stage_name=stage_name,
147
+ context_payload=context_payload,
148
+ operational_guidance=operational_guidance,
149
+ output_model=output_model,
150
+ )
151
+ prompt_text = json.dumps(prompt_payload, indent=2, sort_keys=True)
152
+ canonical_light_model = _resolve_pi_model_spec()
153
+ # Load the Devin-specific extension, which now applies its own explicit
154
+ # allowlist via PI's setActiveTools(...) seam.
155
+ pi_base_cmd = _PI_BASE_CMD_WITH_DEVFLOW_TOOLS
156
+
157
+ _MAX_PI_ATTEMPTS = 3
158
+ last_error: Exception | None = None
159
+ invocation = None
160
+ for _attempt in range(_MAX_PI_ATTEMPTS):
161
+ invocation = invoke_llm(
162
+ LlmInvocationRequest(
163
+ purpose=stage_name,
164
+ strength="light",
165
+ repo_root=repo_root,
166
+ prompt=prompt_text,
167
+ prompt_payload=prompt_payload,
168
+ delivery_model="final_only",
169
+ interaction_model="agentic",
170
+ response_contract="json_only",
171
+ timeout_seconds=timeout_seconds,
172
+ base_cmd=pi_base_cmd,
173
+ delivery=_PI_DELIVERY,
174
+ provider=_PI_PROVIDER,
175
+ model=canonical_light_model,
176
+ )
177
+ )
178
+ if not invocation.ok:
179
+ last_error = Devin2PiRunnerError(invocation.stderr or invocation.stdout or "Devin 2.0 PI harness failed.")
180
+ continue
181
+ # Check for parseable JSON in the response
182
+ parsed_json = invocation.parsed_json
183
+ if parsed_json is None:
184
+ try:
185
+ parsed_json = _extract_response_json(invocation.stdout)
186
+ except Devin2PiRunnerError as exc:
187
+ last_error = exc
188
+ continue
189
+ break
190
+ else:
191
+ if last_error is not None:
192
+ raise last_error
193
+ raise Devin2PiRunnerError("Devin 2.0 PI harness failed after all retry attempts.")
194
+ assert invocation is not None
195
+ try:
196
+ response_model = output_model.model_validate(parsed_json)
197
+ except ValidationError as exc:
198
+ raise Devin2PiRunnerError(f"Devin 2.0 PI harness returned schema-invalid JSON: {exc}") from exc
199
+
200
+ return Devin2PiRunResult(
201
+ response_model=response_model,
202
+ prompt_payload=prompt_payload,
203
+ invocation=invocation,
204
+ )
@@ -0,0 +1,69 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ from devin.dag_two_arm import run_devin_two_arm_dag as run_devin_chat_dag
7
+ from .stores.execution_store import ExecutionStore
8
+
9
+ DEVIN_QUEUE_NAME = "assistant.devin"
10
+ DEVIN_CHAT_TASK_KIND = "devin.chat"
11
+
12
+
13
+ def enqueue_devin_chat_task(
14
+ *,
15
+ store: ExecutionStore,
16
+ project_id: str | None,
17
+ idea_id: str,
18
+ repo_root: Path,
19
+ text: str | None,
20
+ source_path: Path | None,
21
+ max_stories: int,
22
+ planes: list[str],
23
+ source_run_id: str | None = None,
24
+ response_mode_label: str | None = None,
25
+ ) -> dict[str, Any]:
26
+ idempotency_key = f"{idea_id}:{','.join(sorted(planes))}:{max_stories}:{text or ''}:{str(source_path or '')}:{response_mode_label or ''}"
27
+ return store.enqueue_task(
28
+ project_id=project_id,
29
+ queue_name=DEVIN_QUEUE_NAME,
30
+ task_kind=DEVIN_CHAT_TASK_KIND,
31
+ idempotency_key=idempotency_key,
32
+ source_run_id=source_run_id,
33
+ input_payload={
34
+ "idea_id": idea_id,
35
+ "text": text,
36
+ "source_path": str(source_path) if source_path else None,
37
+ "max_stories": max_stories,
38
+ "planes": planes,
39
+ "response_mode_label": response_mode_label,
40
+ },
41
+ context={"client": "devin", "workflow": "devin_chat"},
42
+ )
43
+
44
+
45
+ def handle_devin_chat_task(store: ExecutionStore, repo_root: Path, task: dict[str, Any]) -> dict[str, Any]:
46
+ payload = dict(task.get("input") or {})
47
+ task_id = str(task["task_id"])
48
+ store.record_task_step(task_id=task_id, step_name="devin_chat.run", status="started", payload=payload)
49
+ result = run_devin_chat_dag(
50
+ repo_root=repo_root,
51
+ store=store,
52
+ idea_id=str(payload.get("idea_id") or ""),
53
+ text=payload.get("text"),
54
+ source_path=Path(str(payload["source_path"])) if payload.get("source_path") else None,
55
+ max_stories=int(payload.get("max_stories") or 3),
56
+ planes=[str(item) for item in (payload.get("planes") or ["api"])],
57
+ response_mode_label=(None if payload.get("response_mode_label") is None else str(payload.get("response_mode_label"))),
58
+ )
59
+ response = {
60
+ "idea_id": str(payload.get("idea_id") or ""),
61
+ "run_id": result.run_id,
62
+ "exit_code": result.exit_code,
63
+ "pipeline_dir": str(result.pipeline_dir),
64
+ "message": result.message,
65
+ "outcome": result.outcome,
66
+ }
67
+ store.emit_task_message(task_id=task_id, message_kind="result", stream="assistant", payload=response)
68
+ store.record_task_step(task_id=task_id, step_name="devin_chat.run", status="finished", payload=response)
69
+ return response
@@ -0,0 +1,42 @@
1
+ # Prompt anti-patterns
2
+
3
+ This is the canonical home for prompt anti-pattern notes in `devflow_engine`.
4
+
5
+ Scope split:
6
+ - prompt design guidance and anti-patterns live under `docs/prompts/`
7
+ - runtime skill artifacts live under `src/devflow_engine/skills/...` as described in `docs/devflow-skill-registry-spec.md`
8
+
9
+ Keep this list short and concrete. Add an entry when it changes prompt quality or agent correctness in a recurring way.
10
+
11
+ ## Context smuggling
12
+
13
+ **Definition:** leaking author-side orchestration, internal jargon, or non-local workflow context into a node/agent prompt that does not actually have that local context.
14
+
15
+ Common examples:
16
+ - telling an agent to "use the output from Node 1" or "continue what Node 2 already established" when that material is not present in the prompt payload
17
+ - referencing GenAI DAG internals, route names, or pipeline stage assumptions that are meaningful to the prompt author but not to the receiving agent
18
+ - writing prompts that depend on hidden repo/process knowledge instead of the explicitly provided task inputs
19
+
20
+ Why it is harmful:
21
+ - creates fake coherence: the prompt sounds specific, but the agent cannot actually ground the references
22
+ - encourages hallucinated continuity and invented dependencies
23
+ - makes prompts brittle when nodes are reused, reordered, or evaluated in isolation
24
+ - hides the real contract the node needs in order to work correctly
25
+
26
+ Preferred correction:
27
+ - restate the local task in terms of the inputs the node actually receives
28
+ - pass required upstream artifacts explicitly instead of naming invisible pipeline steps
29
+ - replace internal orchestration references with bounded, self-contained instructions
30
+ - if an agent truly needs workflow metadata, include that metadata as explicit input, not implied context
31
+
32
+ ## Hidden approval boundary
33
+
34
+ Stub: prompts that imply permission to proceed across a human approval gate without explicitly stating whether approval has been given.
35
+
36
+ ## State inflation
37
+
38
+ Stub: prompts that collapse distinct states such as drafted, persisted, queued, started, and completed into one vague notion of "in progress".
39
+
40
+ ## Tool-shaped prompt leakage
41
+
42
+ Stub: prompts that bake in harness/tool mechanics too early, instead of expressing the task and only layering tool-specific constraints where they are actually required.