python-durable 0.2.0__tar.gz → 0.2.1__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 (23) hide show
  1. {python_durable-0.2.0 → python_durable-0.2.1}/PKG-INFO +1 -1
  2. {python_durable-0.2.0 → python_durable-0.2.1}/pyproject.toml +1 -1
  3. {python_durable-0.2.0 → python_durable-0.2.1}/src/durable/pydantic_ai.py +16 -2
  4. {python_durable-0.2.0 → python_durable-0.2.1}/tests/test_pydantic_ai.py +16 -0
  5. {python_durable-0.2.0 → python_durable-0.2.1}/.github/workflows/publish.yml +0 -0
  6. {python_durable-0.2.0 → python_durable-0.2.1}/.gitignore +0 -0
  7. {python_durable-0.2.0 → python_durable-0.2.1}/LICENSE +0 -0
  8. {python_durable-0.2.0 → python_durable-0.2.1}/README.md +0 -0
  9. {python_durable-0.2.0 → python_durable-0.2.1}/examples/approval.py +0 -0
  10. {python_durable-0.2.0 → python_durable-0.2.1}/examples/examples.py +0 -0
  11. {python_durable-0.2.0 → python_durable-0.2.1}/examples/in_memory_example.py +0 -0
  12. {python_durable-0.2.0 → python_durable-0.2.1}/examples/pydantic_ai_example.py +0 -0
  13. {python_durable-0.2.0 → python_durable-0.2.1}/examples/redis_example.py +0 -0
  14. {python_durable-0.2.0 → python_durable-0.2.1}/src/durable/__init__.py +0 -0
  15. {python_durable-0.2.0 → python_durable-0.2.1}/src/durable/backoff.py +0 -0
  16. {python_durable-0.2.0 → python_durable-0.2.1}/src/durable/context.py +0 -0
  17. {python_durable-0.2.0 → python_durable-0.2.1}/src/durable/redis_store.py +0 -0
  18. {python_durable-0.2.0 → python_durable-0.2.1}/src/durable/store.py +0 -0
  19. {python_durable-0.2.0 → python_durable-0.2.1}/src/durable/workflow.py +0 -0
  20. {python_durable-0.2.0 → python_durable-0.2.1}/tests/__init__.py +0 -0
  21. {python_durable-0.2.0 → python_durable-0.2.1}/tests/test_durable.py +0 -0
  22. {python_durable-0.2.0 → python_durable-0.2.1}/tests/test_redis_store.py +0 -0
  23. {python_durable-0.2.0 → python_durable-0.2.1}/tests/test_signals.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-durable
3
- Version: 0.2.0
3
+ Version: 0.2.1
4
4
  Summary: Lightweight workflow durability for Python — make any async workflow resumable after crashes with just a decorator.
5
5
  Project-URL: Repository, https://github.com/WillemDeGroef/python-durable
6
6
  Author: Willem
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-durable"
3
- version = "0.2.0"
3
+ version = "0.2.1"
4
4
  description = "Lightweight workflow durability for Python — make any async workflow resumable after crashes with just a decorator."
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -69,6 +69,20 @@ def _deserialize_messages(data: list[dict]) -> list[Any]:
69
69
  return result
70
70
 
71
71
 
72
+ def _serialize_run_result(result: Any) -> dict:
73
+ """Convert an agent RunResult to a JSON-serializable dict."""
74
+ output = result.output
75
+ # If output is a pydantic model, convert to dict
76
+ if hasattr(output, "model_dump"):
77
+ output = output.model_dump(mode="json")
78
+ data: dict[str, Any] = {"output": output}
79
+ try:
80
+ data["all_messages"] = _serialize_messages(result.all_messages())
81
+ except Exception:
82
+ data["all_messages"] = []
83
+ return data
84
+
85
+
72
86
  def _run_id_for_agent(agent_name: str, prompt: str, run_id: str | None) -> str:
73
87
  """Generate a deterministic run ID from the agent name and prompt."""
74
88
  if run_id:
@@ -207,7 +221,7 @@ class DurableAgent(Generic[AgentDepsT, OutputT]):
207
221
  step_id="agent-run",
208
222
  **kwargs,
209
223
  )
210
- return result
224
+ return _AgentRunResult(result)
211
225
 
212
226
  async def _do_model_request(
213
227
  self,
@@ -225,7 +239,7 @@ class DurableAgent(Generic[AgentDepsT, OutputT]):
225
239
  run_kwargs.update(kwargs)
226
240
 
227
241
  result = await self.agent.run(prompt, **run_kwargs)
228
- return _AgentRunResult(result)
242
+ return _serialize_run_result(result)
229
243
 
230
244
  async def _do_tool_call(
231
245
  self,
@@ -326,3 +326,19 @@ class TestIntegration:
326
326
  r2 = await durable.run("What is 6*7?", run_id="calc-1")
327
327
  assert r2.output == "42"
328
328
  assert agent.run.call_count == 1
329
+
330
+ async def test_durable_agent_with_sqlite_store(self, tmp_path):
331
+ """Ensure agent results are JSON-serializable for SQLiteStore."""
332
+ db_path = str(tmp_path / "test.db")
333
+ wf = Workflow("test-sqlite", db=db_path)
334
+
335
+ agent, _ = _mock_agent(output="serialized ok")
336
+ durable = DurableAgent(agent, wf, name="sqlite-agent")
337
+
338
+ r1 = await durable.run("Test prompt", run_id="sqlite-1")
339
+ assert r1.output == "serialized ok"
340
+ assert agent.run.call_count == 1
341
+
342
+ r2 = await durable.run("Test prompt", run_id="sqlite-1")
343
+ assert r2.output == "serialized ok"
344
+ assert agent.run.call_count == 1
File without changes
File without changes