prefactor-core 0.2.3__tar.gz → 0.2.4__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 (32) hide show
  1. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/PKG-INFO +1 -1
  2. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/_version.py +1 -1
  3. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/client.py +1 -0
  4. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/managers/agent_instance.py +20 -3
  5. prefactor_core-0.2.4/tests/test_agent_instance_finish_status.py +104 -0
  6. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/.gitignore +0 -0
  7. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/README.md +0 -0
  8. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/examples/agent_e2e.py +0 -0
  9. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/pyproject.toml +0 -0
  10. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/__init__.py +0 -0
  11. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/config.py +0 -0
  12. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/context_stack.py +0 -0
  13. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/exceptions.py +0 -0
  14. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/managers/__init__.py +0 -0
  15. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/managers/span.py +0 -0
  16. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/models.py +0 -0
  17. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/operations.py +0 -0
  18. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/queue/__init__.py +0 -0
  19. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/queue/base.py +0 -0
  20. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/queue/executor.py +0 -0
  21. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/queue/memory.py +0 -0
  22. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/schema_registry.py +0 -0
  23. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/span_context.py +0 -0
  24. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/src/prefactor_core/utils.py +0 -0
  25. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/tests/test_client.py +0 -0
  26. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/tests/test_failure_handling.py +0 -0
  27. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/tests/test_imports.py +0 -0
  28. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/tests/test_queue.py +0 -0
  29. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/tests/test_sdk_header.py +0 -0
  30. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/tests/test_span_context.py +0 -0
  31. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/tests/test_span_manager.py +0 -0
  32. {prefactor_core-0.2.3 → prefactor_core-0.2.4}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: prefactor-core
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Core Prefactor SDK with async queue-based operations
5
5
  Author-email: Prefactor Pty Ltd <josh@prefactor.tech>
6
6
  License: MIT
@@ -3,5 +3,5 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  PACKAGE_NAME = "prefactor-core"
6
- __version__ = "0.2.3"
6
+ __version__ = "0.2.4"
7
7
  PACKAGE_VERSION = __version__
@@ -274,6 +274,7 @@ class PrefactorCoreClient:
274
274
  elif operation.type == OperationType.FINISH_AGENT_INSTANCE:
275
275
  await self._http.agent_instances.finish(
276
276
  agent_instance_id=operation.payload["instance_id"],
277
+ status=operation.payload.get("status", "complete"),
277
278
  timestamp=operation.timestamp,
278
279
  idempotency_key=operation.payload.get("idempotency_key"),
279
280
  )
@@ -14,6 +14,7 @@ from ..utils import generate_idempotency_key
14
14
 
15
15
  if TYPE_CHECKING:
16
16
  from prefactor_http.client import PrefactorHttpClient
17
+ from prefactor_http.models.types import FinishStatus
17
18
 
18
19
  from ..client import PrefactorCoreClient
19
20
 
@@ -115,20 +116,30 @@ class AgentInstanceManager:
115
116
 
116
117
  await self._enqueue(operation)
117
118
 
118
- async def finish(self, instance_id: str) -> None:
119
+ async def finish(
120
+ self,
121
+ instance_id: str,
122
+ status: "FinishStatus" = "complete",
123
+ ) -> None:
119
124
  """Mark an instance as finished.
120
125
 
121
126
  Queues a finish operation for the instance.
122
127
 
123
128
  Args:
124
129
  instance_id: The ID of the instance to finish.
130
+ status: Terminal status for the instance. Defaults to ``"complete"``.
125
131
  """
126
- await self.finish_with_idempotency_key(instance_id, generate_idempotency_key())
132
+ await self.finish_with_idempotency_key(
133
+ instance_id,
134
+ generate_idempotency_key(),
135
+ status=status,
136
+ )
127
137
 
128
138
  async def finish_with_idempotency_key(
129
139
  self,
130
140
  instance_id: str,
131
141
  idempotency_key: str,
142
+ status: "FinishStatus" = "complete",
132
143
  ) -> None:
133
144
  """Queue a finish operation using a stable idempotency key."""
134
145
  operation = Operation(
@@ -136,6 +147,7 @@ class AgentInstanceManager:
136
147
  payload={
137
148
  "instance_id": instance_id,
138
149
  "idempotency_key": idempotency_key,
150
+ "status": status,
139
151
  },
140
152
  timestamp=datetime.now(timezone.utc),
141
153
  )
@@ -199,16 +211,21 @@ class AgentInstanceHandle:
199
211
  self._start_idempotency_key,
200
212
  )
201
213
 
