Skip to content

v0.108.0

Choose a tag to compare

@sboily sboily released this 24 Oct 13:53
· 946 commits to main since this release

What's Changed

  • docs(changelog): promote Unreleased to 0.108.0, minimum version 0.108.0 in llms.txt and the c7 overview
  • docs(changelog): close() waits 5 s at most for the decided writes, and init()'s own-schema lookup holds for this release's index names (RMK-930)
  • fix(inbound): a room another call created first is no error once the caller left (RMK-930)
  • fix(framework): close() cuts the background runs its drains start (RMK-930)
  • fix(framework): close() waits for the decided writes on its close budget, names what is still running and goes on (RMK-930)
  • docs(c7): a call the room's work adopts answers at its commit, its delivery behind the event's work (RMK-930)
  • docs(changelog): the concurrency lot's fixes in their entries: a caller that stops waiting, observers outside the lock, adopted calls answered at their commit, close() and the work its drains start (RMK-930)
  • fix(framework): a caller waiting for the work close() cuts returns, not cancelled (RMK-930)
  • fix(framework): close() cuts the tasks its drains start, not only the ones it found first (RMK-930)
  • fix(inbound): a room step 2 opens is completed when its caller leaves during ON_ROOM_CREATED (RMK-930)
  • fix(rooms): timer transitions its caller left are written and reported whole (RMK-930)
  • fix(inbound): a caller cancelled once its call is decided leaves its writes whole, its event delivered and the lane going on (RMK-930)
  • fix(reentrance): a call adopted beside an event answers at its commit, its delivery detached (RMK-930)
  • fix(hooks): an ASYNC observer starts in a context that holds no room lock, and a close() it runs does not wait for it (RMK-903)
  • fix(locks): a cancellation met while the lock is released after a failed section reaches its caller (RMK-902)
  • docs(changelog): the store lot's fixes in their entries: SQLite schema 11 and its identity index, Postgres index names in their own schema, blank addresses, the plan after a locked hook (RMK-930)
  • docs(c7): once a hook ran under the lock, the event is planned with the history and the bindings as the hook left them (RMK-930)
  • fix(store): a blank string under a binding's recipient key names no one, in every store (RMK-930)
  • fix(inbound): once a hook ran under the lock, the event is planned with the history and the bindings as the hook left them (RMK-930)
  • fix(postgres): init() looks its index names up in its own schema, not through search_path (RMK-930)
  • perf(sqlite): a sender's participant lookup reads through indexes, by id and by identity (RMK-930)
  • fix(sqlite): an upgraded file no longer finds its soft-deleted messages through search_events (RMK-930)
  • chore(store): import RoomNotFoundError at the top of the stores, and name _responder_failures in its caller's docstring (RMK-930)
  • docs(changelog): the injected events entry names no internal base class
  • docs(changelog): the response scope and the publication namespace entries say only their own part
  • docs(changelog): every new public name is named in the entry of the feature that brought it
  • fix(api): refuse_too_deep is exported from roomkit, as the sixth composite level's migration tells callers to use it
  • fix(voice): the sherpa-onnx extra's floor is 1.12.30, the oldest release with the APIs Moonshine and stream_language call
  • docs(changelog): the Unreleased section in Keep a Changelog order, every breaking change with its migration
  • docs(c7): a mutation trigger's context holds what the change's hooks committed and the commit's counters (RMK-930)
  • docs(changelog): a mutation trigger's history holds what the change's hooks committed, its counters are the commit's, and an off-lock-only pass reads nothing again (RMK-930)
  • fix(telemetry): a message refused past its room's work budget as it starts still opens its framework.inbound span (RMK-930)
  • test(inbound): send_event() raises RoomClosedError when its own hook closed the room (RMK-930)
  • fix(edits): a mutation trigger reads the room's whole history and its counters as the change's commit left them (RMK-930)
  • fix(inbound): the gate reads the room again only once a locked hook ran, on one connection, and reads the context again when an entry committed during the hooks (RMK-930)
  • docs(changelog): a routed message of the room's work is charged once wherever routing places it (RMK-930)
  • fix(reentrance): a routed message charged for a room another call created first is not charged again where routing places it next (RMK-930)
  • docs(c7): a call naming its room is refused past the budget before its channel is looked up, and a mutation trigger reads the change as its hooks left it (RMK-930)
  • docs(changelog): a message naming its room is refused past its work's budget before anything else, a blocked instruction takes the next index too, and a mutation trigger reads the change as its hooks left it (RMK-930)
  • fix(reentrance): a message naming its room is charged on its room's work budget as it starts, refused past it before anything else (RMK-930)
  • test(instructions): a blocked instruction's result also takes the room's next index once its hooks ran (RMK-930)
  • fix(edits): a mutation trigger's history holds the change as its hooks left it, with or without a target to deliver to (RMK-930)
  • docs(c7): the room read again after a locked hook, an edit's text-form fallback, a mutation trigger's context and how a coordinate is written (RMK-930)
  • docs(changelog): a room a hook closed refuses the event, an instruction's result takes the next index, an edit to a channel that does not edit is its text form, a mutation trigger reads the change committed, and a tiny coordinate reads without an exponent (RMK-930)
  • fix(edits): a mutation trigger reads the room as the change's commit left it, a response's or an injected change's too (RMK-930)
  • fix(inbound): an event takes the room's next index once its locked hooks ran, an instruction's result included (RMK-930)
  • fix(inbound): a room a locked hook closed refuses the event as a closed room does, nothing stored (RMK-930)
  • fix(transcoding): a coordinate reads with one decimal at least, the shortest that reads back the same, never an exponent (RMK-930)
  • fix(transcoding): an edit to a channel that does not edit is one text, its text form, whatever its new content (RMK-930)
  • fix(inbound): the log of a message refused past the cap before opening a room carries no room id (RMK-930)
  • docs(c7): a delivery's call that creates a room, routed or named, draws on its budget (RMK-930)
  • docs(changelog): a call of the room's delivery work that creates a room, routed or named, draws on its budget (RMK-930)
  • fix(reentrance): a call of the room's delivery work naming a room the store lacks draws on that work's budget before the room is created (RMK-930)
  • docs(c7): a routed message that opens a new room draws on its delivery's budget (RMK-930)
  • docs(changelog): a routed message of the room's delivery work that opens a new room draws on its budget (RMK-930)
  • fix(reentrance): a routed message of the room's work is charged for a room its router names but the store lacks, once (RMK-930)
  • fix(reentrance): a message the room's delivery work routes into a new room draws on that work's budget, charged before the room is opened (RMK-930)
  • docs(changelog): a TurnHost verb made after its turn ended starts fresh, with its migration (RMK-930)
  • docs(c7): both doors refuse an empty response scope, which names nobody when a hook writes it (RMK-930)
  • docs(changelog): InboundMessage and send_event refuse an empty response scope, which names nobody when it reaches an event another way (RMK-930)
  • test(reentrance): a task a tool handler or a conference's tool call left running starts fresh once that work is over (RMK-930)
  • fix(turns)!: a host verb made after its turn is work that starts fresh, at the depth it names (RMK-930)
  • docs(c7): the depth floor of a running turn or tool call holds in whatever room (RMK-930)
  • docs(changelog): the depth floor of a running turn or tool call holds in whatever room, only the budget being the room's (RMK-930)
  • fix(reentrance): a call made while a turn or a tool call runs is at least as deep as it, into whatever room, and the floor ends with it (RMK-930)
  • docs(c7): where answers go and the cascade they bind, a hook narrowing response_visibility, and a turn's floor in its own room while it runs (RMK-930)
  • docs(changelog): a hook only narrows where answers go, an empty scope names nobody, the scope binds its cascade only, and work a turn began starts fresh once the turn is over (RMK-930)
  • fix(reentrance)!: work a turn began starts fresh once the turn is over, and a turn's floor binds calls into its own room only (RMK-930)
  • fix(hooks)!: a hook may only narrow where an event's answers go, and a response stays within its cascade's scope after its hooks (RMK-930)
  • fix(visibility): an empty answer scope names nobody on every path, None alone restricting nothing (RMK-930)
  • docs(c7): update_event and delete_event take the caller's organization (RMK-930)
  • docs(changelog): a response scope narrowing every answer of its cascade is a breaking change with its migration, and the organization of update_event and delete_event and the attach a closed new room skips are fixes (RMK-930)
  • fix(visibility): what answers a response stays within both the cascade's scope and the response's own (RMK-930)
  • fix(inbound): a room its ON_ROOM_CREATED hook closed gets no attach of the message's channel (RMK-930)
  • fix(visibility): a message's response scope binds every pass of its cascade again, intersected at each (RMK-930)
  • feat(events): update_event and delete_event take the organization the caller acts for, another's room acting as a missing one (RMK-930)
  • test(transcoding): a composite of a location and a template reads as each part's own text form, as roomkit-rs reads it (RMK-930)
  • fix(visibility)!: a message's response scope narrows its own responses, never widens them, and an answer to a response keeps its channel's (RMK-930)
  • docs(c7): a composite flattened to one text skips its empty parts, and a recipient or a chat is a string that is not blank or a number (RMK-930)
  • docs(changelog): a tool call's and a composite's text form, a message's internal response visibility and what a recipient is are breaking changes, each with its migration (RMK-930)
  • test(routing): a chat message whose chat key holds true or a blank string has no address, as a recipient is read (RMK-930)
  • fix(routing)!: a recipient is a string that is not blank or a number, one rule for the delivery, routing and a delivery status (RMK-930)
  • fix(visibility)!: a message's response_visibility is never internal, refused before anything is read as its visibility is (RMK-930)
  • fix(transcoding)!: a tool call reads as its name and a composite's text skips its empty parts, so an instruction's fingerprint is the text the model reads (RMK-930)
  • docs(c7): a hook_error handler of an off-lock check is adopted beside its event, and the turn-depth floor holds for the turn's spawned work where the owner runs it (RMK-930)
  • docs(changelog): the refused record's visibility and the sixth composite level are breaking changes with their migration, and the turn-depth floor holds where the owner runs the turn's code (RMK-930)
  • test(reentrance): work a turn began keeps the turn's depth once the turn is over, which is why the depth floor, unlike a frame, is never made inert (RMK-930)
  • fix(reentrance): an off-lock check's error report stands in its event's admission order, so a hook_error handler sending into the room is adopted beside it (RMK-930)
  • test(reentrance): the agent calling the kit it holds runs in process, as only an in-memory turn shares the owner's context (RMK-930)
  • test(inbound): the routing budget test is wallclock, and the pre-commit docstring names the room routing created as the room's state (RMK-930)
  • docs(c7): reentrance from a hook, a parse, a delivery or a turn, the processing timeout from the call's start, a refused record's visibility and a sixth composite level (RMK-930)
  • fix(reentrance)!: a call from the room's own work draws on that work's reentry budget, a turn's is as deep as its response, and a nested injection's own injections wait for the section holding the lock (RMK-930)
  • fix(inbound)!: process_timeout is one deadline from the call's start, routing and step 2's lock waits included (RMK-930)
  • fix(visibility): a record stored BLOCKED takes the visibility its event would have been delivered with, its source binding's intersection (RMK-930)
  • fix(events): a sixth composite level is refused where it is built, at every boundary a model_copy could slip one past the validator (RMK-930)
  • fix(events)!: a direct injection's source is OUTBOUND for an intelligence channel, so an agent edits its own injected message (RMK-930)
  • docs(changelog): llama.cpp's start timeout names the budget it was given (RMK-922)
  • docs(c7): a delivery status within its organization and against the one room's recipient, a native edit's file (RMK-930)
  • docs(changelog): a file a channel does not take and a chat message without its chat are breaking changes, each with its migration (RMK-930)
  • perf(store): the room-wide key lookup and the binding lookup's recipient branch read through indexes (RMK-930)
  • fix(transcoding): a native edit's new content carries its files as the target takes them (RMK-930)
  • fix(routing): a message with no address is held to step 3's conditions under the room lock (RMK-930)
  • fix(delivery): commit_event refuses a key in the publication namespace, and a delegated turn's trace rows carry none (RMK-930)
  • fix(delivery): the one room's fallback reads its binding's recipient, so a status is not given a room that delivers to another number (RMK-930)
  • fix(delivery): a delivery status is routed and dispatched within the caller's organization (RMK-930)
  • fix(phones): a phone number is written as RFC 5.7 gives the rules, the trunk prefix written (0) after a country code dropped (RMK-930)
  • fix(delivery): a keyed publication's wait for the room lock is bounded by process_timeout, as the pipeline's own (RMK-930)
  • docs(c7): routing and addresses per RFC 5.7 and 10.4, paused conversations, the store's routing lookups, step 2's attach, a publication's key in its own namespace, a file a channel does not take (RMK-930)
  • fix(delivery)!: a publication's key is stored in a namespace of the framework's own, so a sender's message keyed alike neither blocks it nor stands in for it (RMK-930)
  • fix(transcoding): a file whose type a channel does not list, or over its size limit, is delivered as its text form, and the declarations follow Appendix A (RMK-930)
  • fix(delivery)!: a proactive delivery's key names one publication in its room, looked up before its transport is resolved, in one locked section with the commit (RMK-930)
  • feat(channels)!: a channel's type decides its addressing, from RFC Appendix A's table, and a transport channel takes its type's declaration (RMK-930)
  • fix(routing): a chat message that does not carry its chat has no address, and records no one (RMK-930)
  • fix(routing): step 2 attaches under the room lock once due timers apply, never to a room that refuses events, and keeps a binding a creation hook made (RMK-930)
  • fix(routing)!: a paused conversation keeps its sender's messages, at step 1, at step 3 when its binding is group, and for a delivery status (RMK-930)
  • fix(routing)!: step 1 finds a binding through its recipient, and the default router reads it through the kit's channels (RMK-930)
  • fix(routing)!: the store's routing lookups take the channel, the sender's identity and a RoomFilter, and the newest room either name finds wins (RMK-930)
  • fix(rooms): a timer transition is a compare-and-set, so a commit off the room lock is never overwritten (RMK-930)
  • fix(rooms): close_room returns the room as stored when its timer closes it (RMK-930)
  • refactor(rooms): the room timers are a component the kit builds with its dependencies, not a mixin (RMK-930)
  • docs(c7): room timers per RFC 5.1, transitions already done, binding changes that change nothing, unregistered agents reported (RMK-930)
  • fix(rooms): room timers pause at paused_at, resume on a delivered commit and apply in every locked section at the instant they fell due (RMK-930)
  • fix(rooms): a record stored BLOCKED or committed outside the pipeline is no activity (RMK-930)
  • fix(rooms): a lifecycle record is no activity, so a mute does not restart a room's inactivity timer (RMK-930)
  • fix(delivery): a solicited intelligence channel that is not registered is reported delivery_failed (RMK-930)
  • fix(bindings): a gate change that changes nothing still pushes the stored binding to its channel (RMK-930)
  • fix(events): a direct update_event that changes nothing writes and fires nothing (RMK-930)
  • fix(bindings): a binding change that changes nothing writes nothing and fires nothing (RMK-930)
  • fix(rooms): a transition already done does nothing and close_room refuses an archived room (RMK-930)
  • test(providers): per review, the connect-timeout default of the configs outside providers/ and three wire defaults are pinned again (RMK-922)
  • test(core): per review, the ACP cut waits on the turn behind the lock, the flush bounds and four RFC defaults are back (RMK-923)
  • test(providers): the provider tests wait for what they waited for, and build no real SDK client they do not use (RMK-922)
  • test(providers): delete config tests that read back what they set (RMK-922)
  • fix(hooks): a hook's modify cannot widen a framework record's internal: the visibility is put back whenever the original holds it (RMK-930)
  • fix(visibility): the record stored in place of an answer at the depth limit carrying internal is stored none, within its trigger's answer scope (RMK-930)
  • fix(hooks): a decided event's injected events run in a task the kit holds, so a cancelled or failing caller loses none (RMK-930)
  • docs(c7): hook_error is emitted by every BEFORE_BROADCAST pass, an answer's, an injected event's and a streamed row's included (RMK-930)
  • docs(c7): injected events commit after their cause released the lock, fire AFTER_BROADCAST, reach a realtime model silently; only BEFORE_BROADCAST commits them; internal, room hook names, off-lock errors (RMK-930)
  • fix(hooks)!: a hook's injected events commit after their cause released the room lock, each in a section of its own (RMK-930)
  • fix(lanes): a closed room turns away the record in place of a refused answer with room_refused_event, operation reentry (RMK-930)
  • feat(hooks): an injected event's delivery set fires AFTER_BROADCAST, and a realtime host takes it silently (RMK-930)
  • fix(hooks): an off-lock hook's hook_error is emitted when it is met, before the lock, whatever the gates decide (RMK-930)
  • fix(visibility): only the framework writes internal: the doors refuse it, a hook's modify has it put back, a channel's answer carrying it is stored none (RMK-930)
  • fix(hooks): a name a room enables on the turn executors joins the room's hooks, so a room never holds two hooks of one name (RMK-930)
  • fix(hooks): a SYNC hook's injected events on a trigger other than BEFORE_BROADCAST are dropped with a warning, never silently (RMK-930)
  • test: per review, every exported name, the RFC's interruption defaults and the recording strings are pinned again, and a wait_for bound is expired too (RMK-924)
  • test(core): the core tests wait for what they waited for, with budgets in milliseconds and no production hashing cost (RMK-923)
  • test(typing): the mypy subclass check runs with ty in make typecheck and CI's type check, not in every test run (RMK-923)
  • test(core): delete tests of nothing, table the range checks and pin each stored value once (RMK-923)
  • refactor(core): a closing lane's task grace is a module constant, so a test can shorten it (RMK-923)
  • test(voice): the GPT-Live call helpers wait for the events read, not 0.1 s, and a close nobody answers 0.01 s (RMK-924)
  • refactor(voice): the outbound pacer's stop grace is a module constant, so a test can shorten it (RMK-924)
  • fix(edits): a delete the persistence policy does not store still marks its target's edits deleted (RMK-930)
  • fix(store): init() adds a missing events column only, and the default commit finds edits by their target (RMK-930)
  • docs(edits): a delete marks its target's edits deleted, and a DELETE row alone hides nothing (RMK-930)
  • fix(edits): a delete's commit marks every edit of its target deleted, so an edit outside its target's window stays withheld (RMK-930)
  • docs(storage): a store records a delivery set's results alone (RMK-930)
  • fix(sqlite): a soft-deleted message leaves the full-text index (RMK-930)
  • fix(history): only a target's deleted mark withholds it, never a DELETE row alone (RMK-930)
  • fix(delivery): a failed delivery's record writes its results alone and undoes no edit or delete (RMK-930)
  • fix(regenerate): a regeneration and a held message's release re-run no agent on a deleted message or a change row (RMK-930)
  • fix(discussion): a message deleted while it waits gives no turn and no dispatch decision (RMK-930)
  • docs(rooms): room ids are global, and a refused creation says only that the id is taken (RMK-930)
  • fix(buzz): the huddle watcher feeds only the announcements room it opens (RMK-930)
  • docs(edits): what an edit or a delete is and may target, who may make it, the withheld history, the hard delete and a room created once (RMK-930)
  • fix(store): a room is created once, every store refusing an id it holds (RMK-930)
  • fix(edits): a hard delete takes the removed events' edits and deletes and fires ON_EVENT_DELETED per event (RMK-930)
  • fix(history): a soft-deleted event's content is withheld from every history a channel is handed (RMK-929, RMK-930)
  • fix(edits): a change's target is read and validated again after hooks ran under the lock (RMK-930)
  • fix(edits): an accepted change is narrowed to its target's audience and delivered with its target as committed (RMK-930)
  • fix(hooks): a modify keeps a change's edit_source, delete_type and kind of content (RMK-930)
  • fix(edits): a response and a hook's injected event take step 8a, an injected change a SYSTEM one only (RMK-930)
  • fix(edits): ADMIN is an active OWNER or AGENT, and a channel's own output speaks as no participant (RMK-930)
  • fix(edits): a change targets an event that is not BLOCKED, not deleted and not itself a change (RMK-930)
  • fix(edits): an edit or a delete is told by its type and its content together, and a change held elsewhere is refused (RMK-930)
  • fix(edits): an edit or a delete commits with its target in one store transaction (RMK-930)
  • test(voice): the voice tests wait for what the channel did, not for fixed pauses or production budgets (RMK-924)
  • test(voice): delete tests of nothing and copies, and pin the voice hook triggers once (RMK-924)
  • test(orchestration, tasks): per review, three rewritten tests catch again what their old version caught (RMK-925)
  • test(orchestration, tasks): the rest of the area waits on the end it needs, and its time budgets are counted or marked (RMK-925)
  • test(orchestration, tasks): the delegation tests expire the library's own bound instead of waiting it out (RMK-925)
  • test(orchestration): the discussion tests wait for what they waited for, not for a mock's delay (RMK-925)
  • test(orchestration, tasks): delete tests of nothing and exact copies (RMK-925)
  • fix(scripts): test_redundancy reads a run whose test file was deleted since (RMK-925)
  • test(instructions): a hook's modify of a real response to an instruction, buffered or streamed, neither changes nor removes its fingerprint (RMK-930)
  • fix(instructions): an instruction is the caller's, a parser's INSTRUCTION type is put back to the message's, an empty key is no key on send_event, and a refused handoff greeting is logged (RMK-930)
  • fix(responses): the pipeline clears verification on every response, not only one claiming another source (RMK-930)
  • refactor(instructions): name the response drop after what it does, a predicate that logs the drop (RMK-930)
  • fix(instructions): a hook's injected INSTRUCTION is dropped with a warning before any pass, and the rest of its result stands (RMK-930)
  • fix(instructions): a channel's response typed INSTRUCTION is dropped with a warning and does not re-enter (RMK-930)
  • fix(instructions): the pipeline writes the instruction fingerprint over the instruction's text form and reserves its key, an instruction names a registered agent before anything is read, and a modify keeps standalone and the fingerprint (RMK-930)
  • test(identity): two concurrent links of one address leave one winner on Postgres (RMK-930)
  • feat(identity): unlink_address frees an address, so moving one is an unlink then a link (RMK-930)
  • fix(routing): a routed room that does not bind the channel is attached under the lock that checks it (RMK-930)
  • fix(routing): a routed room is checked again under its lock, not only its binding (RMK-930)
  • fix(routing): the router is given the organization and the identity, and searches the organization's rooms only (RMK-930)
  • fix(identity): an address belongs to one identity per organization, and an organization links its own identities only (RMK-930)
  • docs(speaking): ON_SPEAK_DECISION is SYNC in the hooks page and the CHANGELOG, with its migration, and examples/raise_hand_on_offer.py turns an offer into a raised hand (RMK-914)
  • feat(speaking): a question put to someone else is theirs to answer first (RMK-914)
  • fix(speaking): a thought taken while the agent answers in the room wants to say nothing yet (RMK-914)
  • feat(speaking): a turn about the agent said to someone else does not address it, and asking whether it is ready to listen is not a request for quiet (RMK-914)
  • feat(speaking): a turn is unfinished by how it ends, not by a hesitation inside it (RMK-914)
  • feat(speaking): what the agent has in mind is weighed against a question still open, not the last turn alone, and a postponed one holds a listening room's offer (RMK-914)
  • feat(speaking): a room that listens lets the agent ask for the floor, decided late on its thought (RMK-914)
  • feat(speaking): a thought back after its event was decided is decided again, for the ON_SPEAK_DECISION hooks to act on (RMK-914)
  • feat(speaking): a SYNC ON_SPEAK_DECISION hook changes the decision before the channel acts on it (RMK-914)
  • fix(ai): dispatch host tools through the resolved turn handler
  • fix(voice): an ON_TRANSCRIPTION attribution given words no speaker was attributed to is logged, not dropped silently (RMK-904)
  • test(voice): the speaker fixtures name a sample person, not the maintainer (RMK-904)
  • test(ai): the turn cancelled from outside is cancelled once its provider was asked, not after a fixed 0.1 s a loaded CI outlasted (RMK-921)
  • test(streaming): the failed-response test cancels its channel's pull once the failure is read, not after a fixed 5 ms a turn crossing Redis outlasted (RMK-921)
  • test(video): the video channel and vision integration tests await the analysis instead of sleeping for it (RMK-921)
  • test(conference,video): tidy the pruning per review: bounds kept where a timer was dropped, three contracts back, the export test's sweep finished (RMK-921)
  • fix(test): the pruning gate fails on a test rewritten in place or failing, and compares functions, not their cases (RMK-921)
  • test(conference,video): slow tests wait on configured budgets and on events, and a duration is asserted only where it is the behaviour (RMK-921)
  • test(conference): a scenario another test already asserts more of is not run twice, and input variants are one table (RMK-921)
  • test(video): copy-paste variants are parametrized, duplicates are gone, and two tests that passed without their subject now check it (RMK-921)
  • test(video,conference): tests of what Python, dataclasses and enum guarantee are gone, and one test reads every subpackage's exports (RMK-921)
  • test: diff tells a line a deleted test took away from one a race let a remaining test miss, and fails only on the first (RMK-921)
  • test: scripts/test_redundancy.py lists the suite's pruning candidates per area and names the lines a pruning dropped (RMK-921)
  • fix(people): ParticipantRole.AGENT is a human agent who takes part, an AI participant is a BOT, and the discussion reads its people as every reader does, per RMK-911
  • test(context): the first fence counts its unicodedata reads instead of timing itself, so four workers on a four-core runner no longer push it past 50 ms (RMK-919)
  • fix(tests): --dist worksteal moves from addopts to the parallel commands, as the smoke and fastrtc CI jobs run a bare pytest that refused it (RMK-919)
  • test: the suite runs on one worker per core, make test-changed runs only what a change reaches, and CLAUDE.md states the rules a test meets (RMK-919)
  • fix(hooks): an injected event's transport targets have their tasks and observations collected, as at any delivery, per RMK-902
  • fix(identity): a pending sender writes under a record of its own, and routing and the tool actor follow the reach rule, per review (RMK-915)
  • refactor(identity): extract the identity_resolved announcement from _apply_identity_result (RMK-915)
  • fix(api): EventDirection is exported from roomkit, and send_event's docstring states the key per source channel and the visibility grammar, per RMK-902
  • fix(hooks): an injected event is committed as a pass of its own and asks no agent, per RMK-902 (RMK-333)
  • fix(identity): an id names its participant only on a channel they are reached through, for their role, authority, identification and verification as for their name (RMK-915)
  • fix(pipeline): responses are written as their responder's, idempotency keys are per source channel, a blocked replay is answered blocked, and a failed lock release changes nothing, per RMK-902
  • test(tasks): the inline delegation's caller times out while the worker's turn runs, never before the task is announced, per CI (RMK-910)
  • test(verification): the release in another process runs on a real Postgres in CI, under a sender of its own (RMK-908)
  • fix(tasks): a call joins a cancel being completed only while the task ended cancelled, within its reach, before the hand-back is decided; the console decides as the tool does, per review (RMK-910)
  • fix(channels, anam): a coroutine returned where no loop runs is closed, not dropped unawaited (RMK-909)
  • fix(voice, turns): three more places start the work they were handed inside its task or close it unstarted, per review (RMK-909)
  • fix(hooks): unusable results, the identity a replacement keeps, and unique hook names, per RMK-902
  • fix(verification): a held delivery is named at its commit under the room lock, a release's answer stays named when its reader is detached, and the handle's reach is stated, per review (RMK-908)
  • fix(ai): a turn its provider refused to answer is logged with the provider's reason (RMK-912)
  • fix(speaking): the thought note carries the agent's impression, never its own thought, so Claude no longer refuses every later turn (RMK-912)
  • fix(verification): a held message's delivery stays named until its release is answered, and a cancelled one is released with no answer (RMK-908)
  • fix(tasks): a task is announced once ON_TASK_DELEGATED fires, a failed end keeps its turn's record, a cancel_task joins a cancel being completed (RMK-910)
  • fix(channels): work handed to a task of its own is run by the task itself, so a task cancelled before its first step leaves nothing unawaited (RMK-909)
  • fix(core): a channel's max_length cuts a composite's text parts and below four code points without the marker, and a nameless location reads its coordinates alone, per RMK-902 (RFC §6.6)
  • fix(core): visibility, direction and source refusal as the RFC now states them, per RMK-902
  • fix(ai, voice): per review, observers and people the agent never hears take no part, the people note quotes each name, a voice matched by id alone reads under its participant's record, and one label matched to two participants is two turns (RMK-904)
  • perf(channels): the split-copy scan remembers each boundary by its window, so a run slid out of a memory's window scans its new boundary only, per review (RMK-882)
  • fix(orchestration): the Pipeline strategy refuses a realtime channel, a handoff to an agent with nothing to set gives the channel's prompt, per review and decision (RMK-873, RMK-872)
  • docs(turns): the backend contract names the owner's hosted channels and attach recipients, backend_closed reads as such, tests cover each door, per review (RMK-878, RMK-880, RMK-881, RMK-883, RMK-901)
  • fix(tasks): only a worker run's own entry ends its task's line under another action, never one a turn posts, per security review (RMK-875)
  • fix(tasks): the host's cancel_task joins an agent's, the runner contract says who ends a refused task, a worker run keeps a caller's on_complete, per review (RMK-874, RMK-871, RMK-875)
  • fix(tasks): a strategy run's terminal entry under its own action ends its task's line, the Loop's included, per review (RMK-875)
  • fix(tasks): another agent's stream failure is never a buffered worker's, and is logged once as its turn's, per review (RMK-879)
  • perf(channels): a run of unanswered messages known clean is scanned for split copies at its new boundary only (RMK-882)
  • fix(orchestration): the Pipeline strategy's realtime wiring runs only the rooms it is installed in, each with its own handler (RMK-873)
  • fix(orchestration): the Pipeline strategy wires its voice channel, greeting and farewell parameters (RMK-873)
  • refactor(orchestration): extract the handoff greeting from ConversationPipeline into HandoffGreeting (RMK-873)
  • fix(turns): an owner call cancelled before its task's first step leaves no coroutine unawaited (RMK-901)
  • fix(orchestration): one builder for a realtime agent's prompt; a language change never empties the session's (RMK-872)
  • refactor(redis): one client_options for every Redis client, the pub/sub watch and each call bound tested, per review (RMK-868)
  • docs(changelog): what redis-py 8.0.0 does to a turn backend on a unix socket, measured, per review (RMK-869)
  • docs(telemetry): the ended spans kept weigh about 5 MB at most, measured, per review (RMK-877)
  • fix(turns): room_attached and room_detached reach only the executors that may run the channel's turns (RMK-881)
  • fix(turns): a live agent's turn fails no_executor once the kit's own executor closed, never a host's copy (RMK-880)
  • refactor(turns): one builder for the no_executor refusal, room hooks included, and a Redis twin of the given-up turn test (RMK-883)
  • docs(turns): TurnLinkError names backend_closed, and a test reads it on both backends (RMK-878)
  • fix(tasks): another agent's failed turn in the child room no longer fails the delegated task (RMK-879)
  • test(tasks): past the bound of ended tasks kept, a line still listed running is no task of the room (RMK-876)
  • fix(tasks): two cancel_task calls on one task cancel it once, both answered cancelled, neither told it back (RMK-874)
  • fix(tasks): a task its runner refuses, or whose run raises outside its turn's outcome, ends failed once (RMK-871)
  • fix(orchestration): a worker run's terminal entry names its task, so a cut or cancelled worker's line ends (RMK-875)
  • feat(ai): who takes part is read from the room's roster, silent people included (RMK-904)
  • feat(voice): an ON_TRANSCRIPTION hook can match a voice to the room participant it is (RMK-904)
  • fix(models): the RFC's data model, per RMK-902 (latest_index, EventDirection, event ids, UTC timestamps, DeliveryMode)
  • test(context): the first fence's timing runs after a collection, so a full GC never lands in it (RMK-901)
  • fix(hooks): an ASYNC observer of a SYNC-run trigger no longer holds up the operation it observes (RMK-903)
  • docs(changelog): the Redis turn backend guide says redis-py 8.0.0 does not serve a unix socket (RMK-869)
  • fix(telemetry): OpenTelemetryProvider keeps the latest 10,000 ended spans, as their contexts (RMK-877)
  • fix(redis): the delivery queue, status bus and realtime clients give up a half-open connection within a bound (RMK-868)
  • fix(core): a delivery is located with its room, not at its commit, and the pre-commit tests cover every step, per review (RMK-899)
  • fix(identity): a pre-commit timeout during identity resolution refuses the message instead of raising UnboundLocalError (RMK-899)
  • fix(core): a delivery key names its message from process_inbound's start (RMK-899)
  • fix(voice): the words quoted in a cut answer's mark cannot close it
  • feat(voice): a cut answer reads with the words the person heard of it
  • feat(voice): list_local_models(kind=None) (RMK-898)
  • feat(voice): Nemotron 3.5 streaming STT, a stream told its language (RMK-895)
  • feat(voice): Moonshine STT in SherpaOnnxSTTProvider, Moonshine v2 tiny and base as local models (RMK-897)
  • feat(voice): Kitten TTS in SherpaOnnxTTSProvider, Kitten v0.8 nano and mini as local models (RMK-896)
  • feat(voice): eight more local models, and examples that download theirs by name (RMK-894)
  • feat(voice): local models download once by name, Kokoro voices by name, RNNoise from the pyrnnoise wheel (RMK-893)
  • fix(voice): an acknowledgement whose first partial echoed the response fires ON_BACKCHANNEL once (RMK-892)
  • fix(voice): an acknowledgement said word by word no longer cuts the agent at its first partial (RMK-889)
  • perf(voice): an agent's first turn no longer waits for the mark patterns (RMK-888), and an abandoned Voxtral session closes in 0.2 s
  • Begin 0.108.0.dev0 development

Full Changelog: v0.107.0...v0.108.0