Skip to content

feat: wasm fold - #5503

Merged
ehayes2000 merged 4 commits into
new-ai-agentsfrom
wasm-fold
Aug 10, 2026
Merged

feat: wasm fold#5503
ehayes2000 merged 4 commits into
new-ai-agentsfrom
wasm-fold

Conversation

@ehayes2000

Copy link
Copy Markdown
Contributor

No description provided.

@ehayes2000
ehayes2000 requested a review from a team as a code owner August 7, 2026 16:38
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c2031a28-f93c-4849-8da8-01dadcb22c7b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@ehayes2000
ehayes2000 changed the base branch from new-ai-agents to placeholder-comms August 7, 2026 16:39
@ehayes2000 ehayes2000 changed the title Wasm fold feat: wasm fold Aug 7, 2026
@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown

@ehayes2000
ehayes2000 force-pushed the wasm-fold branch 2 times, most recently from ef00797 to b76f46b Compare August 7, 2026 20:01
@ehayes2000
ehayes2000 marked this pull request as draft August 9, 2026 23:51
@ehayes2000
ehayes2000 force-pushed the wasm-fold branch 2 times, most recently from 7d55e7e to 61780d2 Compare August 10, 2026 13:46
@ehayes2000
ehayes2000 marked this pull request as ready for review August 10, 2026 14:11

@404Wolf 404Wolf left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Okay, overall this makes sense. A few nits but mostly good.

One thing Im thinking--

We're folding on the backend so that we can ensure we have the null comms messages. The method that does the fold in the PlaceholderLogs thing ALSO fires out the raw event too. This feels like weird coupling. But moreover, if we're doing the fold on the backend, AND we have catch-up logic on the backend, maybe it just makes sense to do all the fold work on the backend (including sending pre-folded stuff over connection gateway). Not to crush your wasm dreams, but maybe you should have claude switch to backend-driven folding and see what it looks like -- I think it might rip out a lot of complexity.

PlaceholderSyncingLogs is 1:1 with a agent session, I wish somehow the type system could enforce this.

/// prompt and one reply, opened with `session/new`.
///
/// Recordings under `~/.agent_runtime_sessions` are real ACP traffic, so
/// unlike [`TURN`] this was not hand-shaped to exercise anything in

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How do you feel about bringing in insta (or similar)?
I feel like we'll have only more and more snapshots here for testing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Insta looks good. Def better than testing.rs. I'll add it

/// into the log row the fold consumes.
///
/// Prompts get a user id attached, mirroring what the agent service stamps
/// onto `agent_session_log.user_id` for user-originated ACP traffic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

fn parse_line(session: AgentSessionId, line: &str) -> AgentSessionLog {
    let content: Message =
        serde_json::from_str(line).expect("recorded line deserializes as a message");

    let is_prompt = matches!(
        &content,
        Message::ToRuntime(ToRuntimeMessage::Acp(acp))
            if matches!(
                &acp.0,
                RawJsonRpcMessage::Request(request)
                    if PromptRequest::matches_method(&request.method)
            )
    );

    AgentSessionLog {
        agent_session_id: session,
        user_id: is_prompt.then(|| {
            MacroUserIdStr::try_from_email("eric@example.com").expect("test email parses")
        }),
        content,
    }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In general we should go through and update the method == "session/prompt" to use the actual helpers from the crate


use agent_client_protocol::Channel as AcpChannel;
use agent_client_protocol::{Channel as AcpChannel, TransportFrame};
use futures::StreamExt;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't know if there's really a solution here, but all of this init logic is basically only used in tests/examples, we use the agent_session state machine in reality

/// A bot that has been deleted still has messages in the channel, so this
/// answers for one rather than failing - a session's history should not
/// stop rendering because its agent was removed.
fn session_bot(&self, id: BotId) -> impl Future<Output = Result<SessionBot>> + Send;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If this is just bot id -> bot shouldn't we just use the existing bot hex?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes


/// An [`AgentSessionRealtime`] that streams nowhere.
///
/// Dropping every frame is a legal implementation of the port - it is

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe cleaner if we just impl for ()? idk

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think an explicit unit struct is more obvious than a null impl on a unit type.


/// One entry as a client reads it back: the attribution, and the frame's own
/// two fields flattened in beside it.
///

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this is dumb we should use AgentSessionLogEntryDto

}

/// Serialize a log the way the endpoint does, then decode it the way a client
/// would.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I just think this/many of these tests are dumb

///
/// Buffers are per-thread and cleared on entry, so parallel tests cannot see
/// each other's warnings and a bare fold elsewhere cannot leak into one.
pub fn capturing_warnings<T>(body: impl FnOnce() -> T) -> (T, Vec<CapturedFields>) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we really need this

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This file smells

/// placeholder builds it, and whoever renders one reproduces it from the same
/// parts - which now includes the browser, folding the same log through this
/// crate compiled to WASM. It lives here, with the ids it is made of, so those
/// two cannot drift; the string is persisted, so drift would silently

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also, for this, maybe we should have a real column on comms message that is like "associated_agent_session" rather than smushing it in the ID? and then we can literally use the MessageId newtype? I thought we already added that column but maybe I'm forgetting.

/// The composite id a placeholder comms message stores in its
/// `agent_session_message_id` column: `"{agent_session_id}:{turn}:{author}"`.

@404Wolf

404Wolf commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

the deduplicate typescript file smells, i feel like we're hacking around the issue that folded messages and real channel messages can get mixed together. we should be using IDs to dedupe not text

The current frontend deduplication matches folded prompts to posted messages by exact text. the content is stored in a Set, so one posted message can match and hide multiple folded prompts with the same content. like if you post "yes" would hide every folded "yes" prompt in the loaded channel (like if 6 people sent "yes"), even when they represent different turns that just happen to have the same content.

Maybe the folded messages we send to the frontend should include the dummy comms message entry ID (claude sketch):

Frontend posts comms message
    ↓
Kafka event includes comms message ID
    ↓
Backend creates ForwardMessage
    ↓
ForwardMessage retains source message ID
    ↓
Backend logs ACP prompt with that provenance
    ↓
Fold exposes source message ID
    ↓
Frontend receives folded message with source message ID

@ehayes2000
ehayes2000 force-pushed the wasm-fold branch 2 times, most recently from 9edc24a to 4bcf002 Compare August 10, 2026 20:03
Base automatically changed from placeholder-comms to new-ai-agents August 10, 2026 20:54
@ehayes2000
ehayes2000 merged commit 8ef80e3 into new-ai-agents Aug 10, 2026
5 checks passed
@ehayes2000
ehayes2000 deleted the wasm-fold branch August 10, 2026 21:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants