AbstractRuntime 0.4.10__tar.gz → 0.4.11__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 (298) hide show
  1. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/CHANGELOG.md +10 -0
  2. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/PKG-INFO +8 -8
  3. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/pyproject.toml +8 -8
  4. abstractruntime-0.4.11/release-notes.md +6 -0
  5. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/effect_handlers.py +43 -2
  6. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/llm_client.py +18 -2
  7. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/visual/executor.py +17 -6
  8. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_client_media_artifacts.py +8 -3
  9. abstractruntime-0.4.11/tests/test_media_artifact_resolution.py +66 -0
  10. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_multimodal_abstractcore_integration.py +8 -1
  11. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_session_attachments_registry_and_open_tool.py +9 -1
  12. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_media_nodes.py +18 -2
  13. abstractruntime-0.4.10/release-notes.md +0 -6
  14. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/.github/workflows/ci.yml +0 -0
  15. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/.github/workflows/release.yml +0 -0
  16. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/.gitignore +0 -0
  17. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/ACKNOWLEDGMENTS.md +0 -0
  18. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/CONTRIBUTING.md +0 -0
  19. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/LICENSE +0 -0
  20. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/README.md +0 -0
  21. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/ROADMAP.md +0 -0
  22. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/SECURITY.md +0 -0
  23. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/README.md +0 -0
  24. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/adr/0001_layered_coupling_with_abstractcore.md +0 -0
  25. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/adr/0002_execution_modes_local_remote_hybrid.md +0 -0
  26. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/adr/0003_provenance_tamper_evident_hash_chain.md +0 -0
  27. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/adr/README.md +0 -0
  28. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/api.md +0 -0
  29. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/architecture.md +0 -0
  30. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/README.md +0 -0
  31. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/001_runtime_kernel.md +0 -0
  32. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/002_persistence_and_ledger.md +0 -0
  33. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/003_wait_primitives.md +0 -0
  34. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/004_scheduler_driver.md +0 -0
  35. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/005_abstractcore_integration.md +0 -0
  36. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/006_snapshots_bookmarks.md +0 -0
  37. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/007_provenance_hash_chain.md +0 -0
  38. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/009_artifact_store.md +0 -0
  39. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/010_examples_and_composition.md +0 -0
  40. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/011_subworkflow_support.md +0 -0
  41. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/012_run_store_query_and_scheduler_support.md +0 -0
  42. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/013_effect_retries_and_idempotency.md +0 -0
  43. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/completed/016_runtime_aware_parameters.md +0 -0
  44. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/001_integrations_abstractcore.md +0 -0
  45. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/001_runtime_kernel.md +0 -0
  46. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/002_persistence_and_ledger.md +0 -0
  47. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/002_snapshots_bookmarks.md +0 -0
  48. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/003_provenance_ledger_chain.md +0 -0
  49. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/003_wait_resume_and_scheduler.md +0 -0
  50. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/004_effect_handlers_and_integrations.md +0 -0
  51. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/004_tests.md +0 -0
  52. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/005_docs_updates.md +0 -0
  53. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/005_examples_and_composition.md +0 -0
  54. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/006_ai_fingerprint_and_provenance.md +0 -0
  55. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/DEPRECATED_README.md +0 -0
  56. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/README.md +0 -0
  57. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/deprecated/abstractruntime_docs_final_02a7373b.plan.md +0 -0
  58. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/planned/008_signatures_and_keys.md +0 -0
  59. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/planned/014_remote_tool_worker_executor.md +0 -0
  60. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/planned/015_agent_integration_improvements.md +0 -0
  61. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/planned/017_limit_warnings_and_observability.md +0 -0
  62. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/planned/018_workspace_access_policy_for_media_and_tools.md +0 -0
  63. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/proposed/2026-05-08_runtime_gateway_env_namespace_cleanup.md +0 -0
  64. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/proposed/2026-05-08_runtime_gateway_install_boundary.md +0 -0
  65. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/backlog/proposed/2026-05-09_runtime_retention_and_purge_contract.md +0 -0
  66. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/evidence.md +0 -0
  67. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/faq.md +0 -0
  68. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/getting-started.md +0 -0
  69. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/integrations/abstractcore.md +0 -0
  70. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/limits.md +0 -0
  71. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/manual_testing.md +0 -0
  72. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/mcp-worker.md +0 -0
  73. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/proposal.md +0 -0
  74. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/provenance.md +0 -0
  75. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/snapshots.md +0 -0
  76. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/tools-comms.md +0 -0
  77. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/docs/workflow-bundles.md +0 -0
  78. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/emails.config.example.yaml +0 -0
  79. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/examples/01_hello_world.py +0 -0
  80. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/examples/02_ask_user.py +0 -0
  81. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/examples/03_wait_until.py +0 -0
  82. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/examples/04_multi_step.py +0 -0
  83. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/examples/05_persistence.py +0 -0
  84. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/examples/06_llm_integration.py +0 -0
  85. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/examples/07_react_agent.py +0 -0
  86. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/examples/README.md +0 -0
  87. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/llms-full.txt +0 -0
  88. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/llms.txt +0 -0
  89. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/mkdocs.yml +0 -0
  90. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/pytest.ini +0 -0
  91. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/__init__.py +0 -0
  92. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/core/__init__.py +0 -0
  93. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/core/config.py +0 -0
  94. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/core/event_keys.py +0 -0
  95. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/core/models.py +0 -0
  96. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/core/policy.py +0 -0
  97. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/core/runtime.py +0 -0
  98. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/core/spec.py +0 -0
  99. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/core/vars.py +0 -0
  100. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/evidence/__init__.py +0 -0
  101. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/evidence/recorder.py +0 -0
  102. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/history_bundle.py +0 -0
  103. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/identity/__init__.py +0 -0
  104. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/identity/fingerprint.py +0 -0
  105. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/__init__.py +0 -0
  106. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/__init__.py +0 -0
  107. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/constants.py +0 -0
  108. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/default_tools.py +0 -0
  109. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/embeddings_client.py +0 -0
  110. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/factory.py +0 -0
  111. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/logging.py +0 -0
  112. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/mcp_worker.py +0 -0
  113. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/observability.py +0 -0
  114. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/output_specs.py +0 -0
  115. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/session_attachments.py +0 -0
  116. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/summarizer.py +0 -0
  117. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/tool_executor.py +0 -0
  118. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractcore/workspace_scoped_tools.py +0 -0
  119. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractmemory/__init__.py +0 -0
  120. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/integrations/abstractmemory/effect_handlers.py +0 -0
  121. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/memory/__init__.py +0 -0
  122. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/memory/active_context.py +0 -0
  123. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/memory/active_memory.py +0 -0
  124. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/memory/compaction.py +0 -0
  125. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/memory/kg_packets.py +0 -0
  126. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/memory/memact_composer.py +0 -0
  127. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/memory/recall_levels.py +0 -0
  128. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/memory/token_budget.py +0 -0
  129. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/rendering/__init__.py +0 -0
  130. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/rendering/agent_trace_report.py +0 -0
  131. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/rendering/json_stringify.py +0 -0
  132. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/scheduler/__init__.py +0 -0
  133. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/scheduler/convenience.py +0 -0
  134. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/scheduler/registry.py +0 -0
  135. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/scheduler/scheduler.py +0 -0
  136. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/__init__.py +0 -0
  137. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/artifacts.py +0 -0
  138. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/base.py +0 -0
  139. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/commands.py +0 -0
  140. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/in_memory.py +0 -0
  141. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/json_files.py +0 -0
  142. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/ledger_chain.py +0 -0
  143. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/observable.py +0 -0
  144. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/offloading.py +0 -0
  145. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/snapshots.py +0 -0
  146. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/storage/sqlite.py +0 -0
  147. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/__init__.py +0 -0
  148. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/adapters/__init__.py +0 -0
  149. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/adapters/agent_adapter.py +0 -0
  150. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/adapters/context_adapter.py +0 -0
  151. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/adapters/control_adapter.py +0 -0
  152. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/adapters/effect_adapter.py +0 -0
  153. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/adapters/event_adapter.py +0 -0
  154. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/adapters/function_adapter.py +0 -0
  155. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/adapters/memact_adapter.py +0 -0
  156. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/adapters/subflow_adapter.py +0 -0
  157. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/adapters/variable_adapter.py +0 -0
  158. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/compiler.py +0 -0
  159. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/flow.py +0 -0
  160. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/visual/__init__.py +0 -0
  161. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/visual/agent_ids.py +0 -0
  162. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/visual/builtins.py +0 -0
  163. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/visual/code_executor.py +0 -0
  164. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/visual/models.py +0 -0
  165. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/visualflow_compiler/visual/multi_entry_lowering.py +0 -0
  166. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/workflow_bundle/__init__.py +0 -0
  167. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/workflow_bundle/models.py +0 -0
  168. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/workflow_bundle/packer.py +0 -0
  169. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/workflow_bundle/reader.py +0 -0
  170. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/src/abstractruntime/workflow_bundle/registry.py +0 -0
  171. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/README.md +0 -0
  172. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/conftest.py +0 -0
  173. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_active_context_policy.py +0 -0
  174. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_active_memory.py +0 -0
  175. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_answer_user_effect.py +0 -0
  176. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_artifacts.py +0 -0
  177. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_chat_summarizer_integration.py +0 -0
  178. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_command_store.py +0 -0
  179. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_compaction_helpers.py +0 -0
  180. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_control_adapter_while.py +0 -0
  181. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_default_tools_comms_gating.py +0 -0
  182. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_default_tools_include_skim_files.py +0 -0
  183. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_default_tools_include_skim_folders.py +0 -0
  184. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_default_tools_search_files_executor.py +0 -0
  185. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_durable_toolsets.py +0 -0
  186. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_e2e_tool_calls_idempotency_lmstudio.py +0 -0
  187. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_emit_event_without_workflow_registry.py +0 -0
  188. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_evidence_recorder.py +0 -0
  189. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_factory_timeouts_default_to_abstractcore_config.py +0 -0
  190. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_integration_abstractcore.py +0 -0
  191. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_integrations_abstractcore.py +0 -0
  192. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_json_file_run_store_children_index.py +0 -0
  193. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_jsonl_ledger_recovery.py +0 -0
  194. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_kg_learn_and_recall_contract.py +0 -0
  195. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_ledger_chain.py +0 -0
  196. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_ledger_subscription.py +0 -0
  197. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_call_media_artifact_refs.py +0 -0
  198. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_call_media_artifact_refs_persist_across_restart.py +0 -0
  199. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_call_media_uses_source_path_label.py +0 -0
  200. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_call_requires_prompt.py +0 -0
  201. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_call_response_schema_normalization.py +0 -0
  202. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_call_structured_output_fallback.py +0 -0
  203. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_call_truncation_retry_contract.py +0 -0
  204. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_call_use_context_appends_turn.py +0 -0
  205. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_call_verbatim_payload_capture.py +0 -0
  206. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_client_system_context.py +0 -0
  207. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_llm_client_tool_call_parsing.py +0 -0
  208. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_local_runtime_timeout_kwarg_policy.py +0 -0
  209. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_mcp_remote_tool_executor.py +0 -0
  210. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_mcp_worker_logging.py +0 -0
  211. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_mcp_worker_security.py +0 -0
  212. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_mcp_worker_stdio.py +0 -0
  213. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memact_composer_from_kg_result.py +0 -0
  214. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_kg_assert_attributes_defaults.py +0 -0
  215. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_kg_packets.py +0 -0
  216. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_kg_predicate_aliasing.py +0 -0
  217. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_kg_query_packetization_restart.py +0 -0
  218. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_kg_query_recall_level_policy.py +0 -0
  219. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_kg_semantic_query_ranking.py +0 -0
  220. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_note_effect.py +0 -0
  221. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_query_effect.py +0 -0
  222. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_query_rich_filters.py +0 -0
  223. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_scope_and_rehydrate_effect.py +0 -0
  224. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_memory_tag_effect.py +0 -0
  225. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_mlx_generation_serialization.py +0 -0
  226. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_offloading.py +0 -0
  227. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_packaging_extras.py +0 -0
  228. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_pause_resume.py +0 -0
  229. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_prompt_cache_modules.py +0 -0
  230. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_queryable_run_store.py +0 -0
  231. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_read_file_fallback_to_session_attachments.py +0 -0
  232. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_real_integration.py +0 -0
  233. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_recall_levels_policy.py +0 -0
  234. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_remote_llm_client.py +0 -0
  235. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_rendering_agent_trace_report.py +0 -0
  236. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_rendering_json_stringify.py +0 -0
  237. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_retry_idempotency.py +0 -0
  238. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_run_history_bundle.py +0 -0
  239. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_runtime_config_max_output_tokens_fallback.py +0 -0
  240. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_runtime_install_boundary.py +0 -0
  241. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_runtime_llm_call_grounding_in_ledger.py +0 -0
  242. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_runtime_node_traces.py +0 -0
  243. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_runtime_start_seeds_tool_support.py +0 -0
  244. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_scheduler.py +0 -0
  245. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_snapshots.py +0 -0
  246. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_sqlite_ledger_store.py +0 -0
  247. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_start_subworkflow_async_wait.py +0 -0
  248. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_start_subworkflow_inherit_context_merges_messages.py +0 -0
  249. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_start_subworkflow_workspace_inheritance.py +0 -0
  250. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_structured_output_schema_enum.py +0 -0
  251. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_subworkflow.py +0 -0
  252. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_terminal_effect_completion.py +0 -0
  253. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_terminal_resume_appends_ledger_completion.py +0 -0
  254. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tick_completion_includes_output_in_ledger.py +0 -0
  255. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tool_approval_executor.py +0 -0
  256. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tool_approval_resume_executes.py +0 -0
  257. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tool_calls_idempotency_keys.py +0 -0
  258. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tool_executor_argument_sanitization.py +0 -0
  259. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tool_executor_error_output_detection.py +0 -0
  260. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tool_executor_filename_alias.py +0 -0
  261. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tool_executor_kwarg_canonicalization.py +0 -0
  262. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tool_executor_read_file_aliases.py +0 -0
  263. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tool_executor_timeout.py +0 -0
  264. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_tool_wait_allowlist_safety.py +0 -0
  265. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_trace_context_propagation.py +0 -0
  266. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_vars_query_effect.py +0 -0
  267. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visual_agent_output_context_includes_messages.py +0 -0
  268. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visual_agent_tool_observations_persist_across_restart.py +0 -0
  269. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visual_agent_use_context_inherits_attachments.py +0 -0
  270. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visual_agent_use_context_persists_tool_observations.py +0 -0
  271. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visual_agent_use_context_persists_turn.py +0 -0
  272. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visual_llm_call_schema_ref_resolution.py +0 -0
  273. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visual_memact_compose_node.py +0 -0
  274. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visual_memory_kg_query_outputs_propagate.py +0 -0
  275. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visual_memory_kg_resolve_outputs_propagate.py +0 -0
  276. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visual_multi_entry_loop_overrides.py +0 -0
  277. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_add_message_builtin.py +0 -0
  278. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_add_message_node_appends_to_active_context.py +0 -0
  279. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_call_tool_node.py +0 -0
  280. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_compiler_basic.py +0 -0
  281. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_context_and_builder_nodes.py +0 -0
  282. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_get_element_node.py +0 -0
  283. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_get_random_element_node.py +0 -0
  284. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_has_tools_builtin.py +0 -0
  285. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_llm_call_context_attachments_map_to_media.py +0 -0
  286. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_llm_call_multimodal_output.py +0 -0
  287. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_make_object_node.py +0 -0
  288. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_memory_effect_nodes.py +0 -0
  289. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_memory_source_pins.py +0 -0
  290. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_prompt_only.py +0 -0
  291. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_random_nodes.py +0 -0
  292. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_string_contains_replace.py +0 -0
  293. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_visualflow_tool_parameters_node.py +0 -0
  294. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_wait_event_prompt_metadata.py +0 -0
  295. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_workflow_bundle_registry.py +0 -0
  296. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_workspace_policy_allowlist_mode.py +0 -0
  297. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_workspace_policy_mount_virtual_paths.py +0 -0
  298. {abstractruntime-0.4.10 → abstractruntime-0.4.11}/tests/test_workspace_policy_tool_calls_persist_across_restart.py +0 -0
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.11] - 2026-05-13
11
+
12
+ ### Fixed
13
+ - AbstractCore effect-handler media materialization now preserves artifact `content_type`, media `type`, artifact ids, and safe filename extensions instead of dropping artifact-backed media to bare paths. This keeps generated WAV artifacts valid for downstream transcription nodes.
14
+ - Added explicit MIME extension aliases for common generated media types such as `audio/wav`, `image/png`, and `video/mp4` so platform MIME table differences do not create extensionless temp files.
15
+
16
+ ### Changed
17
+ - Minimum AbstractCore optional dependency floor is now `abstractcore>=2.13.14`.
18
+
19
+
10
20
  ## [0.4.10] - 2026-05-12