202
- async def finish(self) -> None:
214
+ async def finish(self, status: "FinishStatus" = "complete") -> None:
203
215
  """Mark the instance as finished.
204
216
 
205
217
  This queues a finish operation for the instance.
218
+
219
+ Args:
220
+ status: Terminal status for the instance — one of ``"complete"``,
221
+ ``"failed"``, or ``"cancelled"``. Defaults to ``"complete"``.
206
222
  """
207
223
  manager = self._client.instance_manager
208
224
  assert manager is not None
209
225
  await manager.finish_with_idempotency_key(
210
226
  self._instance_id,
211
227
  self._finish_idempotency_key,
228
+ status=status,
212
229
  )
213
230
 
214
231
  async def create_span(
@@ -0,0 +1,104 @@
1
+ """Tests for AgentInstanceHandle.finish() accepting an optional status.
2
+
3
+ See GitHub issue prefactordev/python-sdk#13.
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ from types import SimpleNamespace
9
+ from unittest.mock import patch
10
+
11
+ import pytest
12
+ from prefactor_core import PrefactorCoreClient
13
+ from prefactor_core.config import PrefactorCoreConfig, QueueConfig
14
+ from prefactor_http.config import HttpClientConfig
15
+
16
+
17
+ class _StubAgentInstances:
18
+ def __init__(self) -> None:
19
+ self.finish_calls: list[dict] = []
20
+
21
+ async def register(self, **kwargs):
22
+ return SimpleNamespace(id=kwargs.get("id") or "inst-1")
23
+
24
+ async def start(self, **kwargs):
25
+ return SimpleNamespace(id=kwargs["agent_instance_id"])
26
+
27
+ async def finish(self, **kwargs):
28
+ self.finish_calls.append(kwargs)
29
+ return SimpleNamespace(id=kwargs["agent_instance_id"])
30
+
31
+
32
+ class _StubAgentSpans:
33
+ async def create(self, **kwargs):
34
+ return SimpleNamespace(id="span-1")
35
+
36
+ async def finish(self, **kwargs):
37
+ return SimpleNamespace(id=kwargs["agent_span_id"])
38
+
39
+
40
+ class _StubHttpClient:
41
+ def __init__(
42
+ self,
43
+ *_args,
44
+ agent_instances: _StubAgentInstances | None = None,
45
+ **_kwargs,
46
+ ) -> None:
47
+ self.agent_instances = agent_instances or _StubAgentInstances()
48
+ self.agent_spans = _StubAgentSpans()
49
+
50
+ async def __aenter__(self):
51
+ return self
52
+
53
+ async def __aexit__(self, exc_type, exc, tb):
54
+ return None
55
+
56
+
57
+ def _make_client_config() -> PrefactorCoreConfig:
58
+ return PrefactorCoreConfig(
59
+ http_config=HttpClientConfig(
60
+ api_url="https://api.test.com",
61
+ api_token="test-token",
62
+ max_retries=0,
63
+ initial_retry_delay=0.01,
64
+ max_retry_delay=0.02,
65
+ ),
66
+ queue_config=QueueConfig(num_workers=1, max_retries=0),
67
+ )
68
+
69
+
70
+ @pytest.mark.asyncio
71
+ async def test_finish_without_status_defaults_to_complete():
72
+ """Default call to finish() should forward status='complete' to HTTP."""
73
+ stub_http = _StubHttpClient()
74
+
75
+ with patch("prefactor_core.client.PrefactorHttpClient", return_value=stub_http):
76
+ async with PrefactorCoreClient(_make_client_config()) as client:
77
+ instance = await client.create_agent_instance(
78
+ agent_id="agent-1",
79
+ agent_version={"name": "v1"},
80
+ agent_schema_version={"span_schemas": {}},
81
+ )
82
+ await instance.finish()
83
+
84
+ assert len(stub_http.agent_instances.finish_calls) == 1
85
+ assert stub_http.agent_instances.finish_calls[0].get("status") == "complete"
86
+
87
+
88
+ @pytest.mark.asyncio
89
+ @pytest.mark.parametrize("status", ["failed", "cancelled", "complete"])
90
+ async def test_finish_forwards_explicit_status(status):
91
+ """Explicit status on handle.finish() should reach the HTTP layer."""
92
+ stub_http = _StubHttpClient()
93
+
94
+ with patch("prefactor_core.client.PrefactorHttpClient", return_value=stub_http):
95
+ async with PrefactorCoreClient(_make_client_config()) as client:
96
+ instance = await client.create_agent_instance(
97
+ agent_id="agent-1",
98
+ agent_version={"name": "v1"},
99
+ agent_schema_version={"span_schemas": {}},
100
+ )
101
+ await instance.finish(status=status)
102
+
103
+ assert len(stub_http.agent_instances.finish_calls) == 1
104
+ assert stub_http.agent_instances.finish_calls[0]["status"] == status
File without changes