Skip to content
4 changes: 2 additions & 2 deletions src/agent_comms/following_inputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from .owned_send import OwnedSend
from agent_comms.goal_turn_permit import NoLaunchPermit
from .queued_input import DeliveredInput, InputHandoffRefused
from .thread_identity import ClaimedIdentity, RegisteredTurn
from .thread_identity import ClaimedIdentity
from .turn_input_source import AcceptedFollowingInput

if TYPE_CHECKING:
Expand Down Expand Up @@ -90,7 +90,7 @@ async def open(self, session: TrackedTurnSession) -> None:
goal_store=await Coordination.run_worker(inputs.comms.goals.open_goal_store),
session_id=self.session_id,
thread=thread,
turn=RegisteredTurn(lease.turn_id),
turn=lease.turn_id,
claim_generation=lease.claimed_generation,
original_source=original,
goal_permit=NoLaunchPermit(),
Expand Down
5 changes: 3 additions & 2 deletions src/agent_comms/goal_turn_permit.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@

from agent_comms.ordinary_turn_rules import OrdinaryGoalGrantCheck

from .field_codec import TurnId

if TYPE_CHECKING:
from agent_comms.goal_attempts import GoalAttemptStore, LaunchPermit
from agent_comms.goal_management import Goals
from agent_comms.goals import GoalDeclaration
from agent_comms.pi_payloads import PiUsage
from agent_comms.thread_identity import RegisteredTurn
from agent_comms.threads import Thread
from agent_comms.turn_context import TurnContext
from agent_comms.turn_goal_account import TurnGoalAccount, VerifiedGoalSettlement
Expand Down Expand Up @@ -45,7 +46,7 @@ def stop(self, store: GoalAttemptStore) -> None:
permit.stop(store)

def settle_goal(self, settlement: type[VerifiedGoalSettlement], store: GoalAttemptStore,
goal: GoalDeclaration, turn: RegisteredTurn) -> None:
goal: GoalDeclaration, turn: TurnId) -> None:
for permit in self.claims:
goal.settle(settlement, store, permit, turn)

Expand Down
18 changes: 12 additions & 6 deletions src/agent_comms/goals.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@
from .declared_family import DeclaredFamily
from .errors import RejectedEnforcementError, RelationViolationError
from .field_codec import (
FieldCodec, JsonShapeFamily, JsonShapeMember, MalformedRecord, NullMember,
PresenceExclude, RecordMember, SubclassUnion,
FieldCodec,
JsonShapeFamily,
JsonShapeMember,
MalformedRecord,
NullMember,
PresenceExclude,
RecordMember,
SubclassUnion,
TurnId,
)
from .goal_states import ActiveGoal, GoalState
from agent_comms.goal_turn_permit import GoalTurnPermit, NoLaunchPermit
Expand All @@ -45,7 +52,6 @@
from .goal_management import Goals
from .goal_attempts import GoalAttemptStore, LaunchPermit
from .turn_goal_account import VerifiedGoalSettlement
from .thread_identity import RegisteredTurn
from .todos import Todo


Expand Down Expand Up @@ -588,7 +594,7 @@ def stopped_permit(self, store: GoalAttemptStore) -> GoalTurnPermit: ...

@abstractmethod
def settle(self, settlement: type[VerifiedGoalSettlement], store: GoalAttemptStore,
permit: LaunchPermit, turn: RegisteredTurn) -> None: ...
permit: LaunchPermit, turn: TurnId) -> None: ...

@abstractmethod
def instructions_for(self, goals: Goals, owner: ThreadIncarnation) -> tuple[str, ...]: ...
Expand Down Expand Up @@ -678,7 +684,7 @@ def registration_value(self, previous: GoalDeclaration) -> GoalDeclaration:
return previous

def settle(self, settlement: type[VerifiedGoalSettlement], store: GoalAttemptStore,
permit: LaunchPermit, turn: RegisteredTurn) -> None:
permit: LaunchPermit, turn: TurnId) -> None:
pass

def instructions_for(self, goals: Goals, owner: ThreadIncarnation) -> tuple[str, ...]:
Expand Down Expand Up @@ -785,7 +791,7 @@ def registration_value(self, previous: GoalDeclaration) -> GoalDeclaration:
return self

def settle(self, settlement: type[VerifiedGoalSettlement], store: GoalAttemptStore,
permit: LaunchPermit, turn: RegisteredTurn) -> None:
permit: LaunchPermit, turn: TurnId) -> None:
settlement(store, permit, self, turn).dispatch_sync(self.state)

