harness-sdk-python 0.4.5__tar.gz → 0.6.0__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 (28) hide show
  1. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/PKG-INFO +2 -2
  2. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/README.md +1 -1
  3. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/pyproject.toml +1 -1
  4. harness_sdk_python-0.6.0/src/harness_sdk/__init__.py +4 -0
  5. harness_sdk_python-0.6.0/src/harness_sdk/linear_thread.py +52 -0
  6. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/src/harness_sdk/run_manager.py +187 -116
  7. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/run_helpers.py +63 -9
  8. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_batches.py +3 -3
  9. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_branch_anchor.py +2 -2
  10. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_edit_dispatched.py +5 -5
  11. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_edit_reload.py +8 -8
  12. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_enqueue.py +9 -9
  13. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_facade.py +3 -3
  14. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_input_required.py +57 -39
  15. harness_sdk_python-0.6.0/tests/test_linear_thread.py +122 -0
  16. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_meta.py +18 -18
  17. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_outcomes.py +8 -14
  18. harness_sdk_python-0.6.0/tests/test_prepare_hooks.py +167 -0
  19. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_rewind_during_run.py +8 -8
  20. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_run_leaf.py +54 -49
  21. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_settle.py +9 -20
  22. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_steer.py +6 -6
  23. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_stop_continue.py +81 -12
  24. harness_sdk_python-0.4.5/src/harness_sdk/__init__.py +0 -3
  25. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/.gitignore +0 -0
  26. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/src/harness_sdk/fenced_postgres.py +0 -0
  27. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_fenced_postgres.py +0 -0
  28. {harness_sdk_python-0.4.5 → harness_sdk_python-0.6.0}/tests/test_placement.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: harness-sdk-python
3
- Version: 0.4.5
3
+ Version: 0.6.0
4
4
  Summary: RunManager: the harness-sdk runs subsystem for Python Statewire hosts
5
5
  Project-URL: Repository, https://github.com/assistant-ui/harness-sdk
6
6
  License-Expression: MIT
@@ -23,7 +23,7 @@ class MyHost(Statewire):
23
23
  self.runs = RunManager(
24
24
  state=self.state,
25
25
  start=self._start,
26
- get_message_meta=self._get_message_meta,
26
+ thread=self._thread,
27
27
  create_task=self.create_task,
28
28
  capabilities=("rewind",),
29
29
  )
@@ -11,7 +11,7 @@ class MyHost(Statewire):
11
11
  self.runs = RunManager(
12
12
  state=self.state,
13
13
  start=self._start,
14
- get_message_meta=self._get_message_meta,
14
+ thread=self._thread,
15
15
  create_task=self.create_task,
16
16
  capabilities=("rewind",),
17
17
  )
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "harness-sdk-python"
3
- version = "0.4.5"
3
+ version = "0.6.0"
4
4
  description = "RunManager: the harness-sdk runs subsystem for Python Statewire hosts"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -0,0 +1,4 @@
1
+ from .linear_thread import linear_thread
2
+ from .run_manager import RunManager
3
+
4
+ __all__ = ["RunManager", "linear_thread"]
@@ -0,0 +1,52 @@
1
+ from dataclasses import dataclass
2
+ from typing import Any, Callable
3
+
4
+
5
+ @dataclass(frozen=True)
6
+ class LinearThread:
7
+ _messages: Callable[[], list[dict[str, Any]]]
8
+ _role: Callable[[dict[str, Any]], str]
9
+
10
+ async def get_message_meta(self, message_id: str | None) -> dict[str, Any] | None:
11
+ items = self._messages()
12
+ if message_id is None:
13
+ return {"isLeaf": not items}
14
+ for index, message in enumerate(items):
15
+ if message.get("id") == message_id:
16
+ return {
17
+ "parentId": items[index - 1].get("id") if index > 0 else None,
18
+ "role": self._role(message),
19
+ "isLeaf": index == len(items) - 1,
20
+ "onActiveBranch": True,
21
+ }
22
+ return None
23
+
24
+ async def get_leaf_message_id(self) -> str | None:
25
+ items = self._messages()
26
+ return items[-1].get("id") if items else None
27
+
28
+ async def get_message_child_id(self, parent_id: str) -> str | None:
29
+ """The id of the first non-tool message after parent_id; None when parent_id is unknown or only tools follow."""
30
+ items = self._messages()
31
+ index = next(
32
+ (i for i, m in enumerate(items) if m.get("id") == parent_id), None
33
+ )
34
+ if index is None:
35
+ return None
36
+ for message in items[index + 1 :]:
37
+ if message.get("type") != "tool":
38
+ return message.get("id")
39
+ return None
40
+
41
+
42
+ def linear_thread(
43
+ *,
44
+ messages: Callable[[], list[dict[str, Any]]],
45
+ role: Callable[[dict[str, Any]], str],
46
+ ) -> LinearThread:
47
+ """RunManager thread projection over a linear message list: ``messages`` returns the current list, ``role`` maps a message to its role."""
48
+ if not callable(messages):
49
+ raise TypeError("messages must be callable")
50
+ if not callable(role):
51
+ raise TypeError("role must be callable")
52
+ return LinearThread(messages, role)