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.
- devflow_engine/__init__.py +3 -0
- devflow_engine/agentic_prompts.py +100 -0
- devflow_engine/agentic_runtime.py +398 -0
- devflow_engine/api_key_flow_harness.py +539 -0
- devflow_engine/api_keys.py +357 -0
- devflow_engine/bootstrap/__init__.py +2 -0
- devflow_engine/bootstrap/provision_from_template.py +84 -0
- devflow_engine/cli/__init__.py +0 -0
- devflow_engine/cli/app.py +7270 -0
- devflow_engine/core/__init__.py +0 -0
- devflow_engine/core/config.py +86 -0
- devflow_engine/core/logging.py +29 -0
- devflow_engine/core/paths.py +45 -0
- devflow_engine/core/toml_kv.py +33 -0
- devflow_engine/devflow_event_worker.py +1292 -0
- devflow_engine/devflow_state.py +201 -0
- devflow_engine/devin2/__init__.py +9 -0
- devflow_engine/devin2/agent_definition.py +120 -0
- devflow_engine/devin2/pi_runner.py +204 -0
- devflow_engine/devin_orchestration.py +69 -0
- devflow_engine/docs/prompts/anti-patterns.md +42 -0
- devflow_engine/docs/prompts/devin-agent-prompt.md +55 -0
- devflow_engine/docs/prompts/devin2-agent-prompt.md +81 -0
- devflow_engine/docs/prompts/examples/devin-vapi-clone-reference-exchange.json +85 -0
- devflow_engine/doctor/__init__.py +2 -0
- devflow_engine/doctor/triage.py +140 -0
- devflow_engine/error/__init__.py +0 -0
- devflow_engine/error/remediation.py +21 -0
- devflow_engine/errors/error_solver_dag.py +522 -0
- devflow_engine/errors/runtime_observability.py +67 -0
- devflow_engine/idea/__init__.py +4 -0
- devflow_engine/idea/actors.py +481 -0
- devflow_engine/idea/agentic.py +465 -0
- devflow_engine/idea/analyze.py +93 -0
- devflow_engine/idea/devin_chat_dag.py +1 -0
- devflow_engine/idea/diff.py +99 -0
- devflow_engine/idea/drafts.py +446 -0
- devflow_engine/idea/idea_creation_dag.py +643 -0
- devflow_engine/idea/ideation_enrichment.py +355 -0
- devflow_engine/idea/ideation_enrichment_worker.py +19 -0
- devflow_engine/idea/paths.py +28 -0
- devflow_engine/idea/promote.py +53 -0
- devflow_engine/idea/redaction.py +27 -0
- devflow_engine/idea/repo_tools.py +1277 -0
- devflow_engine/idea/response_mode.py +30 -0
- devflow_engine/idea/story_pipeline.py +1585 -0
- devflow_engine/idea/sufficiency.py +376 -0
- devflow_engine/idea/traditional_stories.py +1257 -0
- devflow_engine/implementation/__init__.py +0 -0
- devflow_engine/implementation/alembic_preflight.py +700 -0
- devflow_engine/implementation/dag.py +8450 -0
- devflow_engine/implementation/green_gate.py +93 -0
- devflow_engine/implementation/prompts.py +108 -0
- devflow_engine/implementation/test_runtime.py +623 -0
- devflow_engine/integration/__init__.py +19 -0
- devflow_engine/integration/agentic.py +66 -0
- devflow_engine/integration/dag.py +3539 -0
- devflow_engine/integration/prompts.py +114 -0
- devflow_engine/integration/supabase_schema.sql +31 -0
- devflow_engine/integration/supabase_sync.py +177 -0
- devflow_engine/llm/__init__.py +1 -0
- devflow_engine/llm/cli_one_shot.py +84 -0
- devflow_engine/llm/cli_stream.py +371 -0
- devflow_engine/llm/execution_context.py +26 -0
- devflow_engine/llm/invoke.py +1322 -0
- devflow_engine/llm/provider_api.py +304 -0
- devflow_engine/llm/repo_knowledge.py +588 -0
- devflow_engine/llm_primitives.py +315 -0
- devflow_engine/orchestration.py +62 -0
- devflow_engine/planning/__init__.py +0 -0
- devflow_engine/planning/analyze_repo.py +92 -0
- devflow_engine/planning/render_drafts.py +133 -0
- devflow_engine/playground/__init__.py +0 -0
- devflow_engine/playground/hooks.py +26 -0
- devflow_engine/playwright_workflow/__init__.py +5 -0
- devflow_engine/playwright_workflow/dag.py +1317 -0
- devflow_engine/process/__init__.py +5 -0
- devflow_engine/process/dag.py +59 -0
- devflow_engine/project_registration/__init__.py +3 -0
- devflow_engine/project_registration/dag.py +1581 -0
- devflow_engine/project_registry.py +109 -0
- devflow_engine/prompts/devin/generic/prompt.md +6 -0
- devflow_engine/prompts/devin/ideation/prompt.md +263 -0
- devflow_engine/prompts/devin/ideation/scenarios.md +5 -0
- devflow_engine/prompts/devin/ideation_loop/prompt.md +6 -0
- devflow_engine/prompts/devin/insight/prompt.md +11 -0
- devflow_engine/prompts/devin/insight/scenarios.md +5 -0
- devflow_engine/prompts/devin/intake/prompt.md +15 -0
- devflow_engine/prompts/devin/iterate/prompt.md +12 -0
- devflow_engine/prompts/devin/shared/eval_doctrine.md +9 -0
- devflow_engine/prompts/devin/shared/principles.md +246 -0
- devflow_engine/prompts/devin_eval/assessment/prompt.md +18 -0
- devflow_engine/prompts/idea/api_ideation_agent/prompt.md +8 -0
- devflow_engine/prompts/idea/api_insight_agent/prompt.md +8 -0
- devflow_engine/prompts/idea/response_doctrine/prompt.md +18 -0
- devflow_engine/prompts/implementation/dependency_assessment/prompt.md +12 -0
- devflow_engine/prompts/implementation/green/green/prompt.md +11 -0
- devflow_engine/prompts/implementation/green/node_config/prompt.md +3 -0
- devflow_engine/prompts/implementation/green_review/outcome_review/prompt.md +5 -0
- devflow_engine/prompts/implementation/green_review/prior_run_review/prompt.md +5 -0
- devflow_engine/prompts/implementation/red/prompt.md +27 -0
- devflow_engine/prompts/implementation/redreview/prompt.md +23 -0
- devflow_engine/prompts/implementation/redreview_repair/prompt.md +16 -0
- devflow_engine/prompts/implementation/setupdoc/prompt.md +10 -0
- devflow_engine/prompts/implementation/story_planning/prompt.md +13 -0
- devflow_engine/prompts/implementation/test_design/prompt.md +27 -0
- devflow_engine/prompts/integration/README.md +185 -0
- devflow_engine/prompts/integration/green/example.md +67 -0
- devflow_engine/prompts/integration/green/green/prompt.md +10 -0
- devflow_engine/prompts/integration/green/node_config/prompt.md +42 -0
- devflow_engine/prompts/integration/green/past_prompts/20260417T212300/green/prompt.md +15 -0
- devflow_engine/prompts/integration/green/past_prompts/20260417T212300/node_config/prompt.md +42 -0
- devflow_engine/prompts/integration/green_enrich/example.md +79 -0
- devflow_engine/prompts/integration/green_enrich/green_enrich/prompt.md +9 -0
- devflow_engine/prompts/integration/green_enrich/node_config/prompt.md +41 -0
- devflow_engine/prompts/integration/green_enrich/past_prompts/20260417T212300/green_enrich/prompt.md +14 -0
- devflow_engine/prompts/integration/green_enrich/past_prompts/20260417T212300/node_config/prompt.md +41 -0
- devflow_engine/prompts/integration/red/code_repair/prompt.md +12 -0
- devflow_engine/prompts/integration/red/example.md +152 -0
- devflow_engine/prompts/integration/red/node_config/prompt.md +86 -0
- devflow_engine/prompts/integration/red/past_prompts/20260417T212300/code_repair/prompt.md +19 -0
- devflow_engine/prompts/integration/red/past_prompts/20260417T212300/node_config/prompt.md +84 -0
- devflow_engine/prompts/integration/red/past_prompts/20260417T212300/red/prompt.md +16 -0
- devflow_engine/prompts/integration/red/past_prompts/20260417T212300/red_repair/prompt.md +15 -0
- devflow_engine/prompts/integration/red/past_prompts/20260417T215032/code_repair/prompt.md +10 -0
- devflow_engine/prompts/integration/red/past_prompts/20260417T215032/node_config/prompt.md +84 -0
- devflow_engine/prompts/integration/red/past_prompts/20260417T215032/red_repair/prompt.md +11 -0
- devflow_engine/prompts/integration/red/red/prompt.md +11 -0
- devflow_engine/prompts/integration/red/red_repair/prompt.md +12 -0
- devflow_engine/prompts/integration/red_review/example.md +71 -0
- devflow_engine/prompts/integration/red_review/node_config/prompt.md +41 -0
- devflow_engine/prompts/integration/red_review/past_prompts/20260417T212300/node_config/prompt.md +41 -0
- devflow_engine/prompts/integration/red_review/past_prompts/20260417T212300/red_review/prompt.md +15 -0
- devflow_engine/prompts/integration/red_review/red_review/prompt.md +9 -0
- devflow_engine/prompts/integration/resolve/example.md +111 -0
- devflow_engine/prompts/integration/resolve/node_config/prompt.md +64 -0
- devflow_engine/prompts/integration/resolve/past_prompts/20260417T212300/node_config/prompt.md +64 -0
- devflow_engine/prompts/integration/resolve/past_prompts/20260417T212300/resolve_implicated_users/prompt.md +15 -0
- devflow_engine/prompts/integration/resolve/past_prompts/20260417T212300/resolve_side_effects/prompt.md +15 -0
- devflow_engine/prompts/integration/resolve/resolve_implicated_users/prompt.md +10 -0
- devflow_engine/prompts/integration/resolve/resolve_side_effects/prompt.md +10 -0
- devflow_engine/prompts/integration/validate/build_idea_acceptance_coverage/prompt.md +12 -0
- devflow_engine/prompts/integration/validate/code_repair/prompt.md +13 -0
- devflow_engine/prompts/integration/validate/example.md +143 -0
- devflow_engine/prompts/integration/validate/node_config/prompt.md +87 -0
- devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/code_repair/prompt.md +19 -0
- devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/node_config/prompt.md +67 -0
- devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/validate_enrich_gate/prompt.md +17 -0
- devflow_engine/prompts/integration/validate/past_prompts/20260417T212300/validate_repair/prompt.md +16 -0
- devflow_engine/prompts/integration/validate/past_prompts/20260417T215032/code_repair/prompt.md +10 -0
- devflow_engine/prompts/integration/validate/past_prompts/20260417T215032/node_config/prompt.md +67 -0
- devflow_engine/prompts/integration/validate/past_prompts/20260417T215032/validate_repair/prompt.md +9 -0
- devflow_engine/prompts/integration/validate/validate_enrich_gate/prompt.md +10 -0
- devflow_engine/prompts/integration/validate/validate_repair/prompt.md +20 -0
- devflow_engine/prompts/integration/write_workflows/example.md +100 -0
- devflow_engine/prompts/integration/write_workflows/node_config/prompt.md +44 -0
- devflow_engine/prompts/integration/write_workflows/past_prompts/20260417T212300/node_config/prompt.md +44 -0
- devflow_engine/prompts/integration/write_workflows/past_prompts/20260417T212300/write_workflows/prompt.md +17 -0
- devflow_engine/prompts/integration/write_workflows/write_workflows/prompt.md +11 -0
- devflow_engine/prompts/iterate/README.md +7 -0
- devflow_engine/prompts/iterate/coder/prompt.md +11 -0
- devflow_engine/prompts/iterate/framer/prompt.md +11 -0
- devflow_engine/prompts/iterate/iterator/prompt.md +13 -0
- devflow_engine/prompts/iterate/observer/prompt.md +11 -0
- devflow_engine/prompts/recovery/diagnosis/prompt.md +7 -0
- devflow_engine/prompts/recovery/execution/prompt.md +8 -0
- devflow_engine/prompts/recovery/execution_verification/prompt.md +7 -0
- devflow_engine/prompts/recovery/failure_investigation/prompt.md +10 -0
- devflow_engine/prompts/recovery/preflight_health_repo_repair/prompt.md +8 -0
- devflow_engine/prompts/recovery/remediation_execution/prompt.md +11 -0
- devflow_engine/prompts/recovery/root_cause_investigation/prompt.md +12 -0
- devflow_engine/prompts/scope_idea/doctrine/prompt.md +7 -0
- devflow_engine/prompts/source_doc_eval/document/prompt.md +6 -0
- devflow_engine/prompts/source_doc_eval/targeted_mutation/prompt.md +9 -0
- devflow_engine/prompts/source_doc_mutation/domain_entities/prompt.md +6 -0
- devflow_engine/prompts/source_doc_mutation/product_brief/prompt.md +6 -0
- devflow_engine/prompts/source_doc_mutation/project_doc_coherence/prompt.md +7 -0
- devflow_engine/prompts/source_doc_mutation/project_doc_render/prompt.md +9 -0
- devflow_engine/prompts/source_doc_mutation/source_doc_coherence/prompt.md +5 -0
- devflow_engine/prompts/source_doc_mutation/source_doc_enrichment_coherence/prompt.md +6 -0
- devflow_engine/prompts/source_doc_mutation/user_workflows/prompt.md +6 -0
- devflow_engine/prompts/source_scope/doctrine/prompt.md +10 -0
- devflow_engine/prompts/ui_grounding/doctrine/prompt.md +7 -0
- devflow_engine/recovery/__init__.py +3 -0
- devflow_engine/recovery/dag.py +2609 -0
- devflow_engine/recovery/models.py +220 -0
- devflow_engine/refactor.py +93 -0
- devflow_engine/registry/__init__.py +1 -0
- devflow_engine/registry/cards.py +238 -0
- devflow_engine/registry/domain_normalize.py +60 -0
- devflow_engine/registry/effects.py +65 -0
- devflow_engine/registry/enforce_report.py +150 -0
- devflow_engine/registry/module_cards_classify.py +164 -0
- devflow_engine/registry/module_cards_draft.py +184 -0
- devflow_engine/registry/module_cards_gate.py +59 -0
- devflow_engine/registry/packages.py +347 -0
- devflow_engine/registry/pathways.py +323 -0
- devflow_engine/review/__init__.py +11 -0
- devflow_engine/review/dag.py +588 -0
- devflow_engine/review/review_story.py +67 -0
- devflow_engine/scope_idea/__init__.py +3 -0
- devflow_engine/scope_idea/agentic.py +39 -0
- devflow_engine/scope_idea/dag.py +1069 -0
- devflow_engine/scope_idea/models.py +175 -0
- devflow_engine/skills/builtins/devflow/queue_failure_investigation/SKILL.md +112 -0
- devflow_engine/skills/builtins/devflow/queue_idea_to_story/SKILL.md +120 -0
- devflow_engine/skills/builtins/devflow/queue_integration/SKILL.md +105 -0
- devflow_engine/skills/builtins/devflow/queue_recovery/SKILL.md +108 -0
- devflow_engine/skills/builtins/devflow/queue_runtime_core/SKILL.md +155 -0
- devflow_engine/skills/builtins/devflow/queue_story_implementation/SKILL.md +122 -0
- devflow_engine/skills/builtins/devin/idea_to_story_handoff/SKILL.md +120 -0
- devflow_engine/skills/builtins/devin/ideation/SKILL.md +168 -0
- devflow_engine/skills/builtins/devin/ideation/state-and-phrasing-reference.md +18 -0
- devflow_engine/skills/builtins/devin/insight/SKILL.md +22 -0
- devflow_engine/skills/registry.example.yaml +42 -0
- devflow_engine/source_doc_assumptions.py +291 -0
- devflow_engine/source_doc_mutation_dag.py +1606 -0
- devflow_engine/source_doc_mutation_eval.py +417 -0
- devflow_engine/source_doc_mutation_worker.py +25 -0
- devflow_engine/source_docs_schema.py +207 -0
- devflow_engine/source_docs_updater.py +309 -0
- devflow_engine/source_scope/__init__.py +15 -0
- devflow_engine/source_scope/agentic.py +45 -0
- devflow_engine/source_scope/dag.py +1626 -0
- devflow_engine/source_scope/models.py +177 -0
- devflow_engine/stores/__init__.py +0 -0
- devflow_engine/stores/execution_store.py +3534 -0
- devflow_engine/story/__init__.py +0 -0
- devflow_engine/story/contracts.py +160 -0
- devflow_engine/story/discovery.py +47 -0
- devflow_engine/story/evidence.py +118 -0
- devflow_engine/story/hashing.py +27 -0
- devflow_engine/story/implemented_queue_purge.py +148 -0
- devflow_engine/story/indexer.py +105 -0
- devflow_engine/story/io.py +20 -0
- devflow_engine/story/markdown_contracts.py +298 -0
- devflow_engine/story/reconciliation.py +408 -0
- devflow_engine/story/validate_stories.py +149 -0
- devflow_engine/story/validate_tests_story.py +512 -0
- devflow_engine/story/validation.py +133 -0
- devflow_engine/ui_grounding/__init__.py +11 -0
- devflow_engine/ui_grounding/agentic.py +31 -0
- devflow_engine/ui_grounding/dag.py +874 -0
- devflow_engine/ui_grounding/models.py +224 -0
- devflow_engine/ui_grounding/pencil_bridge.py +247 -0
- devflow_engine/vendor/__init__.py +0 -0
- devflow_engine/vendor/datalumina_genai/__init__.py +11 -0
- devflow_engine/vendor/datalumina_genai/core/__init__.py +0 -0
- devflow_engine/vendor/datalumina_genai/core/exceptions.py +9 -0
- devflow_engine/vendor/datalumina_genai/core/nodes/__init__.py +0 -0
- devflow_engine/vendor/datalumina_genai/core/nodes/agent.py +48 -0
- devflow_engine/vendor/datalumina_genai/core/nodes/agent_streaming_node.py +26 -0
- devflow_engine/vendor/datalumina_genai/core/nodes/base.py +89 -0
- devflow_engine/vendor/datalumina_genai/core/nodes/concurrent.py +30 -0
- devflow_engine/vendor/datalumina_genai/core/nodes/router.py +69 -0
- devflow_engine/vendor/datalumina_genai/core/schema.py +72 -0
- devflow_engine/vendor/datalumina_genai/core/task.py +52 -0
- devflow_engine/vendor/datalumina_genai/core/validate.py +139 -0
- devflow_engine/vendor/datalumina_genai/core/workflow.py +200 -0
- devflow_engine/worker.py +1086 -0
- devflow_engine/worker_guard.py +233 -0
- devflow_engine-1.0.0.dist-info/METADATA +235 -0
- devflow_engine-1.0.0.dist-info/RECORD +393 -0
- devflow_engine-1.0.0.dist-info/WHEEL +4 -0
- devflow_engine-1.0.0.dist-info/entry_points.txt +3 -0
- devin/__init__.py +6 -0
- devin/dag.py +58 -0
- devin/dag_two_arm.py +138 -0
- devin/devin_chat_scenario_catalog.json +588 -0
- devin/devin_eval.py +677 -0
- devin/nodes/__init__.py +0 -0
- devin/nodes/ideation/__init__.py +0 -0
- devin/nodes/ideation/node.py +195 -0
- devin/nodes/ideation/playground.py +267 -0
- devin/nodes/ideation/prompt.md +65 -0
- devin/nodes/ideation/scenarios/continue_refinement.py +13 -0
- devin/nodes/ideation/scenarios/continue_refinement_evals.py +18 -0
- devin/nodes/ideation/scenarios/idea_fits_existing_patterns.py +17 -0
- devin/nodes/ideation/scenarios/idea_fits_existing_patterns_evals.py +16 -0
- devin/nodes/ideation/scenarios/large_idea_split.py +4 -0
- devin/nodes/ideation/scenarios/large_idea_split_evals.py +17 -0
- devin/nodes/ideation/scenarios/source_documentation_added.py +4 -0
- devin/nodes/ideation/scenarios/source_documentation_added_evals.py +16 -0
- devin/nodes/ideation/scenarios/user_says_create_it.py +30 -0
- devin/nodes/ideation/scenarios/user_says_create_it_evals.py +23 -0
- devin/nodes/ideation/scenarios/vague_idea.py +16 -0
- devin/nodes/ideation/scenarios/vague_idea_evals.py +47 -0
- devin/nodes/ideation/tools.json +312 -0
- devin/nodes/insight/__init__.py +0 -0
- devin/nodes/insight/node.py +49 -0
- devin/nodes/insight/playground.py +154 -0
- devin/nodes/insight/prompt.md +61 -0
- devin/nodes/insight/scenarios/architecture_pattern_query.py +15 -0
- devin/nodes/insight/scenarios/architecture_pattern_query_evals.py +25 -0
- devin/nodes/insight/scenarios/codebase_exploration.py +15 -0
- devin/nodes/insight/scenarios/codebase_exploration_evals.py +23 -0
- devin/nodes/insight/scenarios/devin_ideation_routing.py +19 -0
- devin/nodes/insight/scenarios/devin_ideation_routing_evals.py +39 -0
- devin/nodes/insight/scenarios/devin_insight_routing.py +20 -0
- devin/nodes/insight/scenarios/devin_insight_routing_evals.py +40 -0
- devin/nodes/insight/scenarios/operational_debugging.py +15 -0
- devin/nodes/insight/scenarios/operational_debugging_evals.py +23 -0
- devin/nodes/insight/scenarios/operational_question.py +9 -0
- devin/nodes/insight/scenarios/operational_question_evals.py +8 -0
- devin/nodes/insight/scenarios/queue_status.py +15 -0
- devin/nodes/insight/scenarios/queue_status_evals.py +23 -0
- devin/nodes/insight/scenarios/source_doc_explanation.py +14 -0
- devin/nodes/insight/scenarios/source_doc_explanation_evals.py +21 -0
- devin/nodes/insight/scenarios/worker_state_check.py +15 -0
- devin/nodes/insight/scenarios/worker_state_check_evals.py +22 -0
- devin/nodes/insight/tools.json +126 -0
- devin/nodes/intake/__init__.py +0 -0
- devin/nodes/intake/node.py +27 -0
- devin/nodes/intake/playground.py +47 -0
- devin/nodes/intake/prompt.md +12 -0
- devin/nodes/intake/scenarios/ideation_routing.py +4 -0
- devin/nodes/intake/scenarios/ideation_routing_evals.py +5 -0
- devin/nodes/intake/scenarios/insight_routing.py +4 -0
- devin/nodes/intake/scenarios/insight_routing_evals.py +5 -0
- devin/nodes/iterate/README.md +44 -0
- devin/nodes/iterate/__init__.py +1 -0
- devin/nodes/iterate/_archived_design_stages/01-objectives-requirements.md +112 -0
- devin/nodes/iterate/_archived_design_stages/02-evals.md +131 -0
- devin/nodes/iterate/_archived_design_stages/03-tools-and-boundaries.md +110 -0
- devin/nodes/iterate/_archived_design_stages/04-harness-and-playground.md +32 -0
- devin/nodes/iterate/_archived_design_stages/05-prompt-deferred.md +11 -0
- devin/nodes/iterate/_archived_design_stages/coder_agent_design/01-objectives-requirements.md +20 -0
- devin/nodes/iterate/_archived_design_stages/coder_agent_design/02-evals.md +8 -0
- devin/nodes/iterate/_archived_design_stages/coder_agent_design/03-tools-and-boundaries.md +14 -0
- devin/nodes/iterate/_archived_design_stages/coder_agent_design/04-harness-and-playground.md +12 -0
- devin/nodes/iterate/_archived_design_stages/framer_agent_design/01-objectives-requirements.md +20 -0
- devin/nodes/iterate/_archived_design_stages/framer_agent_design/02-evals.md +8 -0
- devin/nodes/iterate/_archived_design_stages/framer_agent_design/03-tools-and-boundaries.md +13 -0
- devin/nodes/iterate/_archived_design_stages/framer_agent_design/04-harness-and-playground.md +12 -0
- devin/nodes/iterate/_archived_design_stages/iterator_agent_design/01-objectives-requirements.md +25 -0
- devin/nodes/iterate/_archived_design_stages/iterator_agent_design/02-evals.md +9 -0
- devin/nodes/iterate/_archived_design_stages/iterator_agent_design/03-tools-and-boundaries.md +14 -0
- devin/nodes/iterate/_archived_design_stages/iterator_agent_design/04-harness-and-playground.md +12 -0
- devin/nodes/iterate/_archived_design_stages/observer_agent_design/01-objectives-requirements.md +20 -0
- devin/nodes/iterate/_archived_design_stages/observer_agent_design/02-evals.md +8 -0
- devin/nodes/iterate/_archived_design_stages/observer_agent_design/03-tools-and-boundaries.md +14 -0
- devin/nodes/iterate/_archived_design_stages/observer_agent_design/04-harness-and-playground.md +13 -0
- devin/nodes/iterate/agent-roles.md +89 -0
- devin/nodes/iterate/agents/README.md +10 -0
- devin/nodes/iterate/artifacts.md +504 -0
- devin/nodes/iterate/contract.md +100 -0
- devin/nodes/iterate/eval-plan.md +74 -0
- devin/nodes/iterate/node.py +100 -0
- devin/nodes/iterate/pipeline/README.md +13 -0
- devin/nodes/iterate/playground-contract.md +76 -0
- devin/nodes/iterate/prompt.md +11 -0
- devin/nodes/iterate/scenarios/README.md +38 -0
- devin/nodes/iterate/scenarios/artifact-and-loop-scenarios.md +101 -0
- devin/nodes/iterate/scenarios/coder_artifact_alignment.py +32 -0
- devin/nodes/iterate/scenarios/coder_artifact_alignment_evals.py +45 -0
- devin/nodes/iterate/scenarios/coder_bounded_fix.py +27 -0
- devin/nodes/iterate/scenarios/coder_bounded_fix_evals.py +45 -0
- devin/nodes/iterate/scenarios/devin_iterate_routing.py +21 -0
- devin/nodes/iterate/scenarios/devin_iterate_routing_evals.py +36 -0
- devin/nodes/iterate/scenarios/framer_scope_boundary.py +25 -0
- devin/nodes/iterate/scenarios/framer_scope_boundary_evals.py +57 -0
- devin/nodes/iterate/scenarios/framer_task_framing.py +25 -0
- devin/nodes/iterate/scenarios/framer_task_framing_evals.py +58 -0
- devin/nodes/iterate/scenarios/iterate_error_fix.py +21 -0
- devin/nodes/iterate/scenarios/iterate_error_fix_evals.py +39 -0
- devin/nodes/iterate/scenarios/iterate_quick_change.py +21 -0
- devin/nodes/iterate/scenarios/iterate_quick_change_evals.py +35 -0
- devin/nodes/iterate/scenarios/iterate_to_idea_promotion.py +23 -0
- devin/nodes/iterate/scenarios/iterate_to_idea_promotion_evals.py +53 -0
- devin/nodes/iterate/scenarios/iterate_to_insight_reroute.py +23 -0
- devin/nodes/iterate/scenarios/iterate_to_insight_reroute_evals.py +53 -0
- devin/nodes/iterate/scenarios/observer_evidence_seam.py +28 -0
- devin/nodes/iterate/scenarios/observer_evidence_seam_evals.py +55 -0
- devin/nodes/iterate/scenarios/observer_repro_creation.py +28 -0
- devin/nodes/iterate/scenarios/observer_repro_creation_evals.py +45 -0
- devin/nodes/iterate/scenarios/routing-matrix.md +45 -0
- devin/nodes/shared/__init__.py +0 -0
- devin/nodes/shared/filemaker_expert.md +80 -0
- devin/nodes/shared/filemaker_expert.py +354 -0
- devin/nodes/shared/filemaker_expert_eval/runner.py +176 -0
- devin/nodes/shared/filemaker_expert_eval/scenarios.json +65 -0
- devin/nodes/shared/goldilocks_advisor_eval/runner.py +214 -0
- devin/nodes/shared/goldilocks_advisor_eval/scenarios.json +58 -0
- devin/nodes/shared/helpers.py +156 -0
- devin/nodes/shared/idea_compliance_advisor_eval/runner.py +252 -0
- devin/nodes/shared/idea_compliance_advisor_eval/scenarios.json +75 -0
- devin/nodes/shared/models.py +44 -0
- devin/nodes/shared/post.py +40 -0
- devin/nodes/shared/router.py +107 -0
- devin/nodes/shared/tools.py +191 -0
- devin/shared/devin-chat-rubric.md +237 -0
- devin/shared/devin-chat-scenario-suite.md +90 -0
- 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"]
|
|
File without changes
|
|
File without changes
|
|
@@ -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
|