def instructions_for(self, goals: Goals, owner: ThreadIncarnation) -> tuple[str, ...]:
Expand Down
5 changes: 2 additions & 3 deletions src/agent_comms/input_disposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
from .channel_input_batch import SingleInputBatch
from .private_registry_guard import RegistryPrivacy
from .registry_document import RegistrySnapshot
from .thread_identity import RegisteredTurn
from .turn_lease import TurnLeaseFence


Expand Down Expand Up @@ -299,13 +298,13 @@ def reserve(original: InputDocument) -> DocumentChange[InputDocument, InputDocum
return self._update(*_members("key", (row.key for row in originals)), reserve)

def reserve_turn(
self, owner: str, turn: RegisteredTurn, claim_scope: int, text: str,
self, owner: str, turn: TurnId, claim_scope: int, text: str,
*, ownership: ExitStack,
) -> SingleInputBatch:
"""Enlist rollback before publication; caller retains the original wire scope."""
from .channel_input_batch import SingleInputBatch

row = ReservedInput(f"turn:{turn.value}", None, owner, claim_scope, owner, text)
row = ReservedInput(f"turn:{turn}", None, owner, claim_scope, owner, text)

document = self.reserve_originals(row, ownership=ownership)
return SingleInputBatch(document.originals((row.key,)))
Expand Down
3 changes: 2 additions & 1 deletion src/agent_comms/installer/probes/carry.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,12 @@ def rewrite_stored(
) -> None:
"""Inside the caller's write transaction, carry stored values of a guarded row:
its declared mutation guards are lifted and recreated from the same declaration."""
(key,) = (field.name for field in row._fields if field.column.primary_key)
guards = row.triggers()
for name in guards:
TriggerKind.drop(db, name)
db.executemany(
row._sql(f'UPDATE "{row.declared_name}" SET {{{column.name}}}=? WHERE {{seq}}=?'),
row._sql(f'UPDATE "{row.declared_name}" SET {{{column.name}}}=? WHERE {{{key}}}=?'),
updates,
)
for sql in guards.values():
Expand Down
3 changes: 1 addition & 2 deletions src/agent_comms/native_turn_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,9 @@ async def record(self, contexts, prior, thread, lease) -> CapturedContext:
"""Publish the original SDK observation under its leased owner turn, after the
prior this turn holds; the result is the turn's next prior."""
from .coordinator import Coordination
from .thread_identity import RegisteredTurn
from .turn_context import RecordedContextTurn

turn = RecordedContextTurn(RegisteredTurn(lease.turn_id), lease.identity)
turn = RecordedContextTurn(lease.turn_id, lease.identity)
manifest = self.for_turn(thread.incarnation, turn)
return await Coordination.run_worker(
partial(contexts.record_after, prior, manifest)
Expand Down
4 changes: 2 additions & 2 deletions src/agent_comms/ordinary_turn_rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from dataclasses import dataclass
from typing import TYPE_CHECKING

from .field_codec import TurnId
from .reservation_rules import ReservationRule, RuleCheck
from .thread_identity import RegisteredTurn

if TYPE_CHECKING:
from .comms import Comms
Expand Down Expand Up @@ -39,7 +39,7 @@ class OrdinaryOwnerCheck(RuleCheck):
registry: RegistrySnapshot
canonical: str
claim_generation: int
turn: RegisteredTurn
turn: TurnId


class OrdinaryIncarnationRule(ReservationRule):
Expand Down
9 changes: 4 additions & 5 deletions src/agent_comms/owned_send.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@
from .coordination_session import NativeBoundary
from .coordinator import Coordination
from .envelope_claim_transitions import NativeClaim
from .field_codec import InputId
from .field_codec import InputId, TurnId
from .input_attempt import InputAlreadyCleared
from .reservation_rules import ReservationRule, ReservationViolationError
from .thread_identity import RegisteredTurn
from .turn_input_source import (
OriginalTurnInput,
TurnInputSource,
Expand All @@ -53,7 +52,7 @@ class OwnedSend(CodingToolOwner, InputStartListener, SendBoundary):
goal_store: GoalAttemptStore
session_id: str
thread: Thread
turn: RegisteredTurn
turn: TurnId
claim_generation: int
original_source: OriginalTurnInput
goal_permit: GoalTurnPermit
Expand Down Expand Up @@ -146,7 +145,7 @@ def claim_resource(self, store, turn, resource, slot):
owner = snapshot.require(self.owner_name)
canonical = resource.normalized(Path(owner.worktree))
scope = NativeClaim(owner_claimed_generation=self.claim_generation,
operation_id=slot, turn_id=self.turn.value,
operation_id=slot, turn_id=self.turn,
input_id=turn.command.input_id)
return boundary.bus.publisher._publish_acquisition_unlocked(
snapshot, owner, canonical, scope, activity=boundary.activity)
Expand All @@ -170,7 +169,7 @@ def following(self, public_id: InputId, native_id: str, text: str) -> bool:
def _started(self, source: TurnInputSource, native_id: str, sent_text: str) -> bool:
return source.valid_keys(sent_text) and all(
self.inputs.dispositions.started(
key, turn_id=self.turn.value, native_id=native_id, text=sent_text
key, turn_id=self.turn, native_id=native_id, text=sent_text
)
for key in source.keys
)
9 changes: 4 additions & 5 deletions src/agent_comms/owned_turn.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
from .native_input_owner import RegistryOwner
from .owned_send import OwnedSend
from .routing import MessageRoute, ScheduledTurn, TurnRouting
from .thread_identity import RegisteredTurn
from .turn_goal_account import TurnGoalAccount
from .turn_goal_permission import (
OwnerGoalPermission,
Expand Down Expand Up @@ -153,7 +152,7 @@ def begin(self, resources: AsyncExitStack, permits: ExitStack) -> bool:
origin_claims = ExitStack()
permits.callback(origin_claims.close)
self.goals = TurnGoalAccount(
comms=self.runner.comms, owner=self.thread, turn=RegisteredTurn(self.turn_id),
comms=self.runner.comms, owner=self.thread, turn=self.turn_id,
lease=self.turn_lease, permit=self.goal_permit,
pending_origins=self.runner.goals.pending_goal_origins, claims=origin_claims,
)
Expand Down Expand Up @@ -221,7 +220,7 @@ def prepare_prompt(self, batch: InputBatch):
self.relations = self.runner.comms.relationships.context_relations(self.thread.name)
self.context = TurnContext.for_owner(
self.thread,
RecordedContextTurn(RegisteredTurn(self.turn_id), self.turn_lease.identity),
RecordedContextTurn(self.turn_id, self.turn_lease.identity),
self.task,
self.runner.comms.views.thread_views(),
self.relations,
Expand Down Expand Up @@ -270,7 +269,7 @@ def reserve_input(self, batch: InputBatch):
self.original = original.reserve(
self.runner.inputs.dispositions,
self.thread,
RegisteredTurn(self.turn_id),
self.turn_id,
self.turn_lease.claimed_generation,
ownership=reservation,
)
Expand Down Expand Up @@ -344,7 +343,7 @@ async def stream(self):
goal_store=await Coordination.run_worker(self.runner.comms.goals.open_goal_store),
session_id=self.session_id,
thread=self.thread,
turn=RegisteredTurn(self.turn_id),
turn=self.turn_id,
claim_generation=self.turn_lease.claimed_generation,
goal_permit=self.goal_permit,
original_source=replace(self.original, prompt=rendered.text),
Expand Down
11 changes: 4 additions & 7 deletions src/agent_comms/registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from .routing import TurnRouting
from .storage_rules import StorageRule
from .thread_execution import CommanderForkExecution
from .thread_identity import GenerationCounter, RegisteredTurn
from .thread_identity import GenerationCounter
from .thread_status import (
ConnectedThreadStatus,
NoBridgeThreadStatus,
Expand Down Expand Up @@ -326,12 +326,11 @@ def lease_live_turn_with_claim(
) -> tuple[Thread, int]:
"""Claim a turn against the input generation, allowing unrelated metadata changes."""
Thread.require_declaration(expected)
turn = RegisteredTurn(turn_id)
generation = GenerationCounter.require_positive(expected_generation)
with self.store.editing() as edit:
owner = RegistryOwner.capture_local(edit.original.snapshot, expected.name)
owner.require_claim(expected, generation)
leased, _ = edit.lease_turn(owner.thread, turn.value, None)
leased, _ = edit.lease_turn(owner.thread, turn_id, None)
edit.commit()
return leased, generation

Expand All @@ -345,26 +344,24 @@ def lease_live_turn_with_generation(
) -> tuple[Thread, int]:
"""Claim against the exact captured declaration and stable owner generation."""
Thread.require_declaration(expected)
turn = RegisteredTurn(turn_id)
generation = GenerationCounter.require_positive(expected_owner_generation)
with self.store.editing() as edit:
snapshot = edit.original.snapshot
owner = RegistryOwner.capture_local(snapshot, expected.name)
owner.require_exact(snapshot, expected, generation)
owner.thread.turn_record.read().require_idle()
result = edit.lease_turn(owner.thread, turn.value, routing)
result = edit.lease_turn(owner.thread, turn_id, routing)
edit.commit()
return result

def lease_local_turn(
self, name: str, turn_id: TurnId, *, routing: TurnRouting | None = None
) -> tuple[Thread, int]:
"""Atomic local begin-turn, never reviving a stopped or replaced owner."""
turn = RegisteredTurn(turn_id)
with self.store.editing() as edit:
owner = RegistryOwner.capture_local(edit.original.snapshot, name)
owner.thread.turn_record.read().require_idle()
result = edit.lease_turn(owner.thread, turn.value, routing)
result = edit.lease_turn(owner.thread, turn_id, routing)
edit.commit()
return result

Expand Down
3 changes: 1 addition & 2 deletions src/agent_comms/selected_turn.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
from .wake_candidate_index import WakeCandidateIndex
from .context_segments.wake import SelectedWakeSegment
from .context_segments.selected import SelectedTriageSegment, SelectedWorkSegment
from .thread_identity import RegisteredTurn
from .turn_context import RecordedContextTurn, RenderedInput, TurnContext
from .turn_phase import PreparingPhase, PromptAcceptancePhase, PublishingPhase

Expand All @@ -43,7 +42,7 @@ def context(self, segments) -> TurnContext:
lease = owner.require_turn_lease()
return TurnContext(
owner.incarnation,
RecordedContextTurn(RegisteredTurn(lease.turn_id), lease.identity),
RecordedContextTurn(lease.turn_id, lease.identity),
tuple(segments),
)

Expand Down
9 changes: 4 additions & 5 deletions src/agent_comms/task_sources.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@
from .channel_targets import CommandTarget
from .declared_family import DeclaredFamily
from .errors import RelationViolationError
from .field_codec import FieldCodec, WireOmitDefault
from .field_codec import FieldCodec, TurnId, WireOmitDefault
from .goals import GoalDeclaration, GoalRevision
from .message_reference import MessageReference
from .owner_requests import OwnerRequestId, RequestDirective
from .projection_source import ProjectionSource
from .thread_identity import (
RecordedThreadIncarnation,
RegisteredTurn,
ThreadIncarnation,
TurnIdentity,
UserThreadRole,
Expand Down Expand Up @@ -406,14 +405,14 @@ def require_correction(self, original: Message, registry: RegistrySnapshot) -> N
@dataclass(frozen=True, kw_only=True)
class ModelTaskDeclaration(ScopedTaskDeclaration):
source_turn: TurnIdentity
source_turn_id: RegisteredTurn
source_turn_id: TurnId
permits_agent_revision = True

@classmethod
def from_claim(cls, owner: Thread, scope: TaskScopeSelection, change: TaskChange, **content) -> Self:
lease = owner.require_turn_lease()
return cls(scope=scope.select(owner), source_turn=lease.identity,
source_turn_id=RegisteredTurn(lease.turn_id), change=change, **content)
source_turn_id=lease.turn_id, change=change, **content)

def __post_init__(self):
self.author.require_recorded()
Expand Down Expand Up @@ -443,7 +442,7 @@ def turn_scope_matches_original(self, previous: ModelTaskDeclaration, registry:
def require_emission(self, owner: Thread) -> None:
self.require_sender(owner.name)
lease = owner.require_turn_lease()
if (lease.identity, lease.turn_id) != (self.source_turn, self.source_turn_id.value):
if (lease.identity, lease.turn_id) != (self.source_turn, self.source_turn_id):
raise RelationViolationError("Task declaration's original turn is no longer authorized")
self.scope.require_current(owner)

Expand Down
3 changes: 0 additions & 3 deletions src/agent_comms/thread_identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,9 +442,6 @@ def decode(cls, name: str, birth: float) -> ThreadIncarnation:
return FieldCodec.decode(cls, {"name": name, "created_at": birth}).incarnation()


@dataclass(frozen=True, slots=True)
class RegisteredTurn(ProjectionSource):
value: TurnId


@dataclass(frozen=True, slots=True)
Expand Down
Loading
Loading