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,69 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Optional, Type
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
from ..task import TaskContext
|
|
7
|
+
from .base import Node
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
Router Module
|
|
11
|
+
|
|
12
|
+
This module implements the routing logic for workflow nodes.
|
|
13
|
+
It provides base classes for implementing routing decisions between nodes
|
|
14
|
+
in a processing workflow.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class BaseRouter(Node):
|
|
19
|
+
"""Base router class for implementing node routing logic.
|
|
20
|
+
|
|
21
|
+
The BaseRouter class provides core routing functionality for directing
|
|
22
|
+
task flow between workflow nodes. It processes routing rules in sequence
|
|
23
|
+
and falls back to a default node if no rules match.
|
|
24
|
+
|
|
25
|
+
Attributes:
|
|
26
|
+
routes: List of RouterNode instances defining routing rules
|
|
27
|
+
fallback: Optional default node to route to if no rules match
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
async def process(self, task_context: TaskContext) -> TaskContext:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
def route(self, task_context: TaskContext) -> Node:
|
|
34
|
+
"""Determines the next node based on routing rules.
|
|
35
|
+
|
|
36
|
+
Evaluates each routing rule in sequence and returns the first
|
|
37
|
+
matching node. Falls back to the default node if no rules match.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
task_context: Current task execution context
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
The next node to execute, or None if no route is found
|
|
44
|
+
"""
|
|
45
|
+
for route_node in self.routes:
|
|
46
|
+
route_node.task_context = task_context
|
|
47
|
+
next_node = route_node.determine_next_node(task_context)
|
|
48
|
+
if next_node:
|
|
49
|
+
return next_node
|
|
50
|
+
return self.fallback if self.fallback else None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class RouterNode(ABC):
|
|
54
|
+
def __init__(self, task_context: TaskContext = None):
|
|
55
|
+
self.task_context = task_context
|
|
56
|
+
|
|
57
|
+
@abstractmethod
|
|
58
|
+
def determine_next_node(self, task_context: TaskContext) -> Optional[Node]:
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
@property
|
|
62
|
+
def node_name(self):
|
|
63
|
+
return self.__class__.__name__
|
|
64
|
+
|
|
65
|
+
def save_output(self, output: BaseModel):
|
|
66
|
+
self.task_context.nodes[self.node_name] = output
|
|
67
|
+
|
|
68
|
+
def get_output(self, node_class: Type[Node]):
|
|
69
|
+
return self.task_context.nodes.get(node_class.__name__, None)
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from typing import List, Type, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field
|
|
4
|
+
|
|
5
|
+
from .nodes.base import Node
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Workflow Schema Module
|
|
9
|
+
|
|
10
|
+
This module defines the schema classes used to configure workflow structures.
|
|
11
|
+
It provides a type-safe way to define node connections and workflow layouts
|
|
12
|
+
using Pydantic models.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class NodeConfig(BaseModel):
|
|
17
|
+
"""Configuration model for workflow nodes.
|
|
18
|
+
|
|
19
|
+
NodeConfig defines the structure and behavior of a single node within
|
|
20
|
+
a workflow, including its connections to other nodes and routing properties.
|
|
21
|
+
|
|
22
|
+
Attributes:
|
|
23
|
+
node: The Node class to be instantiated
|
|
24
|
+
connections: List of Node classes this node can connect to
|
|
25
|
+
is_router: Flag indicating if this node performs routing logic
|
|
26
|
+
description: Optional description of the node's purpose
|
|
27
|
+
concurrent_nodes: Optional list of Node classes that can run concurrently
|
|
28
|
+
|
|
29
|
+
Example:
|
|
30
|
+
config = NodeConfig(
|
|
31
|
+
node=AnalyzeNode,
|
|
32
|
+
connections=[RouterNode],
|
|
33
|
+
is_router=False,
|
|
34
|
+
description="Analyzes incoming requests"
|
|
35
|
+
concurrent_nodes=[FilterContentGuardrailNode, FilterSQLInjectionGuardrailNode]
|
|
36
|
+
)
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
node: Type[Node]
|
|
40
|
+
connections: List[Type[Node]] = Field(default_factory=list)
|
|
41
|
+
is_router: bool = False
|
|
42
|
+
description: Optional[str] = None
|
|
43
|
+
concurrent_nodes: Optional[List[Type[Node]]] = Field(default_factory=list)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class WorkflowSchema(BaseModel):
|
|
47
|
+
"""Schema definition for a complete workflow.
|
|
48
|
+
|
|
49
|
+
WorkflowSchema defines the overall structure of a processing workflow,
|
|
50
|
+
including its entry point and all constituent nodes.
|
|
51
|
+
|
|
52
|
+
Attributes:
|
|
53
|
+
description: Optional description of the workflow's purpose
|
|
54
|
+
event_schema: Pydantic model for validating incoming events
|
|
55
|
+
start: The entry point Node class for the workflow
|
|
56
|
+
nodes: List of NodeConfig objects defining the workflow structure
|
|
57
|
+
|
|
58
|
+
Example:
|
|
59
|
+
schema = WorkflowSchema(
|
|
60
|
+
description="Support ticket processing workflow",
|
|
61
|
+
start=AnalyzeNode,
|
|
62
|
+
nodes=[
|
|
63
|
+
NodeConfig(node=AnalyzeNode, connections=[RouterNode]),
|
|
64
|
+
NodeConfig(node=RouterNode, connections=[ResponseNode, EscalateNode]),
|
|
65
|
+
]
|
|
66
|
+
)
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
description: Optional[str] = None
|
|
70
|
+
event_schema: Type[BaseModel]
|
|
71
|
+
start: Type[Node]
|
|
72
|
+
nodes: List[NodeConfig]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from typing import Any, Dict
|
|
2
|
+
from pydantic import BaseModel, Field
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
Task Context Module
|
|
6
|
+
This module defines the context object that gets passed between workflow nodes.
|
|
7
|
+
It maintains the state and metadata throughout workflow execution.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TaskContext(BaseModel):
|
|
12
|
+
"""Context container for workflow task execution.
|
|
13
|
+
TaskContext maintains the state and results of a workflow's execution,
|
|
14
|
+
tracking the original event, intermediate node results, and additional
|
|
15
|
+
metadata throughout the processing flow.
|
|
16
|
+
Attributes:
|
|
17
|
+
event: The original event that triggered the workflow
|
|
18
|
+
nodes: Dictionary storing results and state from each node's execution
|
|
19
|
+
metadata: Dictionary storing workflow-level metadata and configuration
|
|
20
|
+
should_stop: Boolean flag indicating whether the workflow should stop execution
|
|
21
|
+
Example:
|
|
22
|
+
context = TaskContext(
|
|
23
|
+
event=incoming_event,
|
|
24
|
+
nodes={"AnalyzeNode": {"score": 0.95}},
|
|
25
|
+
metadata={"priority": "high"}
|
|
26
|
+
)
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
event: Any
|
|
30
|
+
nodes: Dict[str, Any] = Field(
|
|
31
|
+
default_factory=dict,
|
|
32
|
+
description="Stores results and state from each node's execution",
|
|
33
|
+
)
|
|
34
|
+
metadata: Dict[str, Any] = Field(
|
|
35
|
+
default_factory=dict,
|
|
36
|
+
description="Stores workflow-level metadata and configuration",
|
|
37
|
+
)
|
|
38
|
+
should_stop: bool = Field(
|
|
39
|
+
default=False,
|
|
40
|
+
description="Flag indicating whether the workflow should stop execution",
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
def update_node(self, node_name: str, **kwargs):
|
|
44
|
+
self.nodes[node_name] = {**self.nodes.get(node_name, {}), **kwargs}
|
|
45
|
+
|
|
46
|
+
def stop_workflow(self) -> None:
|
|
47
|
+
"""Stops the current workflow execution by setting the stop flag.
|
|
48
|
+
|
|
49
|
+
This method can be called from any node to halt the workflow processing.
|
|
50
|
+
Once called, the workflow will stop after the current node completes.
|
|
51
|
+
"""
|
|
52
|
+
self.should_stop = True
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from collections import deque
|
|
2
|
+
from typing import Set, Type
|
|
3
|
+
|
|
4
|
+
from .nodes.base import Node
|
|
5
|
+
from .schema import WorkflowSchema
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
Workflow Validator Module
|
|
9
|
+
|
|
10
|
+
This module provides validation logic for workflow schemas.
|
|
11
|
+
It ensures that workflows form valid directed acyclic graphs (DAGs)
|
|
12
|
+
and that routing configurations are correct.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class WorkflowValidator:
|
|
17
|
+
"""Validator for ensuring workflow schema correctness.
|
|
18
|
+
|
|
19
|
+
The WorkflowValidator performs comprehensive validation of workflow schemas,
|
|
20
|
+
checking for cycles, unreachable nodes, and proper routing configurations.
|
|
21
|
+
It ensures that the workflow forms a valid directed acyclic graph (DAG)
|
|
22
|
+
and that routing nodes are properly configured.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
workflow_schema: The WorkflowSchema to validate
|
|
26
|
+
|
|
27
|
+
Example:
|
|
28
|
+
validator = WorkflowValidator(workflow_schema)
|
|
29
|
+
validator.validate() # Raises ValueError if validation fails
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, workflow_schema: WorkflowSchema):
|
|
33
|
+
"""Initializes the validator with a workflow schema.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
workflow_schema: The WorkflowSchema to validate
|
|
37
|
+
"""
|
|
38
|
+
self.workflow_schema = workflow_schema
|
|
39
|
+
|
|
40
|
+
def validate(self):
|
|
41
|
+
"""Validates all aspects of the workflow schema.
|
|
42
|
+
|
|
43
|
+
Performs comprehensive validation including DAG structure
|
|
44
|
+
and routing configuration checks.
|
|
45
|
+
|
|
46
|
+
Raises:
|
|
47
|
+
ValueError: If any validation check fails
|
|
48
|
+
"""
|
|
49
|
+
self._validate_dag()
|
|
50
|
+
self._validate_connections()
|
|
51
|
+
|
|
52
|
+
def _validate_dag(self):
|
|
53
|
+
"""Validates that the workflow schema forms a proper DAG.
|
|
54
|
+
|
|
55
|
+
Checks for cycles and ensures all nodes are reachable
|
|
56
|
+
from the start node.
|
|
57
|
+
|
|
58
|
+
Raises:
|
|
59
|
+
ValueError: If the workflow contains cycles or unreachable nodes
|
|
60
|
+
"""
|
|
61
|
+
if self._has_cycle():
|
|
62
|
+
raise ValueError("Workflow schema contains a cycle")
|
|
63
|
+
|
|
64
|
+
reachable_nodes = self._get_reachable_nodes()
|
|
65
|
+
all_nodes = set(nc.node for nc in self.workflow_schema.nodes)
|
|
66
|
+
unreachable_nodes = all_nodes - reachable_nodes
|
|
67
|
+
if unreachable_nodes:
|
|
68
|
+
raise ValueError(
|
|
69
|
+
f"The following nodes are unreachable: {unreachable_nodes}"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
def _has_cycle(self) -> bool:
|
|
73
|
+
"""Detects cycles in the workflow graph using DFS.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
bool: True if a cycle is detected, False otherwise
|
|
77
|
+
"""
|
|
78
|
+
visited = set()
|
|
79
|
+
rec_stack = set()
|
|
80
|
+
|
|
81
|
+
def dfs(node: Type[Node]) -> bool:
|
|
82
|
+
visited.add(node)
|
|
83
|
+
rec_stack.add(node)
|
|
84
|
+
|
|
85
|
+
node_config = next(
|
|
86
|
+
(nc for nc in self.workflow_schema.nodes if nc.node == node), None
|
|
87
|
+
)
|
|
88
|
+
if node_config:
|
|
89
|
+
for neighbor in node_config.connections:
|
|
90
|
+
if neighbor not in visited:
|
|
91
|
+
if dfs(neighbor):
|
|
92
|
+
return True
|
|
93
|
+
elif neighbor in rec_stack:
|
|
94
|
+
return True
|
|
95
|
+
|
|
96
|
+
rec_stack.remove(node)
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
for node_config in self.workflow_schema.nodes:
|
|
100
|
+
if node_config.node not in visited:
|
|
101
|
+
if dfs(node_config.node):
|
|
102
|
+
return True
|
|
103
|
+
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
def _get_reachable_nodes(self) -> Set[Type[Node]]:
|
|
107
|
+
"""Identifies all nodes reachable from the start node using BFS.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Set[Type[Node]]: Set of all reachable node classes
|
|
111
|
+
"""
|
|
112
|
+
reachable = set()
|
|
113
|
+
queue = deque([self.workflow_schema.start])
|
|
114
|
+
|
|
115
|
+
while queue:
|
|
116
|
+
node = queue.popleft()
|
|
117
|
+
if node not in reachable:
|
|
118
|
+
reachable.add(node)
|
|
119
|
+
node_config = next(
|
|
120
|
+
(nc for nc in self.workflow_schema.nodes if nc.node == node), None
|
|
121
|
+
)
|
|
122
|
+
if node_config:
|
|
123
|
+
queue.extend(node_config.connections)
|
|
124
|
+
|
|
125
|
+
return reachable
|
|
126
|
+
|
|
127
|
+
def _validate_connections(self):
|
|
128
|
+
"""Validates node connection configurations.
|
|
129
|
+
|
|
130
|
+
Ensures that only nodes marked as routers have multiple connections.
|
|
131
|
+
|
|
132
|
+
Raises:
|
|
133
|
+
ValueError: If a non-router node has multiple connections
|
|
134
|
+
"""
|
|
135
|
+
for node_config in self.workflow_schema.nodes:
|
|
136
|
+
if len(node_config.connections) > 1 and not node_config.is_router:
|
|
137
|
+
raise ValueError(
|
|
138
|
+
f"Node {node_config.node.__name__} has multiple connections but is not marked as a router."
|
|
139
|
+
)
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""Workflow orchestration (vendored from Datalumina GenAI).
|
|
2
|
+
|
|
3
|
+
This is a *minimal* subset used by DevFlow Engine.
|
|
4
|
+
|
|
5
|
+
Notable changes vs upstream:
|
|
6
|
+
- Removed Langfuse tracing + dotenv side-effects (keep engine self-contained)
|
|
7
|
+
- Normalized imports to be package-relative
|
|
8
|
+
|
|
9
|
+
The engine supports async execution and simple router nodes.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import logging
|
|
16
|
+
from abc import ABC
|
|
17
|
+
from contextlib import contextmanager, nullcontext
|
|
18
|
+
from typing import Any, AsyncIterator, ClassVar, Dict, Optional, Type
|
|
19
|
+
|
|
20
|
+
from .nodes.agent_streaming_node import AgentStreamingNode
|
|
21
|
+
from .nodes.base import Node
|
|
22
|
+
from .nodes.router import BaseRouter
|
|
23
|
+
from .schema import NodeConfig, WorkflowSchema
|
|
24
|
+
from .task import TaskContext
|
|
25
|
+
from .validate import WorkflowValidator
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class NoOpSpan:
|
|
29
|
+
"""No-op span for compatibility with upstream tracing hooks."""
|
|
30
|
+
|
|
31
|
+
def update(self, **_kwargs: Any) -> None: # noqa: D401
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class Workflow(ABC):
|
|
36
|
+
"""Abstract base class for defining a processing workflow."""
|
|
37
|
+
|
|
38
|
+
workflow_schema: ClassVar[WorkflowSchema]
|
|
39
|
+
|
|
40
|
+
def __init__(self) -> None:
|
|
41
|
+
self.validator = WorkflowValidator(self.workflow_schema)
|
|
42
|
+
self.validator.validate()
|
|
43
|
+
self.nodes: Dict[Type[Node], NodeConfig] = self._initialize_nodes()
|
|
44
|
+
|
|
45
|
+
def _observation_context(self, _name: str):
|
|
46
|
+
# Tracing intentionally disabled in vendored version.
|
|
47
|
+
return nullcontext(NoOpSpan())
|
|
48
|
+
|
|
49
|
+
@contextmanager
|
|
50
|
+
def node_context(self, node_name: str):
|
|
51
|
+
logging.info("Starting node: %s", node_name)
|
|
52
|
+
try:
|
|
53
|
+
yield
|
|
54
|
+
except Exception:
|
|
55
|
+
logging.exception("Error in node %s", node_name)
|
|
56
|
+
raise
|
|
57
|
+
finally:
|
|
58
|
+
logging.info("Finished node: %s", node_name)
|
|
59
|
+
|
|
60
|
+
def _initialize_nodes(self) -> Dict[Type[Node], NodeConfig]:
|
|
61
|
+
nodes: Dict[Type[Node], NodeConfig] = {}
|
|
62
|
+
for node_config in self.workflow_schema.nodes:
|
|
63
|
+
nodes[node_config.node] = node_config
|
|
64
|
+
for connected_node in node_config.connections:
|
|
65
|
+
if connected_node not in nodes:
|
|
66
|
+
nodes[connected_node] = NodeConfig(node=connected_node)
|
|
67
|
+
return nodes
|
|
68
|
+
|
|
69
|
+
def run(self, event: Any) -> TaskContext:
|
|
70
|
+
return asyncio.run(self._run(event))
|
|
71
|
+
|
|
72
|
+
async def run_async(self, event: Any) -> TaskContext:
|
|
73
|
+
return await self._run(event)
|
|
74
|
+
|
|
75
|
+
async def run_stream_async(self, event: Any) -> AsyncIterator[Dict[str, Any]]:
|
|
76
|
+
task_context = TaskContext(event=event)
|
|
77
|
+
|
|
78
|
+
with self._observation_context(self.__class__.__name__) as workflow_span:
|
|
79
|
+
try:
|
|
80
|
+
logging.info("Starting workflow streaming execution")
|
|
81
|
+
|
|
82
|
+
task_context.event = self.workflow_schema.event_schema(**event)
|
|
83
|
+
workflow_span.update(input=event)
|
|
84
|
+
|
|
85
|
+
task_context.metadata["nodes"] = self.nodes
|
|
86
|
+
current_node_class: Optional[Type[Node]] = self.workflow_schema.start
|
|
87
|
+
|
|
88
|
+
while current_node_class:
|
|
89
|
+
if task_context.should_stop:
|
|
90
|
+
break
|
|
91
|
+
|
|
92
|
+
current_node = self.nodes[current_node_class].node
|
|
93
|
+
node_name = current_node_class.__name__
|
|
94
|
+
|
|
95
|
+
with self._observation_context(node_name) as node_span:
|
|
96
|
+
node_span.update(
|
|
97
|
+
input=task_context.model_dump(
|
|
98
|
+
exclude={"metadata": {"nodes"}}
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
with self.node_context(node_name):
|
|
103
|
+
if not issubclass(current_node, BaseRouter):
|
|
104
|
+
node_instance = current_node(task_context=task_context)
|
|
105
|
+
|
|
106
|
+
if isinstance(node_instance, AgentStreamingNode):
|
|
107
|
+
async for stream_event in node_instance.process(
|
|
108
|
+
task_context
|
|
109
|
+
):
|
|
110
|
+
yield stream_event
|
|
111
|
+
else:
|
|
112
|
+
task_context = await node_instance.process(
|
|
113
|
+
task_context
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
node_span.update(
|
|
117
|
+
output=task_context.model_dump(
|
|
118
|
+
include={"nodes": {node_name}}
|
|
119
|
+
)
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
current_node_class = await self._get_next_node_class(
|
|
123
|
+
current_node_class, task_context
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
workflow_span.update(
|
|
127
|
+
output=task_context.model_dump(exclude={"metadata": {"nodes"}})
|
|
128
|
+
)
|
|
129
|
+
task_context.metadata.pop("nodes", None)
|
|
130
|
+
|
|
131
|
+
except Exception as e:
|
|
132
|
+
logging.exception("Error in workflow execution")
|
|
133
|
+
workflow_span.update(level="ERROR", status_message=str(e))
|
|
134
|
+
yield {"type": "error", "error": str(e)}
|
|
135
|
+
raise
|
|
136
|
+
|
|
137
|
+
async def _run(self, event: Any) -> TaskContext:
|
|
138
|
+
task_context = TaskContext(event=event)
|
|
139
|
+
|
|
140
|
+
with self._observation_context(self.__class__.__name__) as workflow_span:
|
|
141
|
+
task_context.event = self.workflow_schema.event_schema(**event)
|
|
142
|
+
workflow_span.update(input=event)
|
|
143
|
+
|
|
144
|
+
task_context.metadata["nodes"] = self.nodes
|
|
145
|
+
current_node_class: Optional[Type[Node]] = self.workflow_schema.start
|
|
146
|
+
|
|
147
|
+
while current_node_class:
|
|
148
|
+
if task_context.should_stop:
|
|
149
|
+
break
|
|
150
|
+
|
|
151
|
+
current_node = self.nodes[current_node_class].node
|
|
152
|
+
node_name = current_node_class.__name__
|
|
153
|
+
|
|
154
|
+
with self._observation_context(node_name) as node_span:
|
|
155
|
+
node_span.update(
|
|
156
|
+
input=task_context.model_dump(exclude={"metadata": {"nodes"}})
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
with self.node_context(node_name):
|
|
160
|
+
if not issubclass(current_node, BaseRouter):
|
|
161
|
+
task_context = await current_node(
|
|
162
|
+
task_context=task_context
|
|
163
|
+
).process(task_context)
|
|
164
|
+
|
|
165
|
+
node_span.update(
|
|
166
|
+
output=task_context.model_dump(include={"nodes": {node_name}})
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
current_node_class = await self._get_next_node_class(
|
|
170
|
+
current_node_class, task_context
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
workflow_span.update(
|
|
174
|
+
output=task_context.model_dump(exclude={"metadata": {"nodes"}})
|
|
175
|
+
)
|
|
176
|
+
task_context.metadata.pop("nodes", None)
|
|
177
|
+
return task_context
|
|
178
|
+
|
|
179
|
+
async def _get_next_node_class(
|
|
180
|
+
self, current_node_class: Type[Node], task_context: TaskContext
|
|
181
|
+
) -> Optional[Type[Node]]:
|
|
182
|
+
node_config = next(
|
|
183
|
+
(nc for nc in self.workflow_schema.nodes if nc.node == current_node_class),
|
|
184
|
+
None,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if not node_config or not node_config.connections:
|
|
188
|
+
return None
|
|
189
|
+
|
|
190
|
+
if node_config.is_router:
|
|
191
|
+
router: BaseRouter = self.nodes[current_node_class].node() # type: ignore[assignment]
|
|
192
|
+
return await self._handle_router(router, task_context)
|
|
193
|
+
|
|
194
|
+
return node_config.connections[0]
|
|
195
|
+
|
|
196
|
+
async def _handle_router(
|
|
197
|
+
self, router: BaseRouter, task_context: TaskContext
|
|
198
|
+
) -> Optional[Type[Node]]:
|
|
199
|
+
next_node = router.route(task_context)
|
|
200
|
+
return next_node.__class__ if next_node else None
|