Skip to content

feat(progressive): execute canonical typed output events - #145

Merged
senamakel merged 34 commits into
mainfrom
7964-tinychannels-progressive-current-main
Oct 24, 2026
Merged

senamakel merged 34 commits into
mainfrom
7964-tinychannels-progressive-current-main

Conversation

@senamakel

@senamakel senamakel commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Adds typed progressive output execution to the TinyChannels module. Hosts can feed ordered ChannelOutputEvent batches with turn and conversation scope; final messages use provider-owned SendTyped, and returned delivery results preserve receipts and partial outcomes. The existing legacy Feed operation remains available. The module dependency now disables TinyChannels defaults so its explicit whatsapp-web feature controls that stack.

Refs tinyhumansai/openhuman#7964
Refs #99

Verification:

  • cargo fmt --all -- --check
  • cargo check --workspace
  • cargo clippy -p tinychannels-module --all-targets -- -D warnings
  • cargo test -p tinychannels-module (201 passed; 3 artifact tests ignored by design)
  • cargo test -p tinychannels-bus (103 passed)
  • Focused feed_output_forwards_canonical_events_in_order_with_delivery_scope regression passed.

senamakel and others added 15 commits October 22, 2026 22:52
Advance the tinybus and wiki submodule pointers to their latest commits.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a test asserting that FeedOutput forwards canonical events in order,
assigning consecutive sequence numbers from the supplied starting point and
preserving the turn id on each transport request.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…port

Add a FeedOutput command that carries canonical channel output events
through the module's ordered transport, with a sequence number giving each
batch a stable delivery identity so hosts can retry without changing it.
The sender dispatches each event to the controller backend and the worker
rejects batches larger than 32 events or replies that are already closing.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adjust the expected final message in the progressive feed test to build
OutboundContentPart::Content with the part field instead of content and
caption, matching the current channel API.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the progressive delivery test to include the new markdown_dialect field on text content parts, keeping it in sync with the bus content type. Also bump the tinybus and wiki submodule pointers.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test now filters transport requests down to output events before
checking their count and order, so unrelated requests no longer break
the assertions.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…dependency

The module now opts out of the tinychannels crate's default features and enables only email, lark, and relay-websocket explicitly, so hosts that link it without those providers no longer pull in the default set.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add a ProgressiveResult::OutputUpdated variant carrying typed terminal
delivery results in event order, so callers can observe canonical output
events while retaining receipts and partial failures. Also derive Debug
and PartialEq on ProgressiveTransportResult to support comparison and
inspection of these results.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Output updates now collect the transport results produced while sending
typed parts and surface them through a new OutputUpdated variant, so
callers can observe individual deliveries instead of only a generic
updated status.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
FeedOutput now forwards the handle to the worker and sends final
messages through the typed transport, collecting the resulting
deliveries so callers receive OutputUpdated instead of a bare Updated.
The Feed path keeps returning Updated since it produces no deliveries.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The progressive transport fixture now answers SendTyped requests with a
ChannelSendOutcome carrying a platform message id, and the output forwarding
test asserts that the final message is delivered through typed provider
transport with the expected turn, sequence, idempotency key and parts.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Final message events now carry their original receipt through to the
rebuilt event, so a delivery that returns no outcome no longer drops it.
Formatting in the affected modules was also tidied up.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The FeedOutput variant now stores its channel and conversation references
behind Box, shrinking the enum so the common variants stay small.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The FeedOutput command now dereferences the borrowed channel_ref and conversation values so the owned types expected by the command are produced.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The output event and typed send helpers took the channel, turn, and
conversation as separate arguments, which made call sites long and easy to
mix up. These are now bundled into an OutputScope struct, and the FeedOutput
command variant carries a boxed FeedOutput struct so the enum stays small.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@tinysweeper

tinysweeper Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Reviewed head: 10bae518f3e43c996d04d5b30053531015d04577

Findings

No active actionable findings.

Unverified notes — repository context was unavailable; these are not actionable findings