11
21
 
12
22
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: AbstractRuntime
3
- Version: 0.4.10
3
+ Version: 0.4.11
4
4
  Summary: AbstractRuntime: a durable graph runner designed to pair with AbstractCore.
5
5
  Project-URL: AbstractCore (website), https://www.abstractcore.ai/
6
6
  Project-URL: AbstractRuntime (GitHub), https://github.com/lpalbou/abstractruntime
@@ -23,23 +23,23 @@ Requires-Python: >=3.10
23
23
  Requires-Dist: abstractmemory>=0.2.6
24
24
  Requires-Dist: abstractsemantics>=0.0.3
25
25
  Provides-Extra: abstractcore
26
- Requires-Dist: abstractcore>=2.13.13; extra == 'abstractcore'
26
+ Requires-Dist: abstractcore>=2.13.14; extra == 'abstractcore'
27
27
  Provides-Extra: all-apple
28
- Requires-Dist: abstractcore[all-apple]>=2.13.13; extra == 'all-apple'
28
+ Requires-Dist: abstractcore[all-apple]>=2.13.14; extra == 'all-apple'
29
29
  Provides-Extra: all-gpu
30
- Requires-Dist: abstractcore[all-gpu]>=2.13.13; extra == 'all-gpu'
30
+ Requires-Dist: abstractcore[all-gpu]>=2.13.14; extra == 'all-gpu'
31
31
  Provides-Extra: apple
