execweave 0.8.25__tar.gz → 0.8.28__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.
Files changed (187) hide show
  1. {execweave-0.8.25 → execweave-0.8.28}/PKG-INFO +1 -1
  2. {execweave-0.8.25 → execweave-0.8.28}/pyproject.toml +2 -2
  3. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/__init__.py +1 -1
  4. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/collector.py +9 -1
  5. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/framework_adapters/base.py +34 -2
  6. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/framework_adapters/camel.py +68 -7
  7. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/strace_backend.py +6 -0
  8. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_agent_panel.py +4 -0
  9. {execweave-0.8.25 → execweave-0.8.28}/.gitignore +0 -0
  10. {execweave-0.8.25 → execweave-0.8.28}/LICENSE +0 -0
  11. {execweave-0.8.25 → execweave-0.8.28}/README.md +0 -0
  12. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/__main__.py +0 -0
  13. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/_conversation_records_core.py +0 -0
  14. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/_dashboard_shell_base.py +0 -0
  15. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/_http_proxy_base.py +0 -0
  16. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/_http_proxy_bounded.py +0 -0
  17. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/_http_proxy_stage.py +0 -0
  18. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/agent_bootstrap.py +0 -0
  19. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/agent_topology.py +0 -0
  20. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/agent_trace.py +0 -0
  21. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/agy_preview_sanitize.py +0 -0
  22. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/analysis.py +0 -0
  23. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/anthropic.py +0 -0
  24. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/anthropic_cli.py +0 -0
  25. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/anthropic_full_fidelity.py +0 -0
  26. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/antigravity_adapter.py +0 -0
  27. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/antigravity_adapter_base.py +0 -0
  28. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/antigravity_full_fidelity.py +0 -0
  29. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/antigravity_full_fidelity_base.py +0 -0
  30. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/antigravity_full_fidelity_collaboration_base.py +0 -0
  31. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/antigravity_hook_cli.py +0 -0
  32. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/antigravity_record.py +0 -0
  33. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/antigravity_subagent_linkage.py +0 -0
  34. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/antigravity_trace_capability.py +0 -0
  35. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/auto_specialized.py +0 -0
  36. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/backends.py +0 -0
  37. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/benchmark.py +0 -0
  38. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/claude_adapter.py +0 -0
  39. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/claude_child_transcript.py +0 -0
  40. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/claude_delegation.py +0 -0
  41. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/claude_full_fidelity.py +0 -0
  42. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/claude_hook_cli.py +0 -0
  43. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/claude_hook_contract.py +0 -0
  44. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/claude_model_observer.py +0 -0
  45. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/claude_record.py +0 -0
  46. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/cli.py +0 -0
  47. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_adapter.py +0 -0
  48. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_conversation.py +0 -0
  49. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_full_fidelity.py +0 -0
  50. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_hook_cli.py +0 -0
  51. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_hook_entry.py +0 -0
  52. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_hook_lifecycle.py +0 -0
  53. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_message_diagnostics.py +0 -0
  54. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_message_transport_diagnostics.py +0 -0
  55. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_record.py +0 -0
  56. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_rollout_structures.py +0 -0
  57. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_rollout_trace.py +0 -0
  58. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/codex_rollout_trace_base.py +0 -0
  59. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/command.py +0 -0
  60. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/content_evidence.py +0 -0
  61. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/content_store.py +0 -0
  62. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_archive.py +0 -0
  63. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_message_identity.py +0 -0
  64. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_preview.py +0 -0
  65. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_preview_antigravity.py +0 -0
  66. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_preview_claude.py +0 -0
  67. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_preview_codex.py +0 -0
  68. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_preview_common.py +0 -0
  69. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_preview_generic.py +0 -0
  70. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_preview_lines.py +0 -0
  71. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_preview_transcript.py +0 -0
  72. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_records.py +0 -0
  73. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_records_antigravity.py +0 -0
  74. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_records_codex.py +0 -0
  75. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_records_common.py +0 -0
  76. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/conversation_records_ollama.py +0 -0
  77. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/correlation.py +0 -0
  78. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/cursor_adapter.py +0 -0
  79. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/cursor_delegation.py +0 -0
  80. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/cursor_delegation_base.py +0 -0
  81. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/cursor_full_fidelity.py +0 -0
  82. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/cursor_hook_cli.py +0 -0
  83. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/cursor_hook_contract.py +0 -0
  84. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/cursor_lifecycle.py +0 -0
  85. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/cursor_record.py +0 -0
  86. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/dashboard_shell.py +0 -0
  87. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/entry.py +0 -0
  88. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/evidence_availability.py +0 -0
  89. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/evidence_grade.py +0 -0
  90. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/fidelity.py +0 -0
  91. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/filesystem.py +0 -0
  92. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/focus.py +0 -0
  93. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/framework_adapters/__init__.py +0 -0
  94. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/framework_adapters/autogen.py +0 -0
  95. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/framework_adapters/metagpt.py +0 -0
  96. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/framework_adapters/registry.py +0 -0
  97. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/graph.py +0 -0
  98. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/graph_ops.py +0 -0
  99. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/http_proxy.py +0 -0
  100. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/http_proxy_cli.py +0 -0
  101. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/inference_gateway.py +0 -0
  102. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/inference_gateway_cli.py +0 -0
  103. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/inference_gateway_full_fidelity.py +0 -0
  104. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/inference_identity.py +0 -0
  105. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/inference_identity_cli.py +0 -0
  106. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/integrity.py +0 -0
  107. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/integrity_cli.py +0 -0
  108. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/litellm_callback.py +0 -0
  109. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/litellm_callback_cli.py +0 -0
  110. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live.py +0 -0
  111. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_core.py +0 -0
  112. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_view.py +0 -0
  113. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_view_extra_style.py +0 -0
  114. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_view_markup.py +0 -0
  115. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_view_process_layout.py +0 -0
  116. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_view_readability.py +0 -0
  117. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_view_script_a.py +0 -0
  118. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_view_script_b.py +0 -0
  119. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_view_script_c.py +0 -0
  120. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_view_script_d.py +0 -0
  121. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/live_view_style.py +0 -0
  122. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/model_runtime.py +0 -0
  123. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/model_runtime_cli.py +0 -0
  124. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/model_runtime_full_fidelity.py +0 -0
  125. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/openai_compatible.py +0 -0
  126. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/openai_compatible_cli.py +0 -0
  127. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/openai_compatible_full_fidelity.py +0 -0
  128. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/opencode_adapter.py +0 -0
  129. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/opencode_event_contract.py +0 -0
  130. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/opencode_full_fidelity.py +0 -0
  131. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/opencode_hook_cli.py +0 -0
  132. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/opencode_plugin_cli.py +0 -0
  133. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/opencode_record.py +0 -0
  134. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/opencode_task_linkage.py +0 -0
  135. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/overhead_benchmark.py +0 -0
  136. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/provider_capability.py +0 -0
  137. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/provider_lifecycle.py +0 -0
  138. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/provider_record.py +0 -0
  139. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/rule_pack.py +0 -0
  140. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/rule_pack_cli.py +0 -0
  141. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/runtime_endpoint_availability.py +0 -0
  142. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/scalability_benchmark.py +0 -0
  143. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/schema.py +0 -0
  144. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/scope.py +0 -0
  145. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/semantic.py +0 -0
  146. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/sink.py +0 -0
  147. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/stream_assembly.py +0 -0
  148. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/theme.py +0 -0
  149. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/top.py +0 -0
  150. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/top_cli.py +0 -0
  151. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/validate.py +0 -0
  152. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/vendor/dagre.min.js +0 -0
  153. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/view_cli.py +0 -0
  154. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer.py +0 -0
  155. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_agent_panel_antigravity.py +0 -0
  156. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_agent_panel_claude.py +0 -0
  157. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_agent_panel_codex.py +0 -0
  158. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_agent_panel_cursor.py +0 -0
  159. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_agent_panel_default.py +0 -0
  160. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_agent_panel_ollama.py +0 -0
  161. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_agent_panel_opencode.py +0 -0
  162. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_agent_panel_registry.py +0 -0
  163. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_content_inspector.py +0 -0
  164. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_dashboard_clean.py +0 -0
  165. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_dashboard_focus.py +0 -0
  166. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_dashboard_hardening.py +0 -0
  167. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_dashboard_hardening_v2.py +0 -0
  168. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_dashboard_pr70.py +0 -0
  169. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_edge_decross.py +0 -0
  170. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_execution_flow.py +0 -0
  171. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_execution_flow_provider_normalization.py +0 -0
  172. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_execution_flow_safety.py +0 -0
  173. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_external_endpoints.py +0 -0
  174. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_flow_canvas.py +0 -0
  175. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_flow_layout.py +0 -0
  176. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_gif.py +0 -0
  177. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_layout_geometry.py +0 -0
  178. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_layout_v2.py +0 -0
  179. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_layout_v2_detached.py +0 -0
  180. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_limits.py +0 -0
  181. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_live_layout.py +0 -0
  182. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_projection.py +0 -0
  183. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_projection_base.py +0 -0
  184. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_projection_bridges.py +0 -0
  185. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_semantic_projection.py +0 -0
  186. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/viewer_tool_mirror_identity.py +0 -0
  187. {execweave-0.8.25 → execweave-0.8.28}/src/execweave/workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: execweave
