whiletrue 0.1.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 (98) hide show
  1. whiletrue/__init__.py +0 -0
  2. whiletrue/__main__.py +3 -0
  3. whiletrue/abort.py +79 -0
  4. whiletrue/basics/__init__.py +99 -0
  5. whiletrue/basics/agent.py +249 -0
  6. whiletrue/basics/comments.py +113 -0
  7. whiletrue/basics/diff_size.py +80 -0
  8. whiletrue/basics/exec_.py +84 -0
  9. whiletrue/basics/history.py +117 -0
  10. whiletrue/basics/human.py +201 -0
  11. whiletrue/basics/json_source.py +35 -0
  12. whiletrue/basics/markdown_source.py +55 -0
  13. whiletrue/basics/process.py +99 -0
  14. whiletrue/basics/sessions.py +62 -0
  15. whiletrue/basics/set_.py +29 -0
  16. whiletrue/basics/shell.py +98 -0
  17. whiletrue/basics/wake.py +27 -0
  18. whiletrue/claude_code/__init__.py +58 -0
  19. whiletrue/claude_code/endpoint.py +143 -0
  20. whiletrue/claude_code/headless.py +181 -0
  21. whiletrue/claude_code/interactive.py +344 -0
  22. whiletrue/claude_code/learnings.py +32 -0
  23. whiletrue/claude_code/panes.py +164 -0
  24. whiletrue/claude_code/plugin/.claude-plugin/plugin.json +5 -0
  25. whiletrue/claude_code/plugin/hook.py +44 -0
  26. whiletrue/claude_code/plugin/hooks/hooks.json +81 -0
  27. whiletrue/claude_code/plugin/mcp_server.py +98 -0
  28. whiletrue/claude_code/session.py +345 -0
  29. whiletrue/claude_code/transcript.py +123 -0
  30. whiletrue/cli/__init__.py +15 -0
  31. whiletrue/cli/__main__.py +3 -0
  32. whiletrue/cli/app.py +550 -0
  33. whiletrue/cli/common.py +36 -0
  34. whiletrue/cli/gates.py +156 -0
  35. whiletrue/cli/ops.py +339 -0
  36. whiletrue/cli/panel.py +198 -0
  37. whiletrue/cli/registry.py +143 -0
  38. whiletrue/cli/templates.py +24 -0
  39. whiletrue/codex/__init__.py +14 -0
  40. whiletrue/codex/runner.py +243 -0
  41. whiletrue/control/__init__.py +38 -0
  42. whiletrue/control/chain.py +61 -0
  43. whiletrue/control/loop.py +139 -0
  44. whiletrue/control/map_.py +101 -0
  45. whiletrue/control/parallel.py +32 -0
  46. whiletrue/control/retry.py +100 -0
  47. whiletrue/control/sequence.py +40 -0
  48. whiletrue/control/switch.py +67 -0
  49. whiletrue/core/__init__.py +260 -0
  50. whiletrue/core/caps.py +139 -0
  51. whiletrue/core/comments.py +80 -0
  52. whiletrue/core/composite.py +140 -0
  53. whiletrue/core/config.py +461 -0
  54. whiletrue/core/context.py +177 -0
  55. whiletrue/core/duration.py +19 -0
  56. whiletrue/core/events.py +94 -0
  57. whiletrue/core/expr.py +85 -0
  58. whiletrue/core/history.py +83 -0
  59. whiletrue/core/lock.py +86 -0
  60. whiletrue/core/memory_store.py +352 -0
  61. whiletrue/core/module.py +146 -0
  62. whiletrue/core/outcomes.py +82 -0
  63. whiletrue/core/registry.py +129 -0
  64. whiletrue/core/replay.py +58 -0
  65. whiletrue/core/runner.py +98 -0
  66. whiletrue/core/runtime.py +538 -0
  67. whiletrue/core/source.py +45 -0
  68. whiletrue/core/store.py +207 -0
  69. whiletrue/core/template.py +60 -0
  70. whiletrue/core/validate.py +142 -0
  71. whiletrue/core/wake.py +117 -0
  72. whiletrue/core/workspace.py +55 -0
  73. whiletrue/git/__init__.py +31 -0
  74. whiletrue/git/modules.py +128 -0
  75. whiletrue/git/workspaces.py +77 -0
  76. whiletrue/github/__init__.py +30 -0
  77. whiletrue/github/client.py +269 -0
  78. whiletrue/github/filebacked.py +87 -0
  79. whiletrue/github/memory.py +96 -0
  80. whiletrue/github/plugin.py +343 -0
  81. whiletrue/github/specs.py +39 -0
  82. whiletrue/opencode/__init__.py +25 -0
  83. whiletrue/opencode/runner.py +186 -0
  84. whiletrue/py.typed +0 -0
  85. whiletrue/recipes/issue-loop.yaml +59 -0
  86. whiletrue/recipes/ralph.yaml +14 -0
  87. whiletrue/recipes/review-pass.yaml +27 -0
  88. whiletrue/recipes/review-respond.yaml +22 -0
  89. whiletrue/store_sqlite/__init__.py +6 -0
  90. whiletrue/store_sqlite/migrations.py +132 -0
  91. whiletrue/store_sqlite/sqlite_store.py +537 -0
  92. whiletrue/tmux/__init__.py +11 -0
  93. whiletrue/tmux/controller.py +197 -0
  94. whiletrue-0.1.0.dist-info/METADATA +48 -0
  95. whiletrue-0.1.0.dist-info/RECORD +98 -0
  96. whiletrue-0.1.0.dist-info/WHEEL +4 -0
  97. whiletrue-0.1.0.dist-info/entry_points.txt +2 -0
  98. whiletrue-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,101 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from typing import Any, cast
