pi-durable-python 1.3.0__py3-none-any.whl

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 (90) hide show
  1. pi_durable/__init__.py +320 -0
  2. pi_durable/context.py +328 -0
  3. pi_durable/delta.py +269 -0
  4. pi_durable/documents.py +366 -0
  5. pi_durable/entries.py +66 -0
  6. pi_durable/env/__init__.py +408 -0
  7. pi_durable/env/decode.py +48 -0
  8. pi_durable/env/line_scan.py +190 -0
  9. pi_durable/env/posix.py +1547 -0
  10. pi_durable/errors.py +89 -0
  11. pi_durable/harness/__init__.py +1 -0
  12. pi_durable/harness/agent.py +344 -0
  13. pi_durable/harness/compaction.py +673 -0
  14. pi_durable/harness/context.py +515 -0
  15. pi_durable/harness/define.py +111 -0
  16. pi_durable/harness/events.py +766 -0
  17. pi_durable/harness/generation.py +1079 -0
  18. pi_durable/harness/harness.py +570 -0
  19. pi_durable/harness/inbox.py +255 -0
  20. pi_durable/harness/live.py +374 -0
  21. pi_durable/harness/output.py +467 -0
  22. pi_durable/harness/prompt.py +288 -0
  23. pi_durable/harness/provider.py +78 -0
  24. pi_durable/harness/registry.py +136 -0
  25. pi_durable/harness/scheduler.py +1977 -0
  26. pi_durable/harness/submissions.py +357 -0
  27. pi_durable/harness/task_graph.py +334 -0
  28. pi_durable/harness/tool.py +1365 -0
  29. pi_durable/harness/types.py +772 -0
  30. pi_durable/harness/usage.py +88 -0
  31. pi_durable/harness/util.py +204 -0
  32. pi_durable/harness/validation.py +460 -0
  33. pi_durable/harness/view.py +324 -0
  34. pi_durable/ids.py +63 -0
  35. pi_durable/json.py +186 -0
  36. pi_durable/providers/__init__.py +362 -0
  37. pi_durable/providers/anthropic.py +603 -0
  38. pi_durable/providers/base.py +97 -0
  39. pi_durable/providers/json_parse.py +117 -0
  40. pi_durable/providers/openai.py +574 -0
  41. pi_durable/providers/request.py +35 -0
  42. pi_durable/providers/retry.py +127 -0
  43. pi_durable/providers/stream.py +183 -0
  44. pi_durable/providers/transcript.py +224 -0
  45. pi_durable/providers/usage.py +58 -0
  46. pi_durable/py.typed +0 -0
  47. pi_durable/search.py +115 -0
  48. pi_durable/session/__init__.py +5 -0
  49. pi_durable/session/drafts.py +762 -0
  50. pi_durable/session/forks.py +109 -0
  51. pi_durable/session/observation.py +374 -0
  52. pi_durable/session/session.py +1193 -0
  53. pi_durable/session/transaction.py +1088 -0
  54. pi_durable/storage/__init__.py +5 -0
  55. pi_durable/storage/jsonl/__init__.py +15 -0
  56. pi_durable/storage/jsonl/storage.py +958 -0
  57. pi_durable/storage/memory.py +889 -0
  58. pi_durable/storage/scan.py +57 -0
  59. pi_durable/storage/sqlite/__init__.py +26 -0
  60. pi_durable/storage/sqlite/database.py +62 -0
  61. pi_durable/storage/sqlite/migrations.py +191 -0
  62. pi_durable/storage/sqlite/posix.py +314 -0
  63. pi_durable/storage/sqlite/schema.py +97 -0
  64. pi_durable/storage/sqlite/storage.py +1130 -0
  65. pi_durable/tasks.py +89 -0
  66. pi_durable/testing/__init__.py +41 -0
  67. pi_durable/testing/assertions.py +44 -0
  68. pi_durable/testing/env_conformance.py +828 -0
  69. pi_durable/testing/runner.py +64 -0
  70. pi_durable/testing/storage_conformance.py +2008 -0
  71. pi_durable/testing/types.py +99 -0
  72. pi_durable/tool_search/__init__.py +159 -0
  73. pi_durable/tools/__init__.py +81 -0
  74. pi_durable/tools/_values.py +43 -0
  75. pi_durable/tools/bash.py +250 -0
  76. pi_durable/tools/edit.py +214 -0
  77. pi_durable/tools/edit_diff.py +452 -0
  78. pi_durable/tools/env.py +19 -0
  79. pi_durable/tools/file_mutation_queue.py +68 -0
  80. pi_durable/tools/image.py +248 -0
  81. pi_durable/tools/image_processor.py +77 -0
  82. pi_durable/tools/path_utils.py +111 -0
  83. pi_durable/tools/read.py +506 -0
  84. pi_durable/tools/write.py +71 -0
  85. pi_durable/truncate.py +185 -0
  86. pi_durable/types.py +1297 -0
  87. pi_durable_python-1.3.0.dist-info/METADATA +276 -0
  88. pi_durable_python-1.3.0.dist-info/RECORD +90 -0
  89. pi_durable_python-1.3.0.dist-info/WHEEL +4 -0
  90. pi_durable_python-1.3.0.dist-info/licenses/LICENSE +21 -0
