execweave 0.8.20__tar.gz → 0.8.22__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {execweave-0.8.20 → execweave-0.8.22}/PKG-INFO +4 -1
- {execweave-0.8.20 → execweave-0.8.22}/pyproject.toml +5 -2
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/__init__.py +1 -1
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/_dashboard_shell_base.py +4 -1
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/antigravity_full_fidelity_collaboration_base.py +7 -1
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/cursor_delegation_base.py +5 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/opencode_task_linkage.py +10 -1
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_execution_flow.py +222 -45
- execweave-0.8.22/src/execweave/viewer_execution_flow_provider_normalization.py +105 -0
- execweave-0.8.22/src/execweave/viewer_execution_flow_safety.py +364 -0
- execweave-0.8.20/src/execweave/viewer_execution_flow_safety.py +0 -174
- {execweave-0.8.20 → execweave-0.8.22}/.gitignore +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/LICENSE +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/README.md +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/__main__.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/_conversation_records_core.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/_http_proxy_base.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/_http_proxy_bounded.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/_http_proxy_stage.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/agent_bootstrap.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/agent_topology.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/agent_trace.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/agy_preview_sanitize.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/analysis.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/anthropic.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/anthropic_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/anthropic_full_fidelity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/antigravity_adapter.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/antigravity_adapter_base.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/antigravity_full_fidelity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/antigravity_full_fidelity_base.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/antigravity_hook_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/antigravity_record.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/antigravity_subagent_linkage.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/antigravity_trace_capability.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/auto_specialized.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/backends.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/benchmark.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/claude_adapter.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/claude_child_transcript.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/claude_delegation.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/claude_full_fidelity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/claude_hook_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/claude_hook_contract.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/claude_model_observer.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/claude_record.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_adapter.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_conversation.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_full_fidelity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_hook_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_hook_entry.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_hook_lifecycle.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_message_diagnostics.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_message_transport_diagnostics.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_record.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_rollout_structures.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_rollout_trace.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/codex_rollout_trace_base.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/collector.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/command.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/content_evidence.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/content_store.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_archive.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_message_identity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_preview.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_preview_antigravity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_preview_claude.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_preview_codex.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_preview_common.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_preview_generic.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_preview_lines.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_preview_transcript.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_records.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_records_antigravity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_records_codex.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_records_common.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/conversation_records_ollama.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/correlation.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/cursor_adapter.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/cursor_delegation.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/cursor_full_fidelity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/cursor_hook_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/cursor_hook_contract.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/cursor_record.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/dashboard_shell.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/entry.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/evidence_availability.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/evidence_grade.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/fidelity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/filesystem.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/focus.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/graph.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/graph_ops.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/http_proxy.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/http_proxy_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/inference_gateway.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/inference_gateway_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/inference_gateway_full_fidelity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/inference_identity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/inference_identity_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/integrity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/integrity_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/litellm_callback.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/litellm_callback_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_core.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_view.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_view_extra_style.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_view_markup.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_view_process_layout.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_view_readability.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_view_script_a.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_view_script_b.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_view_script_c.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_view_script_d.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/live_view_style.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/model_runtime.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/model_runtime_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/model_runtime_full_fidelity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/openai_compatible.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/openai_compatible_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/openai_compatible_full_fidelity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/opencode_adapter.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/opencode_event_contract.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/opencode_full_fidelity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/opencode_hook_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/opencode_plugin_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/opencode_record.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/overhead_benchmark.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/provider_capability.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/provider_lifecycle.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/provider_record.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/rule_pack.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/rule_pack_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/runtime_endpoint_availability.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/scalability_benchmark.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/schema.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/scope.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/semantic.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/sink.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/strace_backend.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/stream_assembly.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/theme.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/top.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/top_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/validate.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/vendor/dagre.min.js +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/view_cli.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_agent_panel.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_agent_panel_antigravity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_agent_panel_claude.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_agent_panel_codex.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_agent_panel_cursor.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_agent_panel_default.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_agent_panel_ollama.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_agent_panel_opencode.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_agent_panel_registry.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_content_inspector.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_dashboard_clean.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_dashboard_focus.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_dashboard_hardening.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_dashboard_hardening_v2.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_dashboard_pr70.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_edge_decross.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_external_endpoints.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_gif.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_layout_geometry.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_layout_v2.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_layout_v2_detached.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_limits.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_live_layout.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_projection.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_projection_base.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_projection_bridges.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_semantic_projection.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/viewer_tool_mirror_identity.py +0 -0
- {execweave-0.8.20 → execweave-0.8.22}/src/execweave/workflow.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: execweave
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.22
|
|
4
4
|
Summary: Turn AI-agent runtime behavior into a local interactive execution graph.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Irish-kw/ExecWeave
|
|
6
6
|
Project-URL: Repository, https://github.com/Irish-kw/ExecWeave
|
|
@@ -45,13 +45,16 @@ Provides-Extra: dev
|
|
|
45
45
|
Requires-Dist: pillow>=10.0; extra == 'dev'
|
|
46
46
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
47
47
|
Requires-Dist: pywinpty<4,>=3.0.5; (platform_system == 'Windows') and extra == 'dev'
|
|
48
|
+
Requires-Dist: pyyaml>=6.0; extra == 'dev'
|
|
48
49
|
Requires-Dist: ruff<0.17,>=0.16; extra == 'dev'
|
|
50
|
+
Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'dev'
|
|
49
51
|
Provides-Extra: e2e
|
|
50
52
|
Requires-Dist: pillow>=10.0; extra == 'e2e'
|
|
51
53
|
Requires-Dist: playwright>=1.44; extra == 'e2e'
|
|
52
54
|
Requires-Dist: pywinpty<4,>=3.0.5; (platform_system == 'Windows') and extra == 'e2e'
|
|
53
55
|
Provides-Extra: release
|
|
54
56
|
Requires-Dist: build>=1.2; extra == 'release'
|
|
57
|
+
Requires-Dist: tomli>=2.0; (python_version < '3.11') and extra == 'release'
|
|
55
58
|
Requires-Dist: twine>=6.0; extra == 'release'
|
|
56
59
|
Description-Content-Type: text/markdown
|
|
57
60
|
|
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "execweave"
|
|
7
|
-
# ExecWeave v0.8.
|
|
8
|
-
version = "0.8.
|
|
7
|
+
# ExecWeave v0.8.22 release metadata
|
|
8
|
+
version = "0.8.22"
|
|
9
9
|
description = "Turn AI-agent runtime behavior into a local interactive execution graph."
|
|
10
10
|
readme = "README.md"
|
|
11
11
|
requires-python = ">=3.10"
|
|
@@ -44,13 +44,16 @@ dependencies = [
|
|
|
44
44
|
[project.optional-dependencies]
|
|
45
45
|
dev = [
|
|
46
46
|
"pytest>=8.0",
|
|
47
|
+
"PyYAML>=6.0",
|
|
47
48
|
"pillow>=10.0",
|
|
48
49
|
"ruff>=0.16,<0.17",
|
|
50
|
+
"tomli>=2.0; python_version < '3.11'",
|
|
49
51
|
"pywinpty>=3.0.5,<4; platform_system == 'Windows'",
|
|
50
52
|
]
|
|
51
53
|
release = [
|
|
52
54
|
"build>=1.2",
|
|
53
55
|
"twine>=6.0",
|
|
56
|
+
"tomli>=2.0; python_version < '3.11'",
|
|
54
57
|
]
|
|
55
58
|
# Drives the shipped viewers in a real browser. Kept out of dev so an ordinary
|
|
56
59
|
# development install stays small; CI installs it and requires the checks to run.
|
|
@@ -10,6 +10,7 @@ from .viewer_dashboard_focus import inject_live_dashboard_focus
|
|
|
10
10
|
from .viewer_dashboard_pr70 import inject_pr70_dashboard_repairs
|
|
11
11
|
from .viewer_edge_decross import inject_edge_decross
|
|
12
12
|
from .viewer_execution_flow import inject_execution_flow
|
|
13
|
+
from .viewer_execution_flow_provider_normalization import normalize_provider_execution_flow
|
|
13
14
|
from .viewer_execution_flow_safety import harden_execution_flow_projection
|
|
14
15
|
from .viewer_layout_v2 import inject_layout_v2
|
|
15
16
|
from .viewer_layout_v2_detached import inject_layout_v2_detached_cluster_policy
|
|
@@ -80,7 +81,9 @@ def _build_dashboard_html() -> str:
|
|
|
80
81
|
html = inject_layout_v2(html)
|
|
81
82
|
html = inject_layout_v2_detached_cluster_policy(html)
|
|
82
83
|
html = inject_edge_decross(html)
|
|
83
|
-
html =
|
|
84
|
+
html = normalize_provider_execution_flow(
|
|
85
|
+
harden_execution_flow_projection(inject_execution_flow(html))
|
|
86
|
+
)
|
|
84
87
|
return _align_agent_panel_topology(inject_agent_panel(_guard_compact_live_snapshot(html)))
|
|
85
88
|
|
|
86
89
|
|
{execweave-0.8.20 → execweave-0.8.22}/src/execweave/antigravity_full_fidelity_collaboration_base.py
RENAMED
|
@@ -164,7 +164,13 @@ def _invoke_subagent_events(
|
|
|
164
164
|
relation="REQUESTED_SUBTASK",
|
|
165
165
|
source=parent,
|
|
166
166
|
target=subtask,
|
|
167
|
-
attributes={
|
|
167
|
+
attributes={
|
|
168
|
+
"child_identity_exposed": False,
|
|
169
|
+
# Exact requester -> provider conversation/step/subagent-index spec.
|
|
170
|
+
# Validated ASSIGNED_AGENT_TASK still required before inventing a child.
|
|
171
|
+
"identity_exact": True,
|
|
172
|
+
"identity_method": "antigravity_provider_conversation_step_subagent_index",
|
|
173
|
+
},
|
|
168
174
|
)
|
|
169
175
|
)
|
|
170
176
|
if type_name:
|
|
@@ -134,6 +134,11 @@ def cursor_delegation_events(
|
|
|
134
134
|
subtask = _subtask(payload, child)
|
|
135
135
|
visibility = agent_trace_visibility("cursor")
|
|
136
136
|
exact = {
|
|
137
|
+
# Persist the provider's exact subagent id through GraphEdge.to_dict(), not
|
|
138
|
+
# only in event-specific booleans, so the provider-neutral viewer can make
|
|
139
|
+
# the same fail-closed delegation decision from a materialized graph.
|
|
140
|
+
"identity_exact": True,
|
|
141
|
+
"identity_method": "cursor_provider_subagent_id",
|
|
137
142
|
"provider_subagent_id_exact": True,
|
|
138
143
|
"exact_child_agent_linkage": True,
|
|
139
144
|
**visibility,
|
|
@@ -172,6 +172,15 @@ def opencode_task_session_events(
|
|
|
172
172
|
if isinstance(background, bool):
|
|
173
173
|
attributes["background_requested"] = background
|
|
174
174
|
|
|
175
|
+
# GraphEdge deliberately persists identity_exact / identity_method while the
|
|
176
|
+
# provider-specific booleans above remain event-level evidence. Scope those
|
|
177
|
+
# generic identity claims to the task -> child assignment itself; task content
|
|
178
|
+
# edges should not inherit an unrelated identity method.
|
|
179
|
+
assignment_attributes = {
|
|
180
|
+
**attributes,
|
|
181
|
+
"identity_exact": True,
|
|
182
|
+
"identity_method": "opencode_task_tool_parent_and_child_session_ids",
|
|
183
|
+
}
|
|
175
184
|
child = _agent(child_session, agent_name=agent_name, parent_session_id=parent_session)
|
|
176
185
|
events: list[dict[str, Any]] = [
|
|
177
186
|
{
|
|
@@ -180,7 +189,7 @@ def opencode_task_session_events(
|
|
|
180
189
|
"relation": "ASSIGNED_AGENT_TASK",
|
|
181
190
|
"source": _tool_call(current_session, call_id),
|
|
182
191
|
"target": child,
|
|
183
|
-
"attributes":
|
|
192
|
+
"attributes": assignment_attributes,
|
|
184
193
|
}
|
|
185
194
|
]
|
|
186
195
|
|
|
@@ -43,17 +43,33 @@ EXECUTION_FLOW_SCRIPT = r"""
|
|
|
43
43
|
return ACTION_ALIASES.get(text)||null;
|
|
44
44
|
};
|
|
45
45
|
const moment=item=>{
|
|
46
|
-
if(Number.isInteger(item?.first_sequence))return{kind:0,value:item.first_sequence};
|
|
47
46
|
const attrs=attrsOf(item);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return{
|
|
47
|
+
const sequence=Number.isInteger(item?.first_sequence)?item.first_sequence
|
|
48
|
+
:(Number.isInteger(attrs.first_sequence)?attrs.first_sequence:null);
|
|
49
|
+
const stamp=item?.first_seen||attrs.first_seen||attrs.timestamp||null;
|
|
50
|
+
return{
|
|
51
|
+
sequence:sequence,
|
|
52
|
+
stamp:stamp?String(stamp):null,
|
|
53
|
+
id:String(item?.id||''),
|
|
54
|
+
};
|
|
52
55
|
};
|
|
53
|
-
const
|
|
56
|
+
const momentComparable=(left,right)=>{
|
|
54
57
|
if(!left||!right)return false;
|
|
55
|
-
if(left.
|
|
56
|
-
|
|
58
|
+
if(left.sequence!==null&&right.sequence!==null)return true;
|
|
59
|
+
if(left.stamp&&right.stamp)return true;
|
|
60
|
+
return false;
|
|
61
|
+
};
|
|
62
|
+
const momentLE=(left,right)=>{
|
|
63
|
+
// Only compare when both ends share a sequence or a timestamp. Mixing kinds
|
|
64
|
+
// (or comparing id fallbacks) falsely orders early actions against future switches.
|
|
65
|
+
if(!momentComparable(left,right))return false;
|
|
66
|
+
if(left.sequence!==null&&right.sequence!==null)return left.sequence<=right.sequence;
|
|
67
|
+
return String(left.stamp)<=String(right.stamp);
|
|
68
|
+
};
|
|
69
|
+
const momentEqual=(left,right)=>{
|
|
70
|
+
if(!momentComparable(left,right))return false;
|
|
71
|
+
if(left.sequence!==null&&right.sequence!==null)return left.sequence===right.sequence;
|
|
72
|
+
return String(left.stamp)===String(right.stamp);
|
|
57
73
|
};
|
|
58
74
|
const provider=node=>String(attrsOf(node).provider||'unknown').toLowerCase();
|
|
59
75
|
|
|
@@ -73,30 +89,58 @@ EXECUTION_FLOW_SCRIPT = r"""
|
|
|
73
89
|
incoming.get(edge.target).push(edge);outgoing.get(edge.source).push(edge);
|
|
74
90
|
}
|
|
75
91
|
const aliasToAgent=new Map();
|
|
92
|
+
const rememberAlias=(alias,id)=>{
|
|
93
|
+
if(alias===undefined||alias===null)return;
|
|
94
|
+
const text=String(alias).trim();
|
|
95
|
+
if(!text)return;
|
|
96
|
+
let bucket=aliasToAgent.get(text);
|
|
97
|
+
if(!bucket){bucket=new Set();aliasToAgent.set(text,bucket)}
|
|
98
|
+
bucket.add(id);
|
|
99
|
+
};
|
|
76
100
|
for(const [id,node] of agents){
|
|
77
101
|
const attrs=attrsOf(node);
|
|
78
|
-
|
|
79
|
-
for(const value of
|
|
102
|
+
rememberAlias(id,id);
|
|
103
|
+
for(const value of [node.name,attrs.agent_id,attrs.thread_id,attrs.agent_path,attrs.child_agent_path,attrs.nickname]){
|
|
104
|
+
rememberAlias(value,id);
|
|
105
|
+
}
|
|
80
106
|
}
|
|
81
107
|
const resolveAgent=value=>{
|
|
82
108
|
if(value===undefined||value===null)return null;
|
|
83
109
|
const text=String(value);
|
|
110
|
+
// Exact canonical id always wins over alias lookup.
|
|
84
111
|
if(agents.has(text))return text;
|
|
85
|
-
|
|
112
|
+
const bucket=aliasToAgent.get(text);
|
|
113
|
+
if(!bucket||!bucket.size)return null;
|
|
114
|
+
if(bucket.size===1)return [...bucket][0];
|
|
115
|
+
// Non-unique alias: abstain rather than last-writer-wins.
|
|
116
|
+
return null;
|
|
117
|
+
};
|
|
118
|
+
const uniqueOwner=candidates=>{
|
|
119
|
+
const ids=[...new Set((candidates||[]).filter(Boolean))];
|
|
120
|
+
return ids.length===1?ids[0]:null;
|
|
86
121
|
};
|
|
87
122
|
const ownerForNode=node=>{
|
|
88
123
|
if(!node?.id)return null;
|
|
89
|
-
|
|
124
|
+
const direct=[];
|
|
125
|
+
for(const edge of incoming.get(node.id)||[])if(agents.has(edge.source))direct.push(edge.source);
|
|
126
|
+
const directOwner=uniqueOwner(direct);
|
|
127
|
+
if(directOwner)return directOwner;
|
|
128
|
+
if(direct.length)return null; // ambiguous direct owners
|
|
129
|
+
const viaTurn=[];
|
|
90
130
|
for(const edge of incoming.get(node.id)||[]){
|
|
91
131
|
const parent=rawById.get(edge.source);
|
|
92
132
|
if(parent?.type!=='agent_turn')continue;
|
|
93
|
-
for(const grand of incoming.get(parent.id)||[])if(agents.has(grand.source))
|
|
133
|
+
for(const grand of incoming.get(parent.id)||[])if(agents.has(grand.source))viaTurn.push(grand.source);
|
|
94
134
|
}
|
|
135
|
+
const turnOwner=uniqueOwner(viaTurn);
|
|
136
|
+
if(turnOwner)return turnOwner;
|
|
137
|
+
if(viaTurn.length)return null;
|
|
95
138
|
const attrs=attrsOf(node);
|
|
139
|
+
const attrOwners=[];
|
|
96
140
|
for(const key of ['owner_agent_id','agent_id','source_agent_id','thread_id','agent_path']){
|
|
97
|
-
const found=resolveAgent(attrs[key]);if(found)
|
|
141
|
+
const found=resolveAgent(attrs[key]);if(found)attrOwners.push(found);
|
|
98
142
|
}
|
|
99
|
-
return
|
|
143
|
+
return uniqueOwner(attrOwners);
|
|
100
144
|
};
|
|
101
145
|
const agentForAnchor=id=>{
|
|
102
146
|
if(agents.has(id))return id;
|
|
@@ -106,13 +150,23 @@ EXECUTION_FLOW_SCRIPT = r"""
|
|
|
106
150
|
};
|
|
107
151
|
|
|
108
152
|
const modelNameIndex=new Map();
|
|
153
|
+
const rememberModelAlias=(alias,id)=>{
|
|
154
|
+
if(alias===undefined||alias===null)return;
|
|
155
|
+
const text=String(alias).trim().toLowerCase();
|
|
156
|
+
if(!text)return;
|
|
157
|
+
let bucket=modelNameIndex.get(text);
|
|
158
|
+
if(!bucket){bucket=new Set();modelNameIndex.set(text,bucket)}
|
|
159
|
+
bucket.add(id);
|
|
160
|
+
};
|
|
109
161
|
for(const [id,node] of models){
|
|
110
162
|
const attrs=attrsOf(node);
|
|
111
|
-
|
|
112
|
-
|
|
163
|
+
rememberModelAlias(id,id);
|
|
164
|
+
for(const value of [node.name,attrs.model,attrs.model_name,attrs.native_name]){
|
|
165
|
+
rememberModelAlias(value,id);
|
|
113
166
|
}
|
|
114
167
|
}
|
|
115
168
|
const modelHintFor=node=>{
|
|
169
|
+
if(!node)return null;
|
|
116
170
|
const attrs=attrsOf(node);
|
|
117
171
|
for(const key of ['model','model_name','codex_model','default_model','provider_model']){
|
|
118
172
|
const value=attrs[key];
|
|
@@ -123,8 +177,13 @@ EXECUTION_FLOW_SCRIPT = r"""
|
|
|
123
177
|
const modelIdFromHint=hint=>{
|
|
124
178
|
if(!hint)return null;
|
|
125
179
|
const lower=String(hint).toLowerCase();
|
|
126
|
-
|
|
127
|
-
|
|
180
|
+
// Exact canonical id first.
|
|
181
|
+
if(models.has(hint))return hint;
|
|
182
|
+
if(models.has(lower))return lower;
|
|
183
|
+
const bucket=modelNameIndex.get(lower);
|
|
184
|
+
if(!bucket||!bucket.size)return null;
|
|
185
|
+
if(bucket.size===1)return [...bucket][0];
|
|
186
|
+
// Ambiguous model name across resources: abstain (no suffix fuzzy match).
|
|
128
187
|
return null;
|
|
129
188
|
};
|
|
130
189
|
|
|
@@ -147,20 +206,43 @@ EXECUTION_FLOW_SCRIPT = r"""
|
|
|
147
206
|
if(modelId)addModelEvent(owner,modelId,node);
|
|
148
207
|
}
|
|
149
208
|
for(const list of modelEventsByAgent.values())list.sort((a,b)=>{
|
|
150
|
-
|
|
151
|
-
|
|
209
|
+
// Prefer sequence when both have it; otherwise timestamp; never cross-rank kinds.
|
|
210
|
+
if(a.moment.sequence!==null&&b.moment.sequence!==null){
|
|
211
|
+
return a.moment.sequence-b.moment.sequence;
|
|
212
|
+
}
|
|
213
|
+
if(a.moment.stamp&&b.moment.stamp){
|
|
214
|
+
return String(a.moment.stamp)<String(b.moment.stamp)?-1:String(a.moment.stamp)>String(b.moment.stamp)?1:0;
|
|
215
|
+
}
|
|
216
|
+
if(a.moment.sequence!==null&&b.moment.sequence===null)return -1;
|
|
217
|
+
if(a.moment.sequence===null&&b.moment.sequence!==null)return 1;
|
|
218
|
+
return String(a.moment.id).localeCompare(String(b.moment.id));
|
|
152
219
|
});
|
|
153
220
|
|
|
154
221
|
const resolveModel=(owner,item)=>{
|
|
155
|
-
|
|
222
|
+
// Item hint is only for the owner/actor side. Callers that resolve a child
|
|
223
|
+
// must pass null as item so an actor tool-call model cannot pollute lookup.
|
|
224
|
+
const hinted=item?modelIdFromHint(modelHintFor(item)):null;
|
|
156
225
|
if(hinted)return hinted;
|
|
157
226
|
const list=modelEventsByAgent.get(owner)||[];
|
|
158
227
|
if(!list.length)return null;
|
|
159
|
-
const at=moment(item);
|
|
160
|
-
|
|
161
|
-
for(const event of list)
|
|
162
|
-
|
|
163
|
-
|
|
228
|
+
const at=moment(item||{});
|
|
229
|
+
const eligible=[];
|
|
230
|
+
for(const event of list){
|
|
231
|
+
if(!momentComparable(event.moment,at))continue;
|
|
232
|
+
if(momentLE(event.moment,at))eligible.push(event);
|
|
233
|
+
}
|
|
234
|
+
if(!eligible.length){
|
|
235
|
+
const unique=[...new Set(list.map(event=>event.modelId))];
|
|
236
|
+
return unique.length===1?unique[0]:null;
|
|
237
|
+
}
|
|
238
|
+
// Prefer the latest comparable event; if several tie at the same moment with
|
|
239
|
+
// conflicting models, abstain instead of taking array order.
|
|
240
|
+
let bestMoment=eligible[0].moment;
|
|
241
|
+
for(const event of eligible){
|
|
242
|
+
if(momentLE(bestMoment,event.moment)&&!momentEqual(bestMoment,event.moment))bestMoment=event.moment;
|
|
243
|
+
}
|
|
244
|
+
const tied=eligible.filter(event=>momentEqual(event.moment,bestMoment));
|
|
245
|
+
const unique=[...new Set(tied.map(event=>event.modelId))];
|
|
164
246
|
return unique.length===1?unique[0]:null;
|
|
165
247
|
};
|
|
166
248
|
|
|
@@ -180,18 +262,36 @@ EXECUTION_FLOW_SCRIPT = r"""
|
|
|
180
262
|
if(!kind)continue;
|
|
181
263
|
const sources=(incoming.get(node.id)||[]).filter(edge=>relation(edge)==='STARTED_AGENT_INTERACTION');
|
|
182
264
|
const targets=(outgoing.get(node.id)||[]).filter(edge=>relation(edge)==='TARGETED_BY_AGENT_INTERACTION');
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
if(owner)
|
|
265
|
+
const ownerCandidates=sources.map(edge=>agentForAnchor(edge.source));
|
|
266
|
+
const owner=uniqueOwner(ownerCandidates);
|
|
267
|
+
if(!owner)continue;
|
|
268
|
+
// Unknown endpoints keep the occurrence target-less rather than inventing uniqueness.
|
|
269
|
+
const peerIds=[];
|
|
270
|
+
let peersComplete=true;
|
|
271
|
+
for(const edge of targets){
|
|
272
|
+
const peer=agentForAnchor(edge.target);
|
|
273
|
+
if(!peer){peersComplete=false;continue}
|
|
274
|
+
peerIds.push(peer);
|
|
275
|
+
}
|
|
276
|
+
if(targets.length&&!peersComplete&&!peerIds.length)continue;
|
|
277
|
+
pushOccurrence(kind,owner,peerIds,node,[node.id],[...sources,...targets].map(edge=>edge.id).filter(Boolean));
|
|
186
278
|
}
|
|
187
279
|
|
|
188
280
|
for(const node of rawNodes){
|
|
189
281
|
if(node?.type!=='agent_message'||!node.id)continue;
|
|
190
282
|
const sent=(incoming.get(node.id)||[]).filter(edge=>relation(edge)==='SENT_AGENT_MESSAGE');
|
|
191
283
|
const delivered=(outgoing.get(node.id)||[]).filter(edge=>relation(edge)==='DELIVERED_AGENT_MESSAGE');
|
|
192
|
-
const owner=sent.map(edge=>agentForAnchor(edge.source))
|
|
193
|
-
|
|
194
|
-
|
|
284
|
+
const owner=uniqueOwner(sent.map(edge=>agentForAnchor(edge.source)));
|
|
285
|
+
if(!owner)continue;
|
|
286
|
+
const peerIds=[];
|
|
287
|
+
let peersComplete=true;
|
|
288
|
+
for(const edge of delivered){
|
|
289
|
+
const peer=agentForAnchor(edge.target);
|
|
290
|
+
if(!peer){peersComplete=false;continue}
|
|
291
|
+
peerIds.push(peer);
|
|
292
|
+
}
|
|
293
|
+
if(delivered.length&&!peersComplete&&!peerIds.length)continue;
|
|
294
|
+
pushOccurrence('send_input',owner,peerIds,node,[node.id],[...sent,...delivered].map(edge=>edge.id).filter(Boolean));
|
|
195
295
|
}
|
|
196
296
|
|
|
197
297
|
for(const edge of rawEdges){
|
|
@@ -293,13 +393,70 @@ EXECUTION_FLOW_SCRIPT = r"""
|
|
|
293
393
|
for(const modelId of new Set(list.map(item=>item.modelId)))ensureContext(owner,modelId);
|
|
294
394
|
}
|
|
295
395
|
|
|
296
|
-
const consumedRawNodes=new Set(),consumedRawEdges=new Set(),
|
|
396
|
+
const consumedRawNodes=new Set(),consumedRawEdges=new Set(),consumedCallIds=new Set();
|
|
397
|
+
const contentRefFromNode=(contentNode,edge,direction)=>{
|
|
398
|
+
const attrs=attrsOf(contentNode);
|
|
399
|
+
const viewer=attrs.viewer_content&&typeof attrs.viewer_content==='object'?attrs.viewer_content:{};
|
|
400
|
+
return{
|
|
401
|
+
content_node_id:contentNode.id,
|
|
402
|
+
raw_node_id:contentNode.id,
|
|
403
|
+
raw_edge_id:edge?.id||null,
|
|
404
|
+
relation:edge?.relation||null,
|
|
405
|
+
direction:direction||null,
|
|
406
|
+
sha256:viewer.sha256||attrs.sha256||attrs.content_sha256||null,
|
|
407
|
+
path:viewer.safe_relative_path||attrs.path||attrs.content_path||null,
|
|
408
|
+
size_bytes:viewer.size_bytes??attrs.size_bytes??attrs.content_size_bytes??null,
|
|
409
|
+
media_type:viewer.media_type||attrs.media_type||attrs.content_media_type||null,
|
|
410
|
+
content_kind:viewer.content_kind||attrs.content_kind||contentNode.name||null,
|
|
411
|
+
};
|
|
412
|
+
};
|
|
297
413
|
for(const group of groups.values()){
|
|
298
414
|
const context=group.modelId?ensureContext(group.owner,group.modelId):null;
|
|
299
415
|
const source=context||group.owner;
|
|
300
416
|
const baseRank=agentRank.get(group.owner)||0;
|
|
301
417
|
const actionRank=baseRank+(context?2:1);
|
|
302
418
|
const id=`viewer:orchestration:${encodeURIComponent(group.owner)}:${encodeURIComponent(group.modelId||'unresolved')}:${group.kind}`;
|
|
419
|
+
const contentRefs=[];
|
|
420
|
+
const toolCallOccurrences=[];
|
|
421
|
+
for(const rawId of group.rawNodeIds){
|
|
422
|
+
const rawNode=rawById.get(rawId);
|
|
423
|
+
if(!rawNode)continue;
|
|
424
|
+
if(String(rawNode.type||'')==='observed_content'){
|
|
425
|
+
contentRefs.push(contentRefFromNode(rawNode,null,'node'));
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
for(const edge of [...(outgoing.get(rawId)||[]),...(incoming.get(rawId)||[])]){
|
|
429
|
+
const peerId=edge.source===rawId?edge.target:edge.source;
|
|
430
|
+
const peer=rawById.get(peerId);
|
|
431
|
+
if(peer?.type!=='observed_content')continue;
|
|
432
|
+
const direction=edge.source===rawId?'outgoing':'incoming';
|
|
433
|
+
const ref=contentRefFromNode(peer,edge,direction);
|
|
434
|
+
if(!contentRefs.some(item=>item.content_node_id===ref.content_node_id&&item.raw_edge_id===ref.raw_edge_id)){
|
|
435
|
+
contentRefs.push(ref);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
if(['tool_call','tool_call_observation'].includes(String(rawNode?.type||''))){
|
|
439
|
+
consumedCallIds.add(rawId);
|
|
440
|
+
const attrs=attrsOf(rawNode);
|
|
441
|
+
let toolId=null;
|
|
442
|
+
for(const edge of outgoing.get(rawId)||[]){
|
|
443
|
+
if(relation(edge)==='USES_TOOL'||relation(edge)==='RESOLVED_TOOL'){toolId=edge.target;break}
|
|
444
|
+
}
|
|
445
|
+
toolCallOccurrences.push({
|
|
446
|
+
invocation_id:rawId,
|
|
447
|
+
owner_id:group.owner,
|
|
448
|
+
tool_id:toolId,
|
|
449
|
+
call_ids:[rawId],
|
|
450
|
+
first_sequence:Number.isInteger(rawNode.first_sequence)?rawNode.first_sequence:null,
|
|
451
|
+
last_sequence:Number.isInteger(rawNode.last_sequence)?rawNode.last_sequence:null,
|
|
452
|
+
first_seen:rawNode.first_seen||null,
|
|
453
|
+
last_seen:rawNode.last_seen||null,
|
|
454
|
+
input:attrs.arguments??attrs.args??attrs.tool_input??attrs.input??attrs.parameters??attrs.request??null,
|
|
455
|
+
output:attrs.output??attrs.result??attrs.tool_output??attrs.response??null,
|
|
456
|
+
content_references:contentRefs.filter(ref=>ref.raw_edge_id&&[...(outgoing.get(rawId)||[]),...(incoming.get(rawId)||[])].some(edge=>edge.id===ref.raw_edge_id)),
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
}
|
|
303
460
|
addedNodes.push({
|
|
304
461
|
id,type:'tool',name:group.kind,
|
|
305
462
|
attributes:{
|
|
@@ -309,6 +466,8 @@ EXECUTION_FLOW_SCRIPT = r"""
|
|
|
309
466
|
evidence_node_ids:[...group.rawNodeIds].sort(),evidence_edge_ids:[...group.rawEdgeIds].sort(),
|
|
310
467
|
viewer_occurrence_count:group.occurrences.length,
|
|
311
468
|
viewer_model_context_unresolved:!context||undefined,
|
|
469
|
+
viewer_content_references:contentRefs,
|
|
470
|
+
viewer_tool_call_occurrences:toolCallOccurrences,
|
|
312
471
|
}
|
|
313
472
|
});
|
|
314
473
|
addedEdges.push({
|
|
@@ -326,13 +485,23 @@ EXECUTION_FLOW_SCRIPT = r"""
|
|
|
326
485
|
}
|
|
327
486
|
for(const rawId of group.rawNodeIds)consumedRawNodes.add(rawId);
|
|
328
487
|
for(const rawId of group.rawEdgeIds)consumedRawEdges.add(rawId);
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Shared tool definitions / model resources stay unless every remaining USES_TOOL
|
|
491
|
+
// into them came from consumed calls. Consuming one owner's call must not wipe the
|
|
492
|
+
// shared definition for other owners or unresolved calls.
|
|
493
|
+
const hideToolDefs=new Set();
|
|
494
|
+
for(const [toolId,node] of [...rawById].filter(([,n])=>n?.type==='tool')){
|
|
495
|
+
const uses=(incoming.get(toolId)||[]).filter(edge=>['USES_TOOL','RESOLVED_TOOL'].includes(relation(edge)));
|
|
496
|
+
if(!uses.length)continue;
|
|
497
|
+
// Keep shared tool definitions when any live use remains: another owner's
|
|
498
|
+
// unconsumed call, an agent-direct USES_TOOL, or unresolved evidence.
|
|
499
|
+
const allConsumedCalls=uses.every(edge=>{
|
|
500
|
+
const src=rawById.get(edge.source);
|
|
501
|
+
const isCall=['tool_call','tool_call_observation'].includes(String(src?.type||''));
|
|
502
|
+
return isCall&&consumedCallIds.has(edge.source);
|
|
503
|
+
});
|
|
504
|
+
if(allConsumedCalls)hideToolDefs.add(toolId);
|
|
336
505
|
}
|
|
337
506
|
|
|
338
507
|
const flowNodes=display.nodes.map(node=>{
|
|
@@ -342,17 +511,25 @@ EXECUTION_FLOW_SCRIPT = r"""
|
|
|
342
511
|
|
|
343
512
|
const modelRelation=edge=>MODEL_RELATIONS.has(relation(edge))||relation(edge)==='MODEL_CONTEXT';
|
|
344
513
|
const orchestrationRelation=edge=>DIRECT_ACTION_RELATIONS.has(relation(edge));
|
|
345
|
-
let nodes=flowNodes.filter(node=>!consumedRawNodes.has(node.id)&&!
|
|
514
|
+
let nodes=flowNodes.filter(node=>!consumedRawNodes.has(node.id)&&!hideToolDefs.has(node.id));
|
|
346
515
|
let edges=display.edges.filter(edge=>{
|
|
347
516
|
if(consumedRawEdges.has(edge.id))return false;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
if(
|
|
517
|
+
// Keep unconsumed inferred / provider orchestration evidence. Only hide edges
|
|
518
|
+
// that were actually folded into an occurrence (tracked via consumedRawEdges).
|
|
519
|
+
if(orchestrationRelation(edge)&&agents.has(edge.source)&&agents.has(edge.target)){
|
|
520
|
+
return !consumedRawEdges.has(edge.id);
|
|
521
|
+
}
|
|
522
|
+
if(hideToolDefs.has(edge.source)||hideToolDefs.has(edge.target))return false;
|
|
523
|
+
// Only supersede an owner→model edge when THAT owner already has a viewer
|
|
524
|
+
// model-context for the same model. Other owners' shared-model usage stays.
|
|
525
|
+
if(modelRelation(edge)&&agents.has(edge.source)&&contextIds.has(contextId(edge.source,edge.target)))return false;
|
|
351
526
|
return true;
|
|
352
527
|
});
|
|
353
528
|
|
|
354
529
|
for(const modelId of contextifiedModels){
|
|
355
530
|
const remaining=edges.filter(edge=>edge.source===modelId||edge.target===modelId);
|
|
531
|
+
// Keep the raw model resource whenever any non-superseded usage remains
|
|
532
|
+
// (another owner, unresolved call, or non-agent attachment).
|
|
356
533
|
if(!remaining.length)nodes=nodes.filter(node=>node.id!==modelId);
|
|
357
534
|
}
|
|
358
535
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
_EXACT_SUBTASK_ACTION = """ const evidenceEdges=[...requests,...assignments,...childSessionEdges];
|
|
5
|
+
pushOccurrence(
|
|
6
|
+
'assign_agent_task',owner,[target],assignmentSeed,[subtask.id],
|
|
7
|
+
evidenceEdges.map(edge=>edge.id).filter(Boolean)
|
|
8
|
+
);"""
|
|
9
|
+
_EXACT_SUBTASK_ACTION_NORMALIZED = """ const evidenceEdges=[...requests,...assignments,...childSessionEdges];
|
|
10
|
+
const matchingSpawn=occurrences.find(occurrence=>
|
|
11
|
+
occurrence.kind==='spawn_agent'&&occurrence.owner===owner&&occurrence.targets.has(target)
|
|
12
|
+
);
|
|
13
|
+
if(matchingSpawn){
|
|
14
|
+
if(!matchingSpawn.rawNodeIds.includes(subtask.id))matchingSpawn.rawNodeIds.push(subtask.id);
|
|
15
|
+
for(const edgeIdValue of evidenceEdges.map(edge=>edge.id).filter(Boolean)){
|
|
16
|
+
if(!matchingSpawn.rawEdgeIds.includes(edgeIdValue))matchingSpawn.rawEdgeIds.push(edgeIdValue);
|
|
17
|
+
}
|
|
18
|
+
}else{
|
|
19
|
+
pushOccurrence(
|
|
20
|
+
'assign_agent_task',owner,[target],assignmentSeed,[subtask.id],
|
|
21
|
+
evidenceEdges.map(edge=>edge.id).filter(Boolean)
|
|
22
|
+
);
|
|
23
|
+
}"""
|
|
24
|
+
|
|
25
|
+
_ACTION_TARGET_END = """ for(const target of [...group.targets].sort()){
|
|
26
|
+
addedEdges.push({
|
|
27
|
+
id:`viewer:${id}--${targetRelation}-->${target}`,source:id,target,relation:targetRelation,
|
|
28
|
+
count:1,viewer_only:true,causal:false,inferred:false,
|
|
29
|
+
attributes:{viewer_only:true,projection:'execution_flow',evidence_node_ids:[...group.rawNodeIds],evidence_edge_ids:[...group.rawEdgeIds]}
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
for(const rawId of group.rawNodeIds)consumedRawNodes.add(rawId);"""
|
|
33
|
+
_ACTION_TARGET_WITH_PAYLOADS = """ for(const target of [...group.targets].sort()){
|
|
34
|
+
addedEdges.push({
|
|
35
|
+
id:`viewer:${id}--${targetRelation}-->${target}`,source:id,target,relation:targetRelation,
|
|
36
|
+
count:1,viewer_only:true,causal:false,inferred:false,
|
|
37
|
+
attributes:{viewer_only:true,projection:'execution_flow',evidence_node_ids:[...group.rawNodeIds],evidence_edge_ids:[...group.rawEdgeIds]}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
// Retarget visible detail edges onto the replacement action, but never onto
|
|
41
|
+
// peers that other flow groups also consume (prevents dangling action ->
|
|
42
|
+
// consumed interaction anchors in Codex reduced-state replay).
|
|
43
|
+
const peerConsumedRawNodeIds=new Set();
|
|
44
|
+
for(const other of groups.values())for(const rawId of other.rawNodeIds)peerConsumedRawNodeIds.add(rawId);
|
|
45
|
+
const detailRelations=new Set([
|
|
46
|
+
'HAS_SUBTASK_PROMPT','HAS_SUBTASK_DESCRIPTION','TARGETS_AGENT_PROFILE',
|
|
47
|
+
'HAS_COMMAND','HAS_WORKING_DIRECTORY','USES_PROFILE','READS_FILE','WRITES_FILE',
|
|
48
|
+
'HAS_FILE','OBSERVED_CONTENT','HAS_TOOL_INPUT','HAS_TOOL_OUTPUT'
|
|
49
|
+
]);
|
|
50
|
+
for(const rawId of group.rawNodeIds){
|
|
51
|
+
for(const rawEdge of outgoing.get(rawId)||[]){
|
|
52
|
+
const payloadRelation=relation(rawEdge);
|
|
53
|
+
if(!detailRelations.has(payloadRelation))continue;
|
|
54
|
+
const detailTarget=rawEdge.target;
|
|
55
|
+
// Skip retargeting into another group's consumed anchors.
|
|
56
|
+
if(peerConsumedRawNodeIds.has(detailTarget)&&!group.rawNodeIds.has(detailTarget))continue;
|
|
57
|
+
if(!display.nodes.some(node=>node?.id===detailTarget)&&!rawById.has(detailTarget))continue;
|
|
58
|
+
// Do not paint observed_content back onto the canvas; content stays hidden
|
|
59
|
+
// and is exposed via viewer_content_references on the action instead.
|
|
60
|
+
const targetNode=rawById.get(detailTarget)||display.nodes.find(node=>node?.id===detailTarget);
|
|
61
|
+
if(targetNode?.type==='observed_content')continue;
|
|
62
|
+
if(targetNode?.type==='agent_interaction')continue;
|
|
63
|
+
addedEdges.push({
|
|
64
|
+
id:`viewer:${id}--${payloadRelation}-->${detailTarget}:evidence:${encodeURIComponent(rawEdge.id||rawId)}`,
|
|
65
|
+
source:id,target:detailTarget,relation:rawEdge.relation||payloadRelation,
|
|
66
|
+
count:Number.isFinite(rawEdge.count)?rawEdge.count:1,viewer_only:true,causal:false,inferred:false,
|
|
67
|
+
attributes:{viewer_only:true,projection:'execution_flow',evidence_node_ids:[rawId],evidence_edge_ids:[rawEdge.id].filter(Boolean)}
|
|
68
|
+
});
|
|
69
|
+
if(rawEdge.id)consumedRawEdges.add(rawEdge.id);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
for(const rawId of group.rawNodeIds)consumedRawNodes.add(rawId);"""
|
|
73
|
+
|
|
74
|
+
_EDGE_FILTER = " if(consumedRawEdges.has(edge.id))return false;"
|
|
75
|
+
_EDGE_FILTER_NO_DANGLING = """ if(consumedRawEdges.has(edge.id))return false;
|
|
76
|
+
// Drop edges that still point at consumed presentation nodes, but never use
|
|
77
|
+
// this as a blanket cover for lost evidence — detail retargeting above must
|
|
78
|
+
// have preserved reachable payloads onto the replacement action first.
|
|
79
|
+
if(consumedRawNodes.has(edge.source)||consumedRawNodes.has(edge.target))return false;"""
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def normalize_provider_execution_flow(html: str) -> str:
|
|
83
|
+
"""Normalize equivalent exact delegation encodings without weakening evidence gates.
|
|
84
|
+
|
|
85
|
+
Cursor may report both a direct child-start lifecycle edge and an exact subtask
|
|
86
|
+
assignment for the same child. Those are two observations of one delegation, not two
|
|
87
|
+
orchestration actions. The exact subtask evidence is folded into the existing spawn
|
|
88
|
+
occurrence when both owner and child already match. Providers without a direct spawn
|
|
89
|
+
(for example the validated Antigravity assignment path) keep the assignment action.
|
|
90
|
+
|
|
91
|
+
Superseded task/tool-call nodes are presentation-only removals. Any provider-observed
|
|
92
|
+
task prompt/description remains reachable from the replacement orchestration action,
|
|
93
|
+
and no display edge is allowed to reference a consumed node. The raw graph is never
|
|
94
|
+
mutated by this normalizer.
|
|
95
|
+
"""
|
|
96
|
+
seams = (
|
|
97
|
+
(_EXACT_SUBTASK_ACTION, _EXACT_SUBTASK_ACTION_NORMALIZED, "exact-subtask fold"),
|
|
98
|
+
(_ACTION_TARGET_END, _ACTION_TARGET_WITH_PAYLOADS, "delegation payload preservation"),
|
|
99
|
+
(_EDGE_FILTER, _EDGE_FILTER_NO_DANGLING, "consumed-node edge filter"),
|
|
100
|
+
)
|
|
101
|
+
for needle, replacement, label in seams:
|
|
102
|
+
if html.count(needle) != 1:
|
|
103
|
+
raise RuntimeError(f"execution-flow provider normalization seam changed: {label}")
|
|
104
|
+
html = html.replace(needle, replacement, 1)
|
|
105
|
+
return html
|