5
+
6
+ from pydantic import BaseModel, Field
7
+
8
+ from whiletrue.control.chain import run_chain
9
+ from whiletrue.core import (
10
+ CompositeContext,
11
+ ConfigIssue,
12
+ Emit,
13
+ PipelineNode,
14
+ Strategy,
15
+ ValidateContext,
16
+ define_strategy,
17
+ parse_expr,
18
+ )
19
+ from whiletrue.core.expr import ExprError
20
+ from whiletrue.core.module import PortValues
21
+
22
+ #: Variables a `map`/`switch` expression may use.
23
+ EXPR_VARIABLES = frozenset({"run", "item", "iter", "input"})
24
+
25
+
26
+ class MapConfig(BaseModel):
27
+ #: CEL expression yielding a list. Each element is `iter.value` for one pass over the children.
28
+ over: str = Field(min_length=1)
29
+ #: How many elements run at once (each pass gets its own `iter`). Results keep element order.
30
+ parallel: int = Field(default=1, ge=1)
31
+
32
+
33
+ def check_expr(name: str, source: str) -> list[ConfigIssue]:
34
+ try:
35
+ problems = parse_expr(source).check(EXPR_VARIABLES)
36
+ except ExprError as error:
37
+ problems = [str(error)]
38
+ return [ConfigIssue("error", f"`{name}`: {p}") for p in problems]
39
+
40
+
41
+ def _validate(config: MapConfig, _vctx: ValidateContext) -> list[ConfigIssue]:
42
+ return check_expr("map.over", config.over)
43
+
44
+
45
+ async def _run(
46
+ children: list[PipelineNode], input: PortValues, ctx: CompositeContext[MapConfig]
47
+ ) -> Emit:
48
+ scope = {**ctx.scope.snapshot(), "input": input.get("in")}
49
+ values = parse_expr(ctx.config.over).eval(scope)
50
+ if not isinstance(values, list):
51
+ return Emit("fail", {"error": f"`map.over` must be a list, got {type(values).__name__}"})
52
+ elements = cast(list[Any], values)
53
+ if ctx.config.parallel > 1:
54
+ return await _run_parallel(children, input, ctx, elements)
55
+ results: list[Any] = []
56
+ for index, value in enumerate(elements, start=1):
57
+ if ctx.signal.aborted:
58
+ return Emit("fail", {"error": "cancelled"})
59
+ ctx.scope.set("iter", {"index": index, "value": value, "previous": ""})
60
+ emit = await run_chain(children, input, ctx)
61
+ if emit.port != "ok":
62
+ return emit
63
+ results.append(emit.value)
64
+ return Emit("ok", results)
65
+
66
+
67
+ async def _run_parallel(
68
+ children: list[PipelineNode],
69
+ input: PortValues,
70
+ ctx: CompositeContext[MapConfig],
71
+ elements: list[Any],
72
+ ) -> Emit:
73
+ slots = asyncio.Semaphore(ctx.config.parallel)
74
+ stop = asyncio.Event()
75
+
76
+ async def one(index: int, value: Any) -> Emit | None:
77
+ async with slots:
78
+ if stop.is_set() or ctx.signal.aborted:
79
+ return None
80
+ scope = ctx.scope.child()
81
+ scope.set("iter", {"index": index, "value": value, "previous": ""})
82
+ emit = await run_chain(children, input, ctx, scope)
83
+ if emit.port != "ok":
84
+ stop.set()
85
+ return emit
86
+
87
+ emits = await asyncio.gather(*(one(i, v) for i, v in enumerate(elements, start=1)))
88
+ for emit in emits:
89
+ if emit is not None and emit.port != "ok":
90
+ return emit
91
+ if any(e is None for e in emits):
92
+ return Emit("fail", {"error": "cancelled"})
93
+ return Emit("ok", [e.value for e in emits if e is not None])
94
+
95
+
96
+ #: Runs the children once per element of `over` (one after another, or `parallel` at once) and
97
+ #: returns the list of results.
98
+ #: The first element that doesn't succeed stops the map and its outcome is returned.
99
+ map_strategy: Strategy[Any] = define_strategy(
100
+ Strategy(id="map", config=MapConfig, validate=_validate, run=_run)
101
+ )
@@ -0,0 +1,32 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from typing import Any
5
+
6
+ from whiletrue.core import (
7
+ CompositeContext,
8
+ Emit,
9
+ EmptyConfig,
10
+ PipelineNode,
11
+ Strategy,
12
+ define_strategy,
13
+ resolve_outcome,
14
+ )
15
+ from whiletrue.core.module import PortValues
16
+
17
+
18
+ async def _run(
19
+ children: list[PipelineNode], input: PortValues, ctx: CompositeContext[EmptyConfig]
20
+ ) -> Emit:
21
+ emits = await asyncio.gather(*(ctx.run(child, input) for child in children))
22
+ for emit in emits:
23
+ if resolve_outcome(emit.port, {}, ctx.policy).action != "continue":
24
+ return emit
25
+ return Emit("ok", [emit.value for emit in emits])
26
+
27
+
28
+ #: Runs every child at the same time on the same input and returns the list of their results in
29
+ #: order. If any child doesn't succeed, the first such outcome (in child order) is returned.
30
+ parallel_strategy: Strategy[Any] = define_strategy(
31
+ Strategy(id="parallel", config=EmptyConfig, run=_run)
32
+ )
@@ -0,0 +1,100 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ from typing import Any, Literal
5
+
6
+ from pydantic import BaseModel, PositiveFloat, PositiveInt
7
+
8
+ from whiletrue.control.chain import run_chain
9
+ from whiletrue.control.loop import describe
10
+ from whiletrue.core import (
11
+ CompositeContext,
12
+ ConfigIssue,
13
+ Emit,
14
+ PipelineNode,
15
+ Strategy,
16
+ ValidateContext,
17
+ define_strategy,
18
+ parse_duration,
19
+ )
20
+ from whiletrue.core.module import PortValues
21
+
22
+
23
+ class RetryConfig(BaseModel):
24
+ max: PositiveInt = 3
25
+ #: Delay before the second attempt, e.g. "2s". Grows by `factor` each further attempt.
26
+ backoff: str | int | float | None = None
27
+ factor: PositiveFloat = 1.0
28
+ #: Expose the previous failure as `{{iter.previous}}` to the next attempt.
29
+ feedback: bool = True
30
+ #: What happens when every attempt failed. Default: park the item for a human.
31
+ on_exhausted: Literal["needs_human", "fail"] = "needs_human"
32
+
33
+
34
+ def _validate(config: RetryConfig, _vctx: ValidateContext) -> list[ConfigIssue]:
35
+ if config.backoff is None:
36
+ return []
37
+ try:
38
+ parse_duration(config.backoff)
39
+ except ValueError as error:
40
+ return [ConfigIssue("error", f"`retry.backoff`: {error}")]
41
+ return []
42
+
43
+
44
+ async def _sleep(ctx: CompositeContext[Any], ms: float) -> None:
45
+ if ms <= 0:
46
+ return
47
+ waiter = asyncio.ensure_future(ctx.signal.wait())
48
+ try:
49
+ await asyncio.wait({waiter}, timeout=ms / 1000)
50
+ finally:
51
+ waiter.cancel()
52
+
53
+
54
+ async def _run(
55
+ children: list[PipelineNode], input: PortValues, ctx: CompositeContext[RetryConfig]
56
+ ) -> Emit:
57
+ cfg = ctx.config
58
+ delay = parse_duration(cfg.backoff) if cfg.backoff is not None else 0
59
+ last = Emit("ok")
60
+ for attempt in range(1, cfg.max + 1):
61
+ if ctx.signal.aborted:
62
+ return Emit("fail", {"error": "cancelled"})
63
+ previous = describe(last.value) if cfg.feedback and attempt > 1 else ""
64
+ ctx.scope.set("iter", {"index": attempt, "previous": previous, "value": None})
65
+ last = await run_chain(children, input, ctx)
66
+ if last.port != "fail":
67
+ return last
68
+ ctx.log("warn", f"retry attempt {attempt}/{cfg.max} failed", None)
69
+ if attempt < cfg.max:
70
+ await _sleep(ctx, delay * cfg.factor ** (attempt - 1))
71
+ error = {"error": f"retry gave up after {cfg.max} attempts", "last": last.value}
72
+ return Emit(cfg.on_exhausted, error)
73
+
74
+
75
+ #: Re-runs its children when they `fail`, up to `max` attempts, with optional backoff. Other
76
+ #: outcomes pass straight through. When attempts run out, the item is parked as `needs_human`
77
+ #: (or `fail` with `on_exhausted: fail`).
78
+ retry_strategy: Strategy[Any] = define_strategy(
79
+ Strategy(id="retry", config=RetryConfig, validate=_validate, run=_run)
80
+ )
81
+
82
+
83
+ class TryConfig(BaseModel):
84
+ #: Outcome to fire instead of `fail`: `skip` carries on with the previous value, `ok` yields
85
+ #: the error object as the value.
86
+ emit: Literal["skip", "ok"] = "skip"
87
+
88
+
89
+ async def _try(
90
+ children: list[PipelineNode], input: PortValues, ctx: CompositeContext[TryConfig]
91
+ ) -> Emit:
92
+ result = await run_chain(children, input, ctx)
93
+ if result.port != "fail" or ctx.signal.aborted:
94
+ return result
95
+ ctx.log("warn", "try swallowed a failure", {"error": describe(result.value)})
96
+ return Emit("ok", result.value) if ctx.config.emit == "ok" else Emit("skip")
97
+
98
+
99
+ #: Runs its children and turns a `fail` into `skip` (or `ok`) so optional steps never stop the item.
100
+ try_strategy: Strategy[Any] = define_strategy(Strategy(id="try", config=TryConfig, run=_try))
@@ -0,0 +1,40 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from whiletrue.control.chain import run_chain
6
+ from whiletrue.core import (
7
+ CompositeContext,
8
+ Emit,
9
+ EmptyConfig,
10
+ PipelineNode,
11
+ Strategy,
12
+ define_strategy,
13
+ )
14
+ from whiletrue.core.module import PortValues
15
+
16
+
17
+ async def _run(
18
+ children: list[PipelineNode], input: PortValues, ctx: CompositeContext[EmptyConfig]
19
+ ) -> Emit:
20
+ return await run_chain(children, input, ctx)
21
+
22
+
23
+ #: Runs children one after another; each `out` feeds the next `in`.
24
+ sequence_strategy: Strategy[Any] = define_strategy(
25
+ Strategy(id="sequence", chain=True, config=EmptyConfig, run=_run)
26
+ )
27
+
28
+
29
+ async def _tap(
30
+ children: list[PipelineNode], input: PortValues, ctx: CompositeContext[EmptyConfig]
31
+ ) -> Emit:
32
+ emit = await run_chain(children, input, ctx)
33
+ # On success the original input flows on, so a side branch (a fix) does not replace it.
34
+ return Emit("ok", input.get("in")) if emit.port == "ok" else emit
35
+
36
+
37
+ #: Runs children like `sequence`, then passes its own input through unchanged.
38
+ tap_strategy: Strategy[Any] = define_strategy(
39
+ Strategy(id="tap", chain=True, config=EmptyConfig, run=_tap)
40
+ )
@@ -0,0 +1,67 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from typing import Any
5
+
6
+ from pydantic import BaseModel, Field
7
+
8
+ from whiletrue.control.map_ import check_expr
9
+ from whiletrue.core import (
10
+ CompositeContext,
11
+ ConfigIssue,
12
+ Emit,
13
+ PipelineNode,
14
+ Strategy,
15
+ ValidateContext,
16
+ define_strategy,
17
+ parse_expr,
18
+ )
19
+ from whiletrue.core.module import PortValues
20
+
21
+
22
+ class SwitchConfig(BaseModel):
23
+ #: CEL expression; its value (strings as-is, anything else as JSON) selects a case.
24
+ on: str = Field(min_length=1)
25
+ #: Case value -> id of a child step.
26
+ cases: dict[str, str] = Field(default_factory=lambda: {})
27
+ #: Child step id used when no case matches. Without it, no match fires `skip`.
28
+ default: str | None = None
29
+
30
+
31
+ def _validate(config: SwitchConfig, _vctx: ValidateContext) -> list[ConfigIssue]:
32
+ return check_expr("switch.on", config.on)
33
+
34
+
35
+ def _validate_node(
36
+ config: SwitchConfig, node: PipelineNode, _vctx: ValidateContext
37
+ ) -> list[ConfigIssue]:
38
+ ids = {c.id for c in node.children}
39
+ targets = [*config.cases.items(), *([("default", config.default)] if config.default else [])]
40
+ return [
41
+ ConfigIssue("error", f'`switch` case "{case}" targets unknown step "{target}"')
42
+ for case, target in targets
43
+ if target not in ids
44
+ ]
45
+
46
+
47
+ def _key(value: Any) -> str:
48
+ return value if isinstance(value, str) else json.dumps(value, separators=(",", ":"))
49
+
50
+
51
+ async def _run(
52
+ children: list[PipelineNode], input: PortValues, ctx: CompositeContext[SwitchConfig]
53
+ ) -> Emit:
54
+ value = parse_expr(ctx.config.on).eval({**ctx.scope.snapshot(), "input": input.get("in")})
55
+ target = ctx.config.cases.get(_key(value), ctx.config.default)
56
+ child = next((c for c in children if c.id == target), None)
57
+ if child is None:
58
+ return Emit("skip")
59
+ return await ctx.run(child, input)
60
+
61
+
62
+ #: Runs exactly one child, chosen by evaluating `on` and looking it up in `cases`.
63
+ switch_strategy: Strategy[Any] = define_strategy(
64
+ Strategy(
65
+ id="switch", config=SwitchConfig, validate=_validate, validate_node=_validate_node, run=_run
66
+ )
67
+ )
@@ -0,0 +1,260 @@
1
+ """whiletrue core: module/port/cap model, config, validation, runtime. Imports no agent or VCS."""
2
+
3
+ from whiletrue.abort import AbortSignal
4
+ from whiletrue.core.caps import CapError, CapRegistry, CapValidation, create_builtin_caps
5
+ from whiletrue.core.comments import (
6
+ REPLY_PREFIX,
7
+ CommentsContext,
8
+ CommentsProvider,
9
+ IncomingComment,
10
+ sync_comments,
11
+ with_prefix,
12
+ )
13
+ from whiletrue.core.composite import expand_composites
14
+ from whiletrue.core.config import (
15
+ AgentDefinition,
16
+ CompositeDefinition,
17
+ ConfigError,
18
+ ParamSpec,
19
+ PipelineConfig,
20
+ PipelineNode,
21
+ SourceLoc,
22
+ load_agent_definition,
23
+ load_composite,
24
+ load_pipeline,
25
+ parse_agent_definition,
26
+ parse_composite,
27
+ parse_pipeline,
28
+ )
29
+ from whiletrue.core.context import (
30
+ CompositeContext,
31
+ Locks,
32
+ Resource,
33
+ Scope,
34
+ StepContext,
35
+ create_step_context,
36
+ )
37
+ from whiletrue.core.duration import parse_duration
38
+ from whiletrue.core.events import EventBus, WtEvent
39
+ from whiletrue.core.expr import Expr, ExprError, parse_expr
40
+ from whiletrue.core.history import (
41
+ CommentRecord,
42
+ Decision,
43
+ EffectRecord,
44
+ LearningRecord,
45
+ LearningStatus,
46
+ ParkRecord,
47
+ SteerRecord,
48
+ )
49
+ from whiletrue.core.lock import (
50
+ LOCK_FILE,
51
+ LockError,
52
+ check_lock,
53
+ collect_file_hashes,
54
+ read_lock,
55
+ sha256_file,
56
+ write_lock,
57
+ )
58
+ from whiletrue.core.memory_store import MemoryStore
59
+ from whiletrue.core.module import (
60
+ EFFECTS,
61
+ ActionModule,
62
+ ConfigIssue,
63
+ Effect,
64
+ Emit,
65
+ EmptyConfig,
66
+ ModuleDefinitionError,
67
+ Ports,
68
+ PortSpec,
69
+ Strategy,
70
+ ValidateContext,
71
+ define_action,
72
+ define_strategy,
73
+ is_effect,
74
+ )
75
+ from whiletrue.core.outcomes import (
76
+ OUTCOME_PORTS,
77
+ InvalidTransition,
78
+ ItemState,
79
+ OnFail,
80
+ OutcomePolicy,
81
+ Resolution,
82
+ can_transition,
83
+ is_outcome_port,
84
+ item_state_for,
85
+ resolve_outcome,
86
+ transition,
87
+ )
88
+ from whiletrue.core.registry import Plugin, PluginApi, Registry, RegistryError, SimplePlugin
89
+ from whiletrue.core.replay import Recording, ReplayData, ReplayError, load_recording
90
+ from whiletrue.core.runner import (
91
+ AgentLimits,
92
+ AgentRequest,
93
+ AgentResult,
94
+ RunContext,
95
+ Runner,
96
+ RunnerCapabilities,
97
+ )
98
+ from whiletrue.core.runtime import (
99
+ ItemOutcome,
100
+ RunItem,
101
+ RunResult,
102
+ find_dependency_cycles,
103
+ hash_pipeline,
104
+ run_pipeline,
105
+ )
106
+ from whiletrue.core.source import SourceError, SourceProvider, fetch_items, source_spec
107
+ from whiletrue.core.store import (
108
+ ItemRecord,
109
+ RunRecord,
110
+ StateStore,
111
+ StepRecord,
112
+ )
113
+ from whiletrue.core.template import TemplateError, render_deep, render_template
114
+ from whiletrue.core.validate import Diagnostic, format_diagnostic, has_errors, validate_pipeline
115
+ from whiletrue.core.wake import (
116
+ WakeChecker,
117
+ WakeCondition,
118
+ WakeContext,
119
+ WakeResult,
120
+ WakeSpec,
121
+ evaluate_wake,
122
+ parse_wake,
123
+ wake_to_dict,
124
+ )
125
+ from whiletrue.core.workspace import (
126
+ Workspace,
127
+ WorkspaceError,
128
+ WorkspaceProvider,
129
+ resolve_workspace,
130
+ workspace_spec,
131
+ )
132
+
133
+ __all__ = [
134
+ "EFFECTS",
135
+ "LOCK_FILE",
136
+ "OUTCOME_PORTS",
137
+ "REPLY_PREFIX",
138
+ "AbortSignal",
139
+ "ActionModule",
140
+ "AgentDefinition",
141
+ "AgentLimits",
142
+ "AgentRequest",
143
+ "AgentResult",
144
+ "CapError",
145
+ "CapRegistry",
146
+ "CapValidation",
147
+ "CommentRecord",
148
+ "CommentsContext",
149
+ "CommentsProvider",
150
+ "CompositeContext",
151
+ "CompositeDefinition",
152
+ "ConfigError",
153
+ "ConfigIssue",
154
+ "Decision",
155
+ "Diagnostic",
156
+ "Effect",
157
+ "EffectRecord",
158
+ "Emit",
159
+ "EmptyConfig",
160
+ "EventBus",
161
+ "Expr",
162
+ "ExprError",
163
+ "IncomingComment",
164
+ "InvalidTransition",
165
+ "ItemOutcome",
166
+ "ItemRecord",
167
+ "ItemState",
168
+ "LearningRecord",
169
+ "LearningStatus",
170
+ "LockError",
171
+ "Locks",
172
+ "MemoryStore",
173
+ "ModuleDefinitionError",
174
+ "OnFail",
175
+ "OutcomePolicy",
176
+ "ParamSpec",
177
+ "ParkRecord",
178
+ "PipelineConfig",
179
+ "PipelineNode",
180
+ "Plugin",
181
+ "PluginApi",
182
+ "PortSpec",
183
+ "Ports",
184
+ "Recording",
185
+ "Registry",
186
+ "RegistryError",
187
+ "ReplayData",
188
+ "ReplayError",
189
+ "Resolution",
190
+ "Resource",
191
+ "RunContext",
192
+ "RunItem",
193
+ "RunRecord",
194
+ "RunResult",
195
+ "Runner",
196
+ "RunnerCapabilities",
197
+ "Scope",
198
+ "SimplePlugin",
199
+ "SourceError",
200
+ "SourceLoc",
201
+ "SourceProvider",
202
+ "StateStore",
203
+ "SteerRecord",
204
+ "StepContext",
205
+ "StepRecord",
206
+ "Strategy",
207
+ "TemplateError",
208
+ "ValidateContext",
209
+ "WakeChecker",
210
+ "WakeCondition",
211
+ "WakeContext",
212
+ "WakeResult",
213
+ "WakeSpec",
214
+ "Workspace",
215
+ "WorkspaceError",
216
+ "WorkspaceProvider",
217
+ "WtEvent",
218
+ "can_transition",
219
+ "check_lock",
220
+ "collect_file_hashes",
221
+ "create_builtin_caps",
222
+ "create_step_context",
223
+ "define_action",
224
+ "define_strategy",
225
+ "evaluate_wake",
226
+ "expand_composites",
227
+ "fetch_items",
228
+ "find_dependency_cycles",
229
+ "format_diagnostic",
230
+ "has_errors",
231
+ "hash_pipeline",
232
+ "is_effect",
233
+ "is_outcome_port",
234
+ "item_state_for",
235
+ "load_agent_definition",
236
+ "load_composite",
237
+ "load_pipeline",
238
+ "load_recording",
239
+ "parse_agent_definition",
240
+ "parse_composite",
241
+ "parse_duration",
242
+ "parse_expr",
243
+ "parse_pipeline",
244
+ "parse_wake",
245
+ "read_lock",
246
+ "render_deep",
247
+ "render_template",
248
+ "resolve_outcome",
249
+ "resolve_workspace",
250
+ "run_pipeline",
251
+ "sha256_file",
252
+ "source_spec",
253
+ "sync_comments",
254
+ "transition",
255
+ "validate_pipeline",
256
+ "wake_to_dict",
257
+ "with_prefix",
258
+ "workspace_spec",
259
+ "write_lock",
260
+ ]