3
- Version: 0.8.25
3
+ Version: 0.8.28
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
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "execweave"
7
- # ExecWeave v0.8.25 release metadata
8
- version = "0.8.25"
7
+ # ExecWeave v0.8.28 release metadata
8
+ version = "0.8.28"
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"
@@ -1,3 +1,3 @@
1
1
  """ExecWeave runtime graph package."""
2
2
 
3
- __version__ = "0.8.25"
3
+ __version__ = "0.8.28"
@@ -75,7 +75,15 @@ def _safe_process_snapshot(proc: psutil.Process) -> ProcessSnapshot | None:
75
75
  exe=exe,
76
76
  create_time=proc.create_time(),
77
77
  )
78
- except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
78
+ except (
79
+ psutil.NoSuchProcess,
80
+ psutil.AccessDenied,
81
+ psutil.ZombieProcess,
82
+ # macOS can surface protected-process cmdline denial as a SystemError
83
+ # from psutil's C extension instead of AccessDenied. Treat that process
84
+ # as unobservable, just like the other permission-race cases.
85
+ SystemError,
86
+ ):
79
87
  return None
80
88
 
81
89
 
@@ -33,8 +33,9 @@ CANONICAL_EVENT_TYPES = frozenset(
33
33
  {
34
34
  "AGENT_CREATED", "AGENT_STARTED", "AGENT_STOPPED",
35
35
  "TASK_CREATED", "TASK_ASSIGNED", "TASK_STARTED", "TASK_UPDATED",
36
+ "TASK_CONTENT_RECORDED",
36
37
  "TASK_COMPLETED", "TASK_FAILED",
37
- "MESSAGE_SENT", "MESSAGE_RECEIVED",
38
+ "MESSAGE_SENT", "MESSAGE_RECEIVED", "MESSAGE_UNROUTED",
38
39
  "MODEL_REQUEST", "MODEL_RESPONSE", "MODEL_FAILURE",
39
40
  "TOOL_CALL", "TOOL_RESULT", "TOOL_FAILURE",
40
41
  "MESSAGE_CONTENT_RECORDED", "MODEL_CONTENT_RECORDED", "TOOL_CONTENT_RECORDED",
@@ -298,6 +299,8 @@ class TaskRecord:
298
299
  task: EntityRef
299
300
  owner: EntityRef | None = None
300
301
  parent_task: EntityRef | None = None
302
+ content: str | None = None
303
+ content_kind: str = "task_prompt"
301
304
  attributes: Mapping[str, Any] = field(default_factory=dict)
302
305
 
303
306
 
@@ -391,9 +394,38 @@ class AdapterContext:
391
394
  return record.agent
392
395
 
393
396
  def record_task(self, record: TaskRecord, *, event_type: str = "TASK_CREATED") -> EntityRef:
394
- self.emit(event_type, event_type, source=record.owner, target=record.task, attributes={"parent_task_id": record.parent_task.id if record.parent_task else None, **dict(record.attributes)})
397
+ content_reference = None
398
+ if record.content is not None:
399
+ content_kind = record.content_kind
400
+ if "." not in content_kind:
401
+ content_kind = f"{self.framework}.{content_kind}"
402
+ content_reference = self.content.put_text(record.content, content_kind=content_kind)
403
+ task_attributes = {
404
+ "parent_task_id": record.parent_task.id if record.parent_task else None,
405
+ **self.content.reference_attributes(content_reference),
406
+ **dict(record.attributes),
407
+ }
408
+ self.emit(event_type, event_type, source=record.owner, target=record.task, attributes=task_attributes)
395
409
  if record.parent_task is not None:
396
410
  self.emit("TASK_CREATED", "PARENT_TASK", source=record.parent_task, target=record.task, attributes={"parent_task_id": record.parent_task.id})
411
+ if content_reference is not None:
412
+ content = EntityRef(
413
+ "observed_content",
414
+ f"observed-content:task:sha256:{content_reference.sha256}",
415
+ content_reference.content_kind,
416
+ content_reference.to_dict(),
417
+ )
418
+ self.emit(
419
+ "TASK_CONTENT_RECORDED",
420
+ "HAS_TASK_CONTENT",
421
+ source=record.task,
422
+ target=content,
423
+ attributes={
424
+ "task_id": record.task.id,
425
+ "conversation_scope": "task",
426
+ **self.content.reference_attributes(content_reference),
427
+ },
428
+ )
397
429
  return record.task
398
430
 
399
431
  def record_message(self, record: MessageRecord) -> EntityRef:
@@ -11,16 +11,17 @@ from .base import AdapterCapabilities, AdapterContext, AgentRecord, EntityRef, F
11
11
  class CAMELAdapter(FrameworkAdapter):
12
12
  framework_name = "camel"
13
13
  capabilities = AdapterCapabilities(
14
- events=("AGENT_CREATED", "AGENT_STARTED", "AGENT_STOPPED", "TASK_CREATED", "TASK_ASSIGNED", "TASK_STARTED", "TASK_UPDATED", "TASK_COMPLETED", "TASK_FAILED", "MESSAGE_SENT", "MESSAGE_RECEIVED", "MODEL_REQUEST", "MODEL_RESPONSE", "MODEL_FAILURE"),
14
+ events=("AGENT_CREATED", "AGENT_STARTED", "AGENT_STOPPED", "TASK_CREATED", "TASK_ASSIGNED", "TASK_STARTED", "TASK_UPDATED", "TASK_COMPLETED", "TASK_FAILED", "TASK_CONTENT_RECORDED", "MESSAGE_SENT", "MESSAGE_RECEIVED", "MESSAGE_UNROUTED", "MODEL_REQUEST", "MODEL_RESPONSE", "MODEL_FAILURE"),
15
15
  content_modes=("metadata_only", "content_ref_only", "prompt_only", "prompt_and_response"),
16
16
  authoritative_surfaces=("camel.societies.workforce.WorkforceCallback", "camel.models.BaseModelBackend.run", "camel.models.BaseModelBackend.arun"),
17
- known_limitations=("WorkforceCallback LogEvent does not expose the emitting worker or recipient; those log messages remain explicitly unrouted unless a stream-chunk or model/message hook supplies the boundary.", "A created worker is not treated as assigned until CAMEL reports a task assignment."),
17
+ known_limitations=("WorkforceCallback LogEvent does not expose the emitting worker or recipient; those log messages are explicitly marked MESSAGE_UNROUTED and correlated to the observed process instead of being assigned to a guessed agent.", "A created worker is not treated as assigned until CAMEL reports a task assignment."),
18
18
  )
19
19
 
20
20
  def __init__(self, context: AdapterContext) -> None:
21
21
  super().__init__(context)
22
22
  self._agents: dict[str, EntityRef] = {}
23
23
  self._tasks: dict[str, EntityRef] = {}
24
+ self._active_tasks_by_agent: dict[str, EntityRef] = {}
24
25
  self._message_counter = 0
25
26
 
26
27
  @classmethod
@@ -44,18 +45,40 @@ class CAMELAdapter(FrameworkAdapter):
44
45
  def agent_stopped(self, agent: EntityRef, **attributes: Any) -> None:
45
46
  self.emit("AGENT_STOPPED", "AGENT_STOPPED", source=agent, attributes=attributes)
46
47
 
47
- def task_event(self, event_type: str, native_id: str | int, *, name: str | None = None, owner: EntityRef | None = None, parent: EntityRef | None = None, **attributes: Any) -> EntityRef:
48
- task = self.task(native_id, name=name, provider="camel", **attributes)
48
+ def task_event(self, event_type: str, native_id: str | int, *, name: str | None = None, owner: EntityRef | None = None, parent: EntityRef | None = None, content: str | None = None, content_kind: str = "task_prompt", **attributes: Any) -> EntityRef:
49
+ existing = self._tasks.get(str(native_id))
50
+ if existing is not None and name is None and content is None and not attributes:
51
+ task = existing
52
+ else:
53
+ entity_attributes = dict(attributes)
54
+ if content is not None:
55
+ entity_attributes.setdefault("task_prompt", content)
56
+ task = self.task(native_id, name=name, provider="camel", **entity_attributes)
49
57
  self._tasks[str(native_id)] = task
50
- self.context.record_task(TaskRecord(task, owner=owner, parent_task=parent, attributes=attributes), event_type=event_type)
58
+ self.context.record_task(
59
+ TaskRecord(
60
+ task,
61
+ owner=owner,
62
+ parent_task=parent,
63
+ content=content,
64
+ content_kind=content_kind,
65
+ attributes=attributes,
66
+ ),
67
+ event_type=event_type,
68
+ )
51
69
  return task
52
70
 
53
71
  def task_created(self, native_id: str | int, **kwargs: Any) -> EntityRef:
54
72
  return self.task_event("TASK_CREATED", native_id, **kwargs)
55
73
 
56
74
  def task_assigned(self, task: EntityRef, agent: EntityRef, **attributes: Any) -> None:
75
+ self._active_tasks_by_agent[agent.id] = task
57
76
  self.emit("TASK_ASSIGNED", "ASSIGNED_TO", source=task, target=agent, attributes=attributes)
58
77
 
78
+ def active_task_for(self, agent: EntityRef | None) -> EntityRef | None:
79
+ """Return the latest provider-observed task assigned to an agent."""
80
+ return self._active_tasks_by_agent.get(agent.id) if agent is not None else None
81
+
59
82
  def task_started(self, task: EntityRef, agent: EntityRef | None = None, **attributes: Any) -> None:
60
83
  self.emit("TASK_STARTED", "TASK_STARTED", source=agent or task, target=task, attributes=attributes)
61
84
 
@@ -73,6 +96,32 @@ class CAMELAdapter(FrameworkAdapter):
73
96
  self.context.record_message(MessageRecord(message, source, target, role=role, task=task, content=content, direction="received" if received else "sent", attributes=attributes))
74
97
  return message
75
98
 
99
+ def message_unrouted(self, message: EntityRef, *, callback_name: str, missing_sender: bool, missing_recipient: bool, reason: str = "callback_payload_missing_agent_boundary") -> None:
100
+ """Keep callback messages visible without inventing an agent route.
101
+
102
+ CAMEL's WorkforceCallback log surface can emit a message without a
103
+ worker or recipient. The process is the only authoritative boundary
104
+ available in that case, so record that boundary explicitly rather
105
+ than leaving the message looking like a dropped graph node.
106
+ """
107
+ process = self.context.process
108
+ if process is None:
109
+ return
110
+ self.emit(
111
+ "MESSAGE_UNROUTED",
112
+ "OBSERVED_AT_PROCESS",
113
+ source=message,
114
+ target=process.to_entity(),
115
+ attributes={
116
+ "callback_name": callback_name,
117
+ "routing_status": "unrouted",
118
+ "routing_reason": reason,
119
+ "missing_sender": missing_sender,
120
+ "missing_recipient": missing_recipient,
121
+ "routing_basis": "authoritative_process_boundary",
122
+ },
123
+ )
124
+
76
125
  def model_call(self, call_id: str | int, agent: EntityRef | None, model_id: str | int, *, model_name: str | None = None, request: Any | None = None, response: Any | None = None, status: str = "request", task: EntityRef | None = None, **attributes: Any) -> EntityRef:
77
126
  model = self.model(model_id, name=model_name, provider="camel", **attributes)
78
127
  call = self.entity("model_call", call_id, name="CAMEL model call", attributes={"provider": "camel"})
@@ -103,7 +152,7 @@ class CAMELAdapter(FrameworkAdapter):
103
152
  source = self._agents.get(str(worker_id)) if worker_id is not None else None
104
153
  target_id = _value(payload, "target_worker_id", "recipient_worker_id", "target_agent_id", "recipient_agent_id", "receiver_id")
105
154
  target = self._agents.get(str(target_id)) if target_id is not None else None
106
- return self.message(
155
+ message = self.message(
107
156
  message_id,
108
157
  source,
109
158
  target,
@@ -116,6 +165,14 @@ class CAMELAdapter(FrameworkAdapter):
116
165
  "message_id_source": "provider" if native_message_id is not None else "execweave_derived",
117
166
  },
118
167
  )
168
+ if source is None or target is None:
169
+ self.message_unrouted(
170
+ message,
171
+ callback_name=name,
172
+ missing_sender=source is None,
173
+ missing_recipient=target is None,
174
+ )
175
+ return message
119
176
  if name == "log_task_decomposed":
120
177
  parent_key = _native(payload, "parent_task_id", "task_id", "id")
121
178
  parent = self._tasks.get(str(parent_key)) or self.task_created(parent_key)
@@ -136,7 +193,11 @@ class CAMELAdapter(FrameworkAdapter):
136
193
  if name == "log_worker_created":
137
194
  return self.agent_created(_native(payload, "worker_id", "id", "name"), name=_string(_value(payload, "name", "role")), role=_string(_value(payload, "role", "worker_type")))
138
195
  if name == "log_task_created":
139
- return self.task_created(_native(payload, "task_id", "id", "name"), name=_string(_value(payload, "name", "description")))
196
+ task_key = _native(payload, "task_id", "id", "name")
197
+ existing = self._tasks.get(str(task_key))
198
+ if existing is not None:
199
+ return existing
200
+ return self.task_created(task_key, name=_string(_value(payload, "name", "description")))
140
201
  if name == "log_task_assigned":
141
202
  task_key = _native(payload, "task_id", "id", "name")
142
203
  task = self._tasks.get(str(task_key)) or self.task_created(task_key)
@@ -49,6 +49,12 @@ def _iso_timestamp(value: float) -> str:
49
49
 
50
50
 
51
51
  def _decode_quoted(value: str) -> str:
52
+ # Synthetic Windows traces carry native drive paths with single
53
+ # backslashes (for example ``C:\\tmp``). Treating those as Python string
54
+ # escapes turns ``\\t`` into a tab and corrupts the observed path. Real
55
+ # Linux strace paths still use the normal C-style decoding below.
56
+ if re.match(r"^[A-Za-z]:[\\/]", value):
57
+ return value.replace(r'\"', '"').replace(r"\\", "\\")
52
58
  try:
53
59
  return str(ast.literal_eval(f'"{value}"'))
54
60
  except (SyntaxError, ValueError):
@@ -372,6 +372,10 @@ function execweaveNodeCardsBase(node){
372
372
  add('Command',a.command);
373
373
  add('Working directory',a.cwd);
374
374
  add('Backend',a.backend);
375
+ }else if(kind==='task'){
376
+ add('Task',a.task_prompt||a.prompt||a.description||node?.name);
377
+ add('Prompt',a.task_prompt||a.prompt||a.description);
378
+ add('Provider',a.provider);
375
379
  }else if(kind==='network_endpoint'){
376
380
  const endpoints=Array.isArray(a.endpoints)?a.endpoints:[];
377
381
  if(endpoints.length){
File without changes
File without changes
File without changes