pi_durable/tasks.py ADDED
@@ -0,0 +1,89 @@
1
+ """Executable durable task definitions.
2
+
3
+ The Session only needs the definition's initial checkpoint and persisted identity; the Harness
4
+ later schedules the phase map. Keeping the token here, in the kernel layer, lets transactions
5
+ create tasks without importing the harness.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from collections.abc import Callable, Mapping
11
+ from dataclasses import dataclass
12
+ from typing import Any, Generic, TypeVar
13
+
14
+ InputT = TypeVar("InputT")
15
+ S = TypeVar("S")
16
+ R = TypeVar("R")
17
+ H = TypeVar("H")
18
+
19
+
20
+ @dataclass(frozen=True, slots=True)
21
+ class TaskDefinition(Generic[InputT, S, R, H]):
22
+ """Definition fields persisted and used when a task is created or recovered."""
23
+
24
+ name: str
25
+ version: int
26
+ initial: Callable[[InputT], S]
27
+ phases: Mapping[str, Any]
28
+ abort: Callable[..., Any]
29
+ migrate: Callable[..., Any] | None = None
30
+ hooks: H | None = None
31
+
32
+ def __getitem__(self, key: str) -> Any:
33
+ return getattr(self, key)
34
+
35
+
36
+ @dataclass(frozen=True, slots=True)
37
+ class Task(Generic[InputT, S, R, H]):
38
+ """Typed executable task token."""
39
+
40
+ definition: TaskDefinition[InputT, S, R, H]
41
+
42
+
43
+ def _values(definition: Mapping[str, Any] | None, kwargs: Mapping[str, Any]) -> dict[str, Any]:
44
+ values = dict(definition or {})
45
+ values.update(kwargs)
46
+ return values
47
+
48
+
49
+ def define_task(
50
+ definition: Mapping[str, Any] | None = None,
51
+ /,
52
+ **kwargs: Any,
53
+ ) -> Task[Any, Any, Any, Any]:
54
+ """Define an executable task; register it later with a Harness registry."""
55
+
56
+ values = _values(definition, kwargs)
57
+ name = values.get("name")
58
+ if not isinstance(name, str) or not name:
59
+ raise TypeError("Task name must be a non-empty string")
60
+ version = values.get("version")
61
+ if not isinstance(version, int) or isinstance(version, bool) or version < 1:
62
+ raise TypeError(f"Task {name} version must be a positive integer")
63
+ initial = values.get("initial")
64
+ if not callable(initial):
65
+ raise TypeError(f"Task {name} requires an initial() function")
66
+ phases = values.get("phases")
67
+ if not isinstance(phases, Mapping):
68
+ raise TypeError(f"Task {name} requires a phases mapping")
69
+ abort = values.get("abort")
70
+ if not callable(abort):
71
+ raise TypeError(f"Task {name} requires an abort() function")
72
+ migrate = values.get("migrate")
73
+ if migrate is not None and not callable(migrate):
74
+ raise TypeError(f"Task {name} migrate must be callable")
75
+ return Task(
76
+ TaskDefinition(
77
+ name=name,
78
+ version=version,
79
+ initial=initial,
80
+ phases=phases,
81
+ abort=abort,
82
+ migrate=migrate,
83
+ hooks=values.get("hooks"),
84
+ )
85
+ )
86
+
87
+
88
+
89
+ __all__ = ["Task", "TaskDefinition", "define_task"]
@@ -0,0 +1,41 @@
1
+ """Conformance and test helpers for storage backends.
2
+
3
+ The suite is runner independent: :func:`create_storage_conformance` returns cases and
4
+ :func:`register_storage_conformance` registers them with a Vitest/Jest-compatible runner.
5
+ Benchmark helpers are deliberately excluded (see ``PARITY.md``).
6
+ """
7
+
8
+ from .assertions import create_expect_assertions
9
+ from .env_conformance import create_env_conformance
10
+ from .runner import register_env_conformance, register_storage_conformance
11
+ from .storage_conformance import create_storage_conformance
12
+ from .types import (
13
+ EnvConformanceAssertions,
14
+ EnvConformanceCase,
15
+ EnvConformanceOptions,
16
+ EnvConformanceProvider,
17
+ ExpectLike,
18
+ StorageConformanceAssertions,
19
+ StorageConformanceCase,
20
+ StorageConformanceOptions,
21
+ StorageConformanceProvider,
22
+ StorageConformanceRunner,
23
+ )
24
+
25
+ __all__ = [
26
+ "EnvConformanceAssertions",
27
+ "EnvConformanceCase",
28
+ "EnvConformanceOptions",
29
+ "EnvConformanceProvider",
30
+ "ExpectLike",
31
+ "StorageConformanceAssertions",
32
+ "StorageConformanceCase",
33
+ "StorageConformanceOptions",
34
+ "StorageConformanceProvider",
35
+ "StorageConformanceRunner",
36
+ "create_env_conformance",
37
+ "create_expect_assertions",
38
+ "create_storage_conformance",
39
+ "register_env_conformance",
40
+ "register_storage_conformance",
41
+ ]
@@ -0,0 +1,44 @@
1
+ """Adapter from a Vitest/Jest-style ``expect`` to the conformance assertion vocabulary.
2
+
3
+ The adapter imports neither runner: it calls the snake_case matcher operations of a compatible
4
+ ``expect`` callable, so translated suites can supply pytest-backed assertions without changing
5
+ the conformance cases.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from collections.abc import Awaitable
11
+
12
+ from .types import ExpectLike, StorageConformanceAssertions
13
+
14
+
15
+ class _Assertions:
16
+ def __init__(self, expect: ExpectLike) -> None:
17
+ self._expect = expect
18
+
19
+ def ok(self, value: object, message: str | None = None) -> None:
20
+ self._expect(value, message).to_be_truthy()
21
+
22
+ def strict_equal(self, actual: object, expected: object) -> None:
23
+ self._expect(actual, None).to_be(expected)
24
+
25
+ def deep_equal(self, actual: object, expected: object) -> None:
26
+ self._expect(actual, None).to_equal(expected)
27
+
28
+ def partial_deep_equal(self, actual: object, expected: object) -> None:
29
+ self._expect(actual, None).to_match_object(expected)
30
+
31
+ def greater_than(self, actual: float, expected: float) -> None:
32
+ self._expect(actual, None).to_be_greater_than(expected)
33
+
34
+ async def rejects(self, operation: Awaitable[object], message_includes: str) -> None:
35
+ await self._expect(operation, None).rejects.to_throw(message_includes)
36
+
37
+
38
+ def create_expect_assertions(expect: ExpectLike) -> StorageConformanceAssertions:
39
+ """Adapt a runner's ``expect`` to :class:`StorageConformanceAssertions` without importing it."""
40
+
41
+ return _Assertions(expect)
42
+
43
+
44
+ __all__ = ["create_expect_assertions"]