Unverified note — critique

  • high: Store the batch's start sequence, not the rebound loop sequence (crates/tinychannels-module/src/progressive.rs:885)
    Problem: `sequence` is the function parameter, but the `for` loop above shadows it with a per-event counter (`let sequence = sequence.checked_add(offset)…`), so by the time this line runs `
    Suggested fix:
    No concrete fix was supplied.

Verdict: Ready for maintainer review · Priority: none
Coverage: Reviewed 6 of 6 files.

Diagnostics and supporting details

Full summary

Pull request purpose (title): feat(progressive): execute canonical typed output events. Tiny Sweeper completed its review; deterministic results follow.

Review snapshot

Change surface Files Review signal Count
Production 4 Active findings 0
Tests 1 Noted findings 1
Documentation 0 Resolved findings 0
Configuration 1 Pending checks/questions 0

Completeness: Complete
Test assessment: Test coverage is assessed from changed tests and lane evidence; execution is not claimed without trusted check data.

Features

  • Added — FeedOutput progressive command: Hosts submit ordered canonical output-event batches scoped to turn, channel, and conversation; more than 32 events and a FinalMessage that is not last are rejected before anything is forwarded. (crates/tinychannels-bus/src/module_progressive.rs pub enum ProgressiveCommand {, crates/tinychannels-module/src/progressive.rs async fn run()
  • Added — Typed final delivery and ordered observation callbacks: A FinalMessage is sent through provider-owned SendTyped with a handle-and-sequence idempotency key, and each event is forwarded to an observation callback in order; callback failures are recorded by sequence instead of aborting the batch or erasing completed provider sends. (crates/tinychannels-module/src/progressive.rs impl ProgressiveSender for Sender {, crates/tinychannels-bus/src/module_progressive.rs pub enum ProgressiveCommand {)
  • Added — OutputUpdated result: Callers receive typed delivery results in event order plus the sequences whose observation callbacks failed. (crates/tinychannels-bus/src/module_progressive.rs pub enum ProgressiveCommand {)
  • Added — Output batch replay and staleness checks: Identical retries return the cached result and re-run only failed callbacks, and same-sequence content or scope changes error; per the description lane, sequences at or below the previous batch's end are reported stale, so a contiguous next batch starting at the previous end is rejected and a turn cannot advance past its first batch. (crates/tinychannels-module/src/progressive.rs async fn run()
  • Added — Atomic content-limit precheck: Oversized text, thinking, or final-message content is rejected before any event is forwarded, keeping reply state consistent. (crates/tinychannels-module/src/progressive.rs const MAX_CONTENT: usize = 384 * 1024;)
  • Modified — Terminal batch ends the worker: A successful batch containing a FinalMessage triggers external-final cleanup and ends the worker, so the entry is terminal and a later Close emits no cancellation or second legacy send. (crates/tinychannels-module/src/progressive.rs async fn run()
  • Added — External-final cleanup of draft and ephemeral bubbles: After a confirmed external final the stale draft message is deleted and draft/dirty flags cleared, while a failed or merely accepted delivery leaves the draft visible; filler and thinking bubbles are removed either way, and the existing finalize path's ephemeral cleanup moves to a shared helper with unchanged order. (src/delivery/progressive/reply.rs impl ProgressiveReply {, src/delivery/progressive/finalize.rs pub(super) async fn finalize_channel_reply()
  • Added — Scope threaded through draft transport: Draft send, edit, delete, and typing inherit the active batch's turn, channel, and conversation scope; a legacy Feed clears the scope while the first accepted output batch binds it for the reply's lifetime. (crates/tinychannels-module/src/progressive.rs impl ProgressiveSender for Sender {, crates/tinychannels-module/src/progressive.rs async fn run()

Tests

  • unit — Replaying an accepted batch is expected to retry only the failed OutputEvent callback and not repeat SendTyped; an identical retry of a plain delta is expected to avoid re-appending it, and reusing the same sequence with changed text is expected to error.: Added in the pull request; covers replay identity and duplicate-delta suppression. Execution is not confirmed by trusted check evidence. (crates/tinychannels-module/src/progressive_tests.rs async fn handles_cannot_cross_private_runtime_reply_stores() {, crates/tinychannels-module/src/progressive.rs async fn run()
  • unit — Draft send, edit, delete, and typing are expected to each carry the bound turn, channel reference, and conversation, and an accepted typed final is expected to keep the flushed draft while a confirmed final deletes it.: Added in the pull request; covers scope threading and the accepted-versus-delivered cleanup distinction. Execution is not confirmed by trusted check evidence. (crates/tinychannels-module/src/progressive_tests.rs async fn progressive_edits_and_deletes_preserve_target_and_message_id() {, src/delivery/progressive/reply.rs impl ProgressiveReply {)
  • unit — Existing thinking-limit and edit/delete target preservation tests are expected to keep their assertions after adapting to the new Sender constructor.: Adjusted in the pull request; the adaptation is mechanical construction changes. Not confirmed as executed here. (crates/tinychannels-module/src/progressive_tests.rs async fn thinking_limit_is_atomic_and_independent_of_text_budget() {, crates/tinychannels-module/src/progressive_tests.rs async fn progressive_edits_and_deletes_preserve_target_and_message_id() {)

Before merge

None.

How this fits together

flowchart LR
  n0["ProgressiveCommand<br/>changed"]:::changed
  n1["ProgressiveTransportRequest<br/>changed"]:::changed
  n2["Closing<br/>changed"]:::changed
  n3["Replies<br/>changed"]:::changed
  n4["Callback<br/>changed"]:::changed
  n5["...nking_and_tool_state_before_terminal_send<br/>changed"]:::changed
  n6["fixture"]:::impacted
  n7["Result"]:::impacted
  n8["FeedOutput"]:::impacted
  n9["expect"]:::impacted
  n10["execute"]:::impacted
  n11["...receipts_when_output_event_callbacks_fail"]:::impacted
  n2 -->|uses| n7
  n4 -->|uses| n1
  n5 -->|calls| n6
  n5 -->|tests| n6
  n6 -->|uses| n3
  n6 -->|uses| n4
  n10 -->|uses| n0
  n10 -->|uses| n7
  n10 -->|calls| n8
  n10 -->|uses| n8
  n11 -->|calls| n6
  n11 -->|tests| n6
  n11 -->|uses| n8
  n11 -->|calls| n9
  n11 -->|tests| n9
  classDef changed fill:#0d4429,stroke:#238636,color:#e6edf3
  classDef impacted fill:#161b22,stroke:#6e7681,color:#c9d1d9
  classDef flagged fill:#5a1e02,stroke:#d93f0b,color:#ffffff
  classDef blocking fill:#67060c,stroke:#f85149,color:#ffffff
Loading
Agent review details

critique

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The critique lane status is Answered, but the evidence supplies no finding text for it, so no critique finding can be described here.
  • Lane summary: Reviewed 2 files; 4 findings. _The code index is behind this pull request (indexed at `9176e4aa07a6`), so retrieved context may be out of date._

security

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The security lane answered with no findings for this pull request.
  • Lane summary: Reviewed 2 files; 0 findings. _The code index is behind this pull request (indexed at `9176e4aa07a6`), so retrieved context may be out of date._

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The tests lane answered that the FeedOutput path, the Sender scope threading, and the external-final cleanup are covered by new tests in progressive_tests.rs asserting on ordering, receipts, replay identity, scope on transport requests, and the accepted-vs-delivered cleanup distinction.
  • Lane summary: The prior lookup round was inconclusive; I made no additional lookups. Nothing in the diff as presented is a defect I can name with a concrete failing input: the new `OutputScope`/replay bookkeeping, the `FeedOutput` arm, the `cleanup_after_external_reply` split, and the `default-features = false` change in `crates/tinychannels-module/Cargo.toml` are all plausible given only this excerpt, and I cannot see the definitions of `ChannelOutputEvent`, `ProgressiveTransportResult`, or the pre-existing `ChannelBackendRequest::ProgressiveTransport` variants to confirm any mismatch. The repo-instruction rules quoted are style/process rules, and I see no violation of the behavioural ones (contract types live in `tinychannels-bus`, tests are in `progressive_tests.rs`, not `#[cfg(test)] mod tests`). I am not reporting a finding, and I am explicitly not treating the doc comments' invariants ("hosts can retry the same batch without changing its delivery identity", "Failed output-event callbacks are reported by sequence") as verified. _The code index is behind this pull request (indexed at `9176e4aa07a6`), so retrieved context may be out of date._