32
- Requires-Dist: abstractcore[apple]>=2.13.13; extra == 'apple'
32
+ Requires-Dist: abstractcore[apple]>=2.13.14; extra == 'apple'
33
33
  Provides-Extra: docs
34
34
  Requires-Dist: mkdocs-material>=9.0.0; extra == 'docs'
35
35
  Requires-Dist: mkdocs>=1.6.0; extra == 'docs'
36
36
  Requires-Dist: pymdown-extensions>=10.0; extra == 'docs'
37
37
  Provides-Extra: gpu
38
- Requires-Dist: abstractcore[gpu]>=2.13.13; extra == 'gpu'
38
+ Requires-Dist: abstractcore[gpu]>=2.13.14; extra == 'gpu'
39
39
  Provides-Extra: mcp-worker
40
- Requires-Dist: abstractcore[tools]>=2.13.13; extra == 'mcp-worker'
40
+ Requires-Dist: abstractcore[tools]>=2.13.14; extra == 'mcp-worker'
41
41
  Provides-Extra: multimodal
42
- Requires-Dist: abstractcore[audio,media,openai,vision,voice]>=2.13.13; extra == 'multimodal'
42
+ Requires-Dist: abstractcore[audio,media,openai,vision,voice]>=2.13.14; extra == 'multimodal'
43
43
  Provides-Extra: test
