events
strands_teams.events ¶
Append-only typed event plane + deterministic replay + replan triggers (spec 006).
This module evolves the untyped team_debug.jsonl into a real, replayable event plane (ASTR §6.5, §7, §15.2). It ships three things, all built on the :class:~strands_teams.models.TeamEvent type:
- :class:
EventLog— an append-only log bound to a singleTeamsLayout-resolved path (:meth:~strands_teams.layout.TeamsLayout.event_log_path). It exposes onlyappendand read operations — no update or delete — so an already-written event can never be mutated (AC-2-5).appendwrites exactly one line and leaves every prior line byte-for-byte unchanged (AC-2-2); anOSErroris logged and swallowed, never raised across the caller (AC-2-4), preserving the never-raises contract of the pre-split_write_debug_entry. - :func:
replay— reconstructs the run's state transitions, artifacts, findings, and decisions from anEventLogalone, with no live model/Bedrock call (AC-3-1). Deterministic across two runs (AC-3-2); applies each event only after all its causal parents (AC-3-3); reflects superseding outcomes while retaining the superseded originals (AC-3-4); skips a malformed line with a recorded warning rather than raising (AC-3-5). - :func:
should_replan— a predicate over the event log firing on any of the five ASTR replan triggers (AC-6-1..AC-6-7).
The event plane carries no chain-of-thought or raw transcript (plan §5; research-coding-runtimes.yaml line 99): a :class:~strands_teams.models.TeamEvent is extra="forbid", so a transcript field is rejected at construction.
REPLAN_TRIGGERS module-attribute ¶
REPLAN_TRIGGERS = (
TRIGGER_REQUIREMENT_CHANGED,
TRIGGER_CRITICAL_FINDING,
TRIGGER_TASK_FAILED,
TRIGGER_BUDGET_EXCEEDED,
TRIGGER_ARTIFACT_INTERFACE_CHANGED,
)
The five ASTR replan triggers, in canonical order.
EventLog ¶
An append-only, replayable log of :class:~strands_teams.models.TeamEvent.
Bound to a single file path (resolved from :meth:~strands_teams.layout.TeamsLayout.event_log_path), writing one JSON-encoded event per line (AC-2-1). The API is deliberately append + read only — there is no update or delete method — so an already-written event is immutable (AC-2-5). Supersession is expressed by appending a new event, never by editing an old line (AC-3-4).
Bind the log to path (created lazily on first :meth:append).
Source code in packages/strands-teams/src/strands_teams/events.py
append ¶
Append exactly one JSON line for event; never raise (AC-2-2, AC-2-4).
Serializes event to a single line via :meth:~pydantic.BaseModel.model_dump_json and appends it, leaving every previously written line byte-for-byte unchanged. An OSError (e.g. a read-only filesystem) is logged and swallowed so a log-write failure never kills the coordinator or the lead loop (AC-2-4), matching the never-raises contract of the pre-split _write_debug_entry (teams.py).
Source code in packages/strands-teams/src/strands_teams/events.py
read ¶
Parse and return every valid event, skipping malformed lines.
A malformed line is skipped; use :func:replay when you need the malformed-line warnings surfaced structurally (AC-3-5).
Source code in packages/strands-teams/src/strands_teams/events.py
read_with_warnings ¶
Return (events, warnings) — one warning per skipped malformed line.
ReplayState ¶
Bases: FrozenModel
The deterministic reconstruction produced by :func:replay (AC-3-1, AC-3-2).
Immutable. :meth:to_canonical_json yields a byte-stable serialization so two replays of the same log compare byte-for-byte identical (AC-3-2, AC-7-1).
Attributes:
| Name | Type | Description |
|---|---|---|
applied | list[str] |
|
transitions | list[str] |
|
artifacts | dict[str, str] |
|
findings | dict[str, dict[str, Any]] | Finding payloads reconstructed from finding-bearing events, keyed by |
decisions | dict[str, dict[str, Any]] | Decision payloads reconstructed from decision-bearing events, keyed by |
superseded | list[str] |
|
warnings | list[str] | One entry per malformed log line skipped during replay (AC-3-5). |
to_canonical_json ¶
Return a byte-stable JSON serialization for cross-replay equality (AC-3-2).
ReplanDecision ¶
Bases: FrozenModel
The structured outcome of :func:should_replan (AC-6-1).
Attributes:
| Name | Type | Description |
|---|---|---|
replan | bool | Whether any replan trigger fired. |
triggers | list[str] | The distinct triggers that fired, in canonical order (empty when |
reasons | list[str] | Human-readable reason per fired trigger. |
parse_lines ¶
Parse JSONL lines into events, collecting a warning per malformed line.
Deterministic: each line is validated as a :class:~strands_teams.models.TeamEvent; a line that is not valid JSON or not a valid event is skipped and a warning string (naming the 1-based line number) is recorded rather than raised (AC-3-5). Returns (events, warnings) in stable line order.
Source code in packages/strands-teams/src/strands_teams/events.py
replay ¶
Reconstruct run state from events with no live model call (AC-3-1..AC-3-5).
Applies each event only after all its causal parents (:func:_causal_order, AC-3-3), records the transition sequence, tracks the latest non-superseded event per artifact binding, reconstructs finding and decision payloads, and reflects supersession (an event bearing epistemic_status="superseded" or an event naming another in its causal_parents with an epistemic_status in {accepted, rejected, superseded} supersedes that parent) while retaining the originals in the log (AC-3-4).
Deterministic: given the same events (and malformed-line warnings), the returned :class:ReplayState is identical across calls (AC-3-2).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
events | Iterable[TeamEvent] | The parsed events to replay (typically | required |
warnings | Iterable[str] | Malformed-line warnings from parsing, folded into the result so :meth: | () |
Returns:
| Name | Type | Description |
|---|---|---|
A | ReplayState | class: |
Source code in packages/strands-teams/src/strands_teams/events.py
replay_log ¶
Replay an :class:EventLog end to end, surfacing malformed-line warnings (AC-3-5).
Source code in packages/strands-teams/src/strands_teams/events.py
should_replan ¶
Decide whether the lead loop should replan (AC-6-1..AC-6-7).
Scans the event log for any of the five ASTR triggers — requirement.changed, critical_finding.created, task.failed, budget.threshold_exceeded, artifact.interface_changed — matching on either an explicit trigger-typed event or the structured payload of a generic dispatch/finding/revision event. Cumulative recorded cost crossing budget_threshold fires the budget trigger (AC-6-4). Returns replan=False with no triggers on a trigger-free log (AC-6-7).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
events | Iterable[TeamEvent] | The events to evaluate (typically | required |
budget_threshold | float | The configured cumulative-cost bound; | 0.0 |
Returns:
| Name | Type | Description |
|---|---|---|
A | ReplanDecision | class: |