commits

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The commits lane answered that it found no sensitive content in committed files.
  • Lane summary: No sensitive content in committed files. _The code index is behind this pull request (indexed at `9176e4aa07a6`), so retrieved context may be out of date._

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The description lane answered that the description matches the diff: it names the FeedOutput command with turn/conversation scope, provider-owned SendTyped for final messages, preserved receipts and partial outcomes, the retained legacy Feed, and the disabled default features.
  • Positive: The description lane answered that sequences at or below the previous batch's end are reported stale, so a contiguous next batch starting at the previous end is rejected.
  • Lane summary: I need to check a few definitions before judging: `ProgressiveSender`'s `typing`/`send`/`edit`/`delete` signatures (to see whether the scoped sender's `apply_scope` rewrites the `channel` field the caller passes, which the new tests assert), the `run` worker's `is_final`/`break` handling and `ProgressiveReply::finalize` behaviour, and `ChannelOutputEvent`'s variants and `FinalMessage` fields so I can tell whether the receipt-preservation logic and the _The code index is behind this pull request (indexed at `9176e4aa07a6`), so retrieved context may be out of date._
Evidence and run details
  • Models: ladder/vectors-oai3, deepseek-v4.1-flash
  • Spend: $0.017581
  • Tokens: 726704 input · 11256 output · 160294 cached · 715 embedding
  • Updated: 2026-10-23T01:18:44Z
  • Continuity: summary cache chain restarted at the storage ceiling.