44
44
  Requires-Dist: pytest>=7.0.0; extra == 'test'
45
45
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "AbstractRuntime"
7
- version = "0.4.10"
7
+ version = "0.4.11"
8
8
  description = "AbstractRuntime: a durable graph runner designed to pair with AbstractCore."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -46,34 +46,34 @@ dependencies = [
46
46
  [project.optional-dependencies]
47
47
  # Enables `abstractruntime.integrations.abstractcore.*` imports.
48
48
  abstractcore = [
49
- "abstractcore>=2.13.13",
49
+ "abstractcore>=2.13.14",
50
50
  ]
51
51
 
52
52
  apple = [
53
- "abstractcore[apple]>=2.13.13",
53
+ "abstractcore[apple]>=2.13.14",
54
54
  ]
55
55
 
56
56
  gpu = [
57
- "abstractcore[gpu]>=2.13.13",
57
+ "abstractcore[gpu]>=2.13.14",
58
58
  ]
59
59
 
60
60
  all-apple = [
61
- "abstractcore[all-apple]>=2.13.13",
61
+ "abstractcore[all-apple]>=2.13.14",
62
62
  ]
63
63
 
64
64
  all-gpu = [
65
- "abstractcore[all-gpu]>=2.13.13",
65
+ "abstractcore[all-gpu]>=2.13.14",
66
66
  ]
67
67
 
68
68
  # Enables AbstractCore multimodal generation helpers with common OpenAI-backed
69
69
  # image/voice capability packages.
70
70
  multimodal = [
71
- "abstractcore[media,openai,vision,voice,audio]>=2.13.13",
71
+ "abstractcore[media,openai,vision,voice,audio]>=2.13.14",
72
72
  ]
73
73
 
74
74
  # Enables `abstractruntime-mcp-worker` with the default toolsets (includes bs4/lxml).
75
75
  mcp-worker = [
76
- "abstractcore[tools]>=2.13.13",
76
+ "abstractcore[tools]>=2.13.14",
77
77
  ]
78
78
 
79
79
  # CI/test dependencies. The workflow runs the basic contract suite plus focused
@@ -0,0 +1,6 @@
1
+ ### Fixed
2
+ - AbstractCore effect-handler media materialization now preserves artifact `content_type`, media `type`, artifact ids, and safe filename extensions instead of dropping artifact-backed media to bare paths. This keeps generated WAV artifacts valid for downstream transcription nodes.
3
+ - Added explicit MIME extension aliases for common generated media types such as `audio/wav`, `image/png`, and `video/mp4` so platform MIME table differences do not create extensionless temp files.
4
+
5
+ ### Changed
6
+ - Minimum AbstractCore optional dependency floor is now `abstractcore>=2.13.14`.
@@ -63,6 +63,23 @@ def _guess_ext_from_content_type(content_type: str) -> str:
63
63
  ct = str(content_type or "").strip().lower()
64
64
  if not ct:
65
65
  return ""
66
+ explicit = {
67
+ "audio/wav": ".wav",
68
+ "audio/wave": ".wav",
69
+ "audio/x-wav": ".wav",
70
+ "audio/mpeg": ".mp3",
71
+ "audio/mp3": ".mp3",
72
+ "audio/ogg": ".ogg",
73
+ "audio/flac": ".flac",
74
+ "image/jpeg": ".jpg",
75
+ "image/jpg": ".jpg",
76
+ "image/png": ".png",
77
+ "image/webp": ".webp",
78
+ "video/mp4": ".mp4",
79
+ "video/quicktime": ".mov",
80
+ }
81
+ if ct in explicit:
82
+ return explicit[ct]
66
83
  ext = mimetypes.guess_extension(ct) or ""
67
84
  if ext == ".jpe":
68
85
  return ".jpg"
@@ -679,9 +696,21 @@ def _resolve_llm_call_media(
679
696
  raw_name = source_path or item.get("filename") or item.get("name")
680
697
  if isinstance(raw_name, str) and raw_name.strip():
681
698
  filename = raw_name.strip()
699
+ content_type = ""
700
+ if isinstance(item, dict):
701
+ for key in ("content_type", "mime_type", "mimeType", "mime"):
702
+ raw_ct = item.get(key)
703
+ if isinstance(raw_ct, str) and raw_ct.strip():
704
+ content_type = raw_ct.strip()
705
+ break
706
+ if not content_type:
707
+ raw_artifact_ct = getattr(artifact, "content_type", None)
708
+ if isinstance(raw_artifact_ct, str) and raw_artifact_ct.strip():
709
+ content_type = raw_artifact_ct.strip()
710
+
682
711
  ext = Path(filename).suffix if filename else ""
683
712
  if not ext:
684
- ct = str(getattr(getattr(artifact, "metadata", None), "content_type", "") or "")
713
+ ct = content_type or str(getattr(getattr(artifact, "metadata", None), "content_type", "") or "")
685
714
  ext = _guess_ext_from_content_type(ct)
686
715
 
687
716
  desired = source_path or filename or artifact_id
@@ -691,7 +720,19 @@ def _resolve_llm_call_media(
691
720
  p.write_bytes(bytes(content))
692
721
  except Exception as e:
693
722
  return None, f"Failed to materialize artifact '{artifact_id}': {e}"
694
- out.append(str(p))
723
+ resolved: Dict[str, Any] = {"file_path": str(p), "$artifact": str(artifact_id), "artifact_id": str(artifact_id)}
724
+ if content_type:
725
+ resolved["content_type"] = content_type
726
+ base_type = content_type.split(";", 1)[0].strip().lower()
727
+ if base_type.startswith("audio/"):
728
+ resolved["type"] = "audio"
729
+ elif base_type.startswith("image/"):
730
+ resolved["type"] = "image"
731
+ elif base_type.startswith("video/"):
732
+ resolved["type"] = "video"
733
+ elif base_type.startswith("text/"):
734
+ resolved["type"] = "text"
735
+ out.append(resolved)
695
736
 
696
737
  return (out or None), None
697
738
 
@@ -842,8 +842,24 @@ def _resolve_media_artifacts(
842
842
  file_path = ""
843
843
 
844
844
  if file_path:
845
- # Return a raw file path to trigger AutoMediaHandler processing.
846
- out.append(str(file_path))
845
+ # Preserve content type alongside the resolved path. Artifact stores
846
+ # often use extensionless content paths, so a raw path can lose the
847
+ # modality and make downstream transcription reject valid audio.
848
+ resolved: Dict[str, Any] = {"file_path": str(file_path)}
849
+ if content_type:
850
+ resolved["content_type"] = str(content_type)
851
+ base_type = str(content_type).split(";", 1)[0].strip().lower()
852
+ if base_type.startswith("audio/"):
853
+ resolved["type"] = "audio"
854
+ elif base_type.startswith("image/"):
855
+ resolved["type"] = "image"
856
+ elif base_type.startswith("video/"):
857
+ resolved["type"] = "video"
858
+ elif base_type.startswith("text/"):
859
+ resolved["type"] = "text"
860
+ resolved["artifact_id"] = str(aid)
861
+ resolved["$artifact"] = str(aid)
862
+ out.append(resolved)
847
863
  continue
848
864
 
849
865
  raise ValueError(f"Unable to resolve artifact '{aid}' to provider-ready media content.")
@@ -1580,8 +1580,8 @@ def visual_to_flow(visual: VisualFlow) -> Flow:
1580
1580
  output_spec["extra"] = dict(extra)
1581
1581
  image_provider = _nonempty_str(_input_or_config(payload, config, "image_provider", "imageProvider"))
1582
1582
  image_model = _nonempty_str(_input_or_config(payload, config, "image_model", "imageModel"))
1583
- legacy_provider = _nonempty_str(_input_or_config(payload, config, "provider"))
1584
- legacy_model = _nonempty_str(_input_or_config(payload, config, "model"))
1583
+ legacy_provider = _nonempty_str(config.get("provider"))
1584
+ legacy_model = _nonempty_str(config.get("model"))
1585
1585
  runtime_provider = _nonempty_str(
1586
1586
  _input_or_config(payload, config, "runtime_provider", "runtimeProvider", "llm_provider", "llmProvider")
1587
1587
  )
@@ -1622,8 +1622,12 @@ def visual_to_flow(visual: VisualFlow) -> Flow:
1622
1622
  value = _input_or_config(payload, config, key)
1623
1623
  if isinstance(value, str) and value.strip():
1624
1624
  output_spec[key] = value.strip()
1625
- tts_provider = _nonempty_str(_input_or_config(payload, config, "tts_provider", "ttsProvider", "provider"))
1626
- tts_model = _nonempty_str(_input_or_config(payload, config, "tts_model", "ttsModel", "model"))
1625
+ tts_provider = _nonempty_str(_input_or_config(payload, config, "tts_provider", "ttsProvider"))
1626
+ tts_model = _nonempty_str(_input_or_config(payload, config, "tts_model", "ttsModel"))
1627
+ if not tts_provider:
1628
+ tts_provider = _nonempty_str(config.get("provider"))
1629
+ if not tts_model:
1630
+ tts_model = _nonempty_str(config.get("model"))
1627
1631
  runtime_provider = _nonempty_str(
1628
1632
  _input_or_config(payload, config, "runtime_provider", "runtimeProvider", "llm_provider", "llmProvider")
1629
1633
  )
@@ -1665,8 +1669,12 @@ def visual_to_flow(visual: VisualFlow) -> Flow:
1665
1669
  value = _input_or_config(payload, config, key)
1666
1670
  if isinstance(value, str) and value.strip():
1667
1671
  output_spec[key] = value.strip()
1668
- stt_provider = _nonempty_str(_input_or_config(payload, config, "stt_provider", "sttProvider", "provider"))
1669
- stt_model = _nonempty_str(_input_or_config(payload, config, "stt_model", "sttModel", "model"))
1672
+ stt_provider = _nonempty_str(_input_or_config(payload, config, "stt_provider", "sttProvider"))
1673
+ stt_model = _nonempty_str(_input_or_config(payload, config, "stt_model", "sttModel"))
1674
+ if not stt_provider:
1675
+ stt_provider = _nonempty_str(config.get("provider"))
1676
+ if not stt_model:
1677
+ stt_model = _nonempty_str(config.get("model"))
1670
1678
  runtime_provider = _nonempty_str(
1671
1679
  _input_or_config(payload, config, "runtime_provider", "runtimeProvider", "llm_provider", "llmProvider")
1672
1680
  )
@@ -1709,6 +1717,9 @@ def visual_to_flow(visual: VisualFlow) -> Flow:
1709
1717
  language = _input_or_config(payload, config, "language")
1710
1718
  if isinstance(language, str) and language.strip():
1711
1719
  details["language"] = language.strip()
1720
+ stt_model = _nonempty_str(_input_or_config(payload, config, "stt_model", "sttModel", "model"))
1721
+ if stt_model:
1722
+ details["model"] = stt_model
1712
1723
  max_duration_s = _coerce_float(_input_or_config(payload, config, "max_duration_s", "maxDurationS"))
1713
1724
  if max_duration_s is not None:
1714
1725
  details["max_duration_s"] = max_duration_s
@@ -21,6 +21,11 @@ def test_resolve_media_artifact_creates_file_path() -> None:
21
21
  assert isinstance(resolved, list)
22
22
  assert resolved
23
23
  item = resolved[0]
24
- assert isinstance(item, str)
25
- assert os.path.exists(item)
26
- os.remove(item)
24
+ assert isinstance(item, dict)
25
+ assert item.get("$artifact") == meta.artifact_id
26
+ assert item.get("artifact_id") == meta.artifact_id
27
+ assert item.get("content_type") == "image/png"
28
+ assert item.get("type") == "image"
29
+ path = str(item.get("file_path") or "")
30
+ assert os.path.exists(path)
31
+ os.remove(path)
@@ -0,0 +1,66 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ def test_resolved_audio_artifact_preserves_content_type_for_transcription(tmp_path: Path) -> None:
7
+ from abstractcore.providers.base import BaseProvider
8
+ from abstractruntime.integrations.abstractcore.llm_client import _is_audio_media_item, _resolve_media_artifacts
9
+
10
+ content_path = tmp_path / "artifact-content-without-extension"
11
+ content_path.write_bytes(b"RIFF\x00\x00\x00\x00WAVE")
12
+
13
+ class Store:
14
+ def _content_path(self, artifact_id: str) -> Path:
15
+ assert artifact_id == "audio-1"
16
+ return content_path
17
+
18
+ resolved = _resolve_media_artifacts(
19
+ [{"$artifact": "audio-1", "content_type": "audio/wav"}],
20
+ artifact_store=Store(),
21
+ )
22
+
23
+ assert isinstance(resolved, list)
24
+ assert resolved == [
25
+ {
26
+ "$artifact": "audio-1",
27
+ "artifact_id": "audio-1",
28
+ "content_type": "audio/wav",
29
+ "file_path": str(content_path),
30
+ "type": "audio",
31
+ }
32
+ ]
33
+ assert _is_audio_media_item(resolved[0]) is True
34
+ assert BaseProvider._media_type(resolved[0]) == "audio"
35
+
36
+
37
+ def test_effect_handler_materialized_audio_artifact_preserves_content_type(tmp_path: Path) -> None:
38
+ from abstractcore.providers.base import BaseProvider
39
+ from abstractruntime.integrations.abstractcore.effect_handlers import _resolve_llm_call_media
40
+
41
+ class Artifact:
42
+ content = b"RIFF\x00\x00\x00\x00WAVE"
43
+ content_type = None
44
+ metadata = None
45
+
46
+ class Store:
47
+ def load(self, artifact_id: str) -> Artifact:
48
+ assert artifact_id == "audio-1"
49
+ return Artifact()
50
+
51
+ resolved, error = _resolve_llm_call_media(
52
+ [{"$artifact": "audio-1", "content_type": "audio/wav"}],
53
+ artifact_store=Store(),
54
+ temp_dir=tmp_path,
55
+ )
56
+
57
+ assert error is None
58
+ assert isinstance(resolved, list)
59
+ assert len(resolved) == 1
60
+ item = resolved[0]
61
+ assert item["$artifact"] == "audio-1"
62
+ assert item["artifact_id"] == "audio-1"
63
+ assert item["content_type"] == "audio/wav"
64
+ assert item["type"] == "audio"
65
+ assert Path(item["file_path"]).suffix == ".wav"
66
+ assert BaseProvider._media_type(item) == "audio"
@@ -205,7 +205,14 @@ def test_llm_call_allows_media_only_transcription_output_and_augments_output_spe
205
205
 
206
206
  assert state.output["llm"]["content"] == "transcribed text"
207
207
  assert seen["prompt"] == ""
208
- assert isinstance(seen["media"], list) and seen["media"][0].endswith(".wav")
208
+ assert isinstance(seen["media"], list)
209
+ media_item = seen["media"][0]
210
+ assert isinstance(media_item, dict)
211
+ assert media_item.get("$artifact") == meta.artifact_id
212
+ assert media_item.get("artifact_id") == meta.artifact_id
213
+ assert media_item.get("content_type") == "audio/wav"
214
+ assert media_item.get("type") == "audio"
215
+ assert str(media_item.get("file_path") or "").endswith(".wav")
209
216
  output = seen["params"]["output"]
210
217
  assert output["modality"] == "text"
211
218
  assert output["run_id"] == run_id
@@ -434,7 +434,15 @@ def test_tool_calls_open_attachment_binary_enqueues_pending_media_and_llm_call_c
434
434
  # Validate that the resolved media file exists during the call.
435
435
  media = kwargs.get("media")
436
436
  assert isinstance(media, list) and len(media) == 1
437
- p = Path(str(media[0]))
437
+ item = media[0]
438
+ if isinstance(item, dict):
439
+ assert item.get("$artifact") == meta.artifact_id
440
+ assert item.get("artifact_id") == meta.artifact_id
441
+ assert item.get("content_type") == "image/jpeg"
442
+ assert item.get("type") == "image"
443
+ p = Path(str(item.get("file_path") or ""))
444
+ else:
445
+ p = Path(str(item))
438
446
  assert p.exists()
439
447
  assert p.read_bytes() == content
440
448
  return {"content": "ok", "metadata": {}}
@@ -4,7 +4,7 @@ from abstractruntime.core.models import EffectType, RunState, RunStatus
4
4
  from abstractruntime.visualflow_compiler import compile_visualflow
5
5
 
6
6
 
7
- def _plan_for_node(node_type: str, effect_config: dict) -> object:
7
+ def _plan_for_node(node_type: str, effect_config: dict, input_data: dict | None = None) -> object:
8
8
  spec = compile_visualflow(
9
9
  {
10
10
  "id": f"vf_{node_type}",
@@ -27,7 +27,7 @@ def _plan_for_node(node_type: str, effect_config: dict) -> object:
27
27
  current_node="node",
28
28
  vars={"_temp": {}},
29
29
  )
30
- return spec.nodes["node"](run, None)
30
+ return spec.nodes["node"](run, input_data)
31
31
 
32
32
 
33
33
  def test_generate_image_node_compiles_to_llm_call_output_selector() -> None:
@@ -82,6 +82,20 @@ def test_generate_image_legacy_provider_model_stay_in_output_spec() -> None:
82
82
  assert output["model"] == "flux-test"
83
83
 
84
84
 
85
+ def test_generate_image_does_not_treat_runtime_provider_input_as_image_provider() -> None:
86
+ plan = _plan_for_node(
87
+ "generate_image",
88
+ {"prompt": "a horse", "image_model": "gpt-image-1-mini"},
89
+ {"provider": "lmstudio", "model": "chat-model"},
90
+ )
91
+
92
+ assert plan.effect is not None
93
+ payload = dict(plan.effect.payload or {})
94
+ output = dict(payload.get("output") or {})
95
+ assert "provider" not in output
96
+ assert output["model"] == "gpt-image-1-mini"
97
+
98
+
85
99
  def test_generate_voice_node_compiles_to_llm_call_tts_selector() -> None:
86
100
  plan = _plan_for_node(
87
101
  "generate_voice",
@@ -143,6 +157,7 @@ def test_listen_voice_node_compiles_to_voice_wait_event() -> None:
143
157
  "prompt": "Say your answer",
144
158
  "wait_key": "voice_answer",
145
159
  "language": "fr",
160
+ "stt_model": "whisper-test",
146
161
  "max_duration_s": 12,
147
162
  },
148
163
  )
@@ -156,4 +171,5 @@ def test_listen_voice_node_compiles_to_voice_wait_event() -> None:
156
171
  assert payload["allow_free_text"] is True
157
172
  assert details["input_mode"] == "voice"
158
173
  assert details["language"] == "fr"
174
+ assert details["model"] == "whisper-test"
159
175
  assert details["max_duration_s"] == 12.0
@@ -1,6 +0,0 @@
1
- ### Fixed
2
- - Generated media VisualFlow nodes now keep media model selection in the output spec and reserve LLM `provider`/`model` routing for explicit `runtime_provider`/`runtime_model` overrides.
3
- - Legacy `provider`/`model` pins on image, TTS, and STT media nodes remain accepted as media selector fallbacks for existing flows.
4
-
5
- ### Changed
6
- - Minimum AbstractCore optional dependency floor is now `abstractcore>=2.13.13` so generated media and audio catalog contracts stay aligned.