Head State Pass summary
08b4ddc52292 ready for maintainer review 0 active finding(s), 0 resolved finding(s) (at 2026-10-22T23:31:05Z)
9176e4aa07a6 ready for maintainer review 0 active finding(s), 0 resolved finding(s) (at 2026-10-22T23:44:30Z)
16ec785aec23 ready for maintainer review 0 active finding(s), 0 resolved finding(s) (at 2026-10-23T00:09:05Z)
0ccac67a8aa2 ready for maintainer review 0 active finding(s), 0 resolved finding(s) (at 2026-10-23T00:31:06Z)
10bae518f3e4 ready for maintainer review 0 active finding(s), 0 resolved finding(s) (at 2026-10-23T01:18:44Z)

tinysweeper 0.1.2

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

  • Run on-demand review

This review includes 6 billable files and costs up to $1.50.

Or wait 55 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7eef2288-474a-4903-be9c-5bf53124296c
📥 Commits

Reviewing files that changed from the base of the PR and between 40e7186 and 10bae51.

📒 Files selected for processing: 6
  • crates/tinychannels-bus/src/module_progressive.rs
  • crates/tinychannels-module/Cargo.toml
  • crates/tinychannels-module/src/progressive.rs
  • crates/tinychannels-module/src/progressive_tests.rs
  • src/delivery/progressive/finalize.rs
  • src/delivery/progressive/reply.rs
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-23T01:20:54.107001Z 10bae51 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking. Approving.

Diagnostics

Total spend: $0.0014

@tinysweeper tinysweeper Bot added the priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. label Oct 22, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ab6675257f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tinychannels-module/src/progressive.rs Outdated
Comment thread crates/tinychannels-module/src/progressive.rs
Comment thread crates/tinychannels-module/src/progressive.rs Outdated
Comment thread crates/tinychannels-module/src/progressive.rs
senamakel and others added 3 commits October 22, 2026 23:16
…ries

Output-event callback failures are now collected by sequence and returned
alongside transport deliveries instead of aborting the whole batch, so a
single failing callback no longer discards provider delivery results.
Sequence arithmetic is also checked for overflow before applying events.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The FeedOutput command variant now carries an AppliedOutput result instead of a vector of ProgressiveTransportResult, simplifying the response type returned to callers.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Progressive transport requests now carry the turn's output scope, so sends, edits, deletes and typing indicators are attributed to the correct turn and conversation. A replay cache was added to the entry so output batches can be reapplied, and the output event failures field is deserialized with a default for backward compatibility.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
@tinysweeper tinysweeper Bot added priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. and removed priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. labels Oct 22, 2026
Replaced the checked_add and unwrap_or fallback with saturating_add when computing the end of the previous event range, which is simpler and avoids the unreachable overflow branch. The test callback was also collapsed into a let-chain to match.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 08b4ddc522

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tinychannels-module/src/progressive.rs
@tinysweeper tinysweeper Bot added priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect. and removed priority: p2 Soon. Real but survivable — a rough edge, a gap, a thing that will bite later. labels Oct 22, 2026
senamakel and others added 3 commits October 22, 2026 23:34
Add a test that drives a progressive channel through a flushed draft followed by a typed final message, asserting the draft is sent first, the canonical final second, and the stale draft deleted last. This locks in the ordering guarantee for channels that support progressive edits.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The module now reports whether the final message was actually delivered by
the transport path, and the reply cleans up its draft, filler, and thinking
bubbles once that delivery succeeds. A failed delivery keeps the draft
visible while still removing the transient filler and thinking messages.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9176e4aa07

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tinychannels-module/src/progressive.rs Outdated
Comment thread crates/tinychannels-module/src/progressive.rs Outdated
Comment thread crates/tinychannels-module/src/progressive.rs
senamakel and others added 4 commits October 22, 2026 23:50
Output scope was applied to the sender before the batch was validated, so a
rejected batch left the sender pointing at the new scope. Scope assignment now
happens inside a wrapper that only runs once the output is accepted, and tests
cover the accepted typed final and over-limit final message paths.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The progressive reply test passed a string literal through into, which is
redundant since the literal already coerces to the expected type. Removing the
call keeps the test compiling without the extra conversion.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The callback fixture now stores a separate result for typed sends so tests can
control the typed transport outcome independently of the default result. The
accepted typed final test was updated to set this new field, keeping its
behaviour unchanged.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformatted the test assertions to satisfy rustfmt and replaced the empty-requests check with a filter that verifies no typed send or output event requests were issued, making the test's intent explicit.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 16ec785aec

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tinychannels-module/src/progressive.rs
Comment thread crates/tinychannels-module/src/progressive.rs
Comment thread crates/tinychannels-module/src/progressive.rs Outdated
senamakel and others added 5 commits October 23, 2026 00:10
…elta budget

Add tests verifying that the first scoped output batch starts typing with the
output batch scope, that a rejected legacy feed keeps the previous progressive
sender scope, and that repeated final text is not double counted against the
delta budget.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The typing tick was only sent once before the command loop, so scoped
feeds stopped refreshing the indicator after the first output. The tick
now runs after each non-terminal output that has an active scope, and
legacy feeds reset the scope through a dedicated helper. Oversized final
messages are also detected up front so they no longer slip past the
content limit check.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The legacy feed path now triggers a typing tick once the feed succeeds, and the output path only refreshes typing when the feed succeeded, was not terminal, and did not deliver a final message. The scope check was dropped since a successful feed already implies an active scope, and apply_legacy_feed now clears the scope only after applying events so a failure leaves state untouched.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test now wraps the channel and conversation references in `Box` to match the updated `ProgressiveCommand::FeedOutput` variant, keeping the scoped output typing test compiling against the boxed fields.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Typing indicators are now only emitted while a scope is set, so the
legacy feed path no longer triggers a typing tick after a successful
feed. This keeps typing state consistent with the scoped output flow.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0ccac67a8a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/tinychannels-module/src/progressive.rs
Comment thread crates/tinychannels-module/src/progressive.rs Outdated
senamakel and others added 3 commits October 23, 2026 01:14
Add tests asserting that replaying an accepted output batch retries the
failed observation callback without repeating typed delivery, and that a
reply handle rejects scope changes once its first batch is accepted.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replayed output batches now re-deliver events whose callbacks previously
failed instead of returning the cached result untouched, and the cached
result is refreshed when the replay matches. A reply handle also pins the
output scope of its first accepted batch so later batches cannot silently
switch scopes.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
FeedOutput now replays a previously applied batch through the same retry
path used by apply_output, so failed observation callbacks are re-run
instead of being dropped when a duplicate request arrives. The retry
logic was extracted into a shared helper to keep both paths consistent.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 10bae518f3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +426 to +428
if let Some(applied) = replay_output(previous.as_ref(), &scope, sequence, &events) {
let mut applied = applied?;
retry_failed_output_callbacks(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Retry transient typed-final delivery failures

When the initial SendTyped call returns Unavailable or its dispatch error is converted to Failed, the batch is still cached and the final event terminates the worker. An identical FeedOutput retry then takes this replay path, retries only failed observation callbacks, and returns the cached delivery failure forever, so a transient outage permanently loses the user's final response despite the stable idempotency key. Reattempt failed typed deliveries on replay while continuing to deduplicate successful or pending sends.

Useful? React with 👍 / 👎.

Comment on lines +916 to +917
if sender
.output_event(scope, failed_sequence, event.clone())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the enriched receipt when retrying final callbacks

If the first OutputEvent callback for a final message fails after SendTyped returns an Outcome, the initial callback contains the provider receipt, but this retry clones the original request event instead. That original event commonly has receipt: None, so the successful retry projects a final message without the delivery receipt even though it remains available in applied.deliveries; rebuild the retried final event with the cached outcome receipt.

Useful? React with 👍 / 👎.

reply.typing_tick().await;
}
},
_ = fillers.tick() => reply.filler_tick().await,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Gate filler sends until the output scope is known

For a FeedOutput turn whose first batch is delayed beyond FILLER_INTERVAL, this timer fires while Sender.scope is still None. Unlike the now-gated typing timer, filler_tick() always posts a static filler, so its Send request lacks the turn, account, and conversation references and can appear in the parent conversation or default account. Defer filler ticks until a scoped batch has been accepted, or make the scope available when the handle is opened.

Useful? React with 👍 / 👎.

@senamakel
senamakel merged commit a4a008c into main Oct 24, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority: p3 Whenever. Cosmetic, a nicety, or a cleanup with no user visible effect.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant