Repository navigation
Conversation
ThinkHarness replaces it. The AI SDK message conversions it was built on become the AI SDK projection, agents/experimental/channels/projections/ai-sdk, which ThinkHarness and the Web Channel's AI SDK transport use. The tool-answer helper moves into ThinkHarness, its only user. The channels example serves a Think agent in place of the AI SDK one.
piChannelsHarness moves from the channels example into the package, and its message-format conversions become the pi projection, agents/experimental/channels/projections/pi. Behaviour is unchanged, including #2519's handling of text that only a fuller copy carries.
…vent replaces reset A harness that gives a user message its own id reports it on placed and done, and Channels shows the message under the inbound message's id. The pi adapter therefore drops its own id store and its kv option, and moves each placed status ahead of the message it names, since pi publishes a commit's submissions after its entries. A transcript event, which replaces the whole active transcript, replaces the reset event: a message event cannot remove messages.
The pi adapter read its starting transcript and pending operations separately from pi's event snapshot, so a commit between the reads could be missed or seen twice. It now builds both from the snapshot, which pi takes atomically with the watch, and keeps the transcript from the entries that follow instead of re-reading it after every entry. It re-reads only when an entry moves the context's start or edits earlier entries, such as a compaction. A snapshot pi sends after an overflow replaces the transcript and ends or starts the run where it differs. The Channels glossary gains Client and Projection.
🦋 Changeset detectedLatest commit: 2252bc4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Contributor
🟡 agents import sizes: 1 entry point grew
Changed exports (20)
How this worksEach runtime export is bundled on its own, minified, and gzipped. Changes smaller than 100 B, or smaller than 1% and 1 KiB, are ignored. Growth over 10% or 5 KiB is marked 🔴. This report is informational and does not fail CI. The workflow artifact contains every measurement. Compared |
agents
@cloudflare/ai-chat
@cloudflare/codemode
hono-agents
@cloudflare/shell
@cloudflare/think
@cloudflare/voice
@cloudflare/worker-bundler
commit: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR removes
AiSdkHarness, moves the pi Channels adapter out of the channels example intoagents/harness/pi, splits each harness's message-format conversions into a projection, and moves message-id mapping from the pi adapter into Channels. It replaces the closed #2510.Why
PiHarnessis the flagship harness, but the code that serves it through Channels lived in an example, and it did work that belongs in Channels: it kept its own store of caller message ids and renamed pi's entries to match.ThinkHarnessnow covers whatAiSdkHarnessdid, so keeping both meant two AI SDK harnesses to maintain.PiHarness,ThinkHarness,OpenCodeHarness). Renaming it to "conversation" would mean renaming all of them.Review checklist
The commits are stages. Each list below is what that stage changes, so a reviewer can check the diff against it. Items are numbered across stages: A for the pi adapter, P for the pi projection, C for Channels.
Stage 1,
beb174d: removeAiSdkHarnessAiSdkHarness, theagents/harness/ai-sdkentry point,createSendMessageTool, and their tests and test bindings.agents/experimental/channels/projections/ai-sdk:toResponseChunks,toResponseChunk,toTranscriptMessage,toUIMessageChunk,toUIMessage.AiSdkConversionOptionsbecomesAiSdkProjectionOptions.answerToolCallandToolCallAnswerintoharness/think/answers.ts, sinceThinkHarnessis the only user. DropawaitsInput, which onlyAiSdkHarnessused./channels/think/...in place of the AI SDK one, with av3migration that deletesAiSdkAgent.AiSdkHarnessforconvertToModelMessages(..., { tools })now point atThinkHarness, which does the same.Stage 2,
46daff5: move the pi adapter into the package, behaviour unchangedThe adapter (
harness/pi/channels.ts, exported fromagents/harness/pi) makes these adaptations at this stage:session,sessions.create,forkandlistpass through toPiHarness.watch()wraps pi'sevents()(snapshot,start,stop,closed).operationId, stored as the submission'srequestId.fromis dropped, since pi has no participants.messageIdin its own kv, and renames user entries to it, scanning pi's submissions for entries it has not matched yet.run_start,run_endand the snapshot's run are looked up in pi's storage to get operation ids.events()snapshot,messages(), andpending().pi.resetentry becomes aresetevent, then the changed messages.queued,placed,doneandunansweredstatuses.tool_execution_start,tool_execution_update,inbox_update,auto_retry_*, a snapshot sent after an overflow, and pi's other events.The pi projection (
agents/experimental/channels/projections/pi) holds the pure conversions:toUserInput: text stays text, collapsed to a string when it is the only part. Data-URL images become pi images. Other files are dropped.toTranscriptMessages: entries become messages under their entry ids. A tool result folds into the assistant message that made the call (detailsif present, otherwise the text). Api.resetentry becomes a system message, "Context reset". System-prompt entries are skipped. An assistanterrorMessagebecomes a text part.PiChunkProjection, one per run: text and reasoning chunks with part idsmessage:index. It emits text that only a fuller copy carries (themessage_startpartial, a whole block or message change, or the saved entry), as fix(examples): stream all of a Pi message's text in Channels #2519 did. Tool calls appear once, when their block completes or at the message end. Tool-call argument deltas are ignored.toToolOutputChunk: a tool's saved result becomes a tool-output or tool-error chunk.The
wait()result conversion stays in the adapter, because it mapsPiHarness's result shape rather than pi's message format.Stage 3,
0b84178: Channels maps message ids; atranscriptevent replacesresetInterface (
experimental/channels/harness.ts):placedanddonestatuses can carrymessageId: the id a harness gave the user message, when it differs from the caller's.placedmust come before that message'smessageevent.{ type: "transcript"; messages }, which replaces the whole active transcript, replaces{ type: "reset" }.Channels (
harness-conversations.ts):placedanddone, and shows held and published messages under the inbound id. A message held under the harness id before the mapping arrives is renamed and republished.transcriptevent ends the live response, resets surfaces to an empty snapshot, then publishes the new transcript. This is whatresetdid, plus the messages.pi adapter:
kvoption is gone:piChannelsHarness(pi).placedanddonereport the entry an operation placed.wait()adds it to a done result by scanning pi's submissions, for a caller that missedplaced.placedmoves to just before themessageit names. Nothing else is reordered. A test fails without this.pi.resetentry becomes atranscriptevent with the new transcript.Think: its native
resetbecomes{ type: "transcript", messages: [] }. Its nativetranscript(re-read) event is still not forwarded, as before.Stage 4,
2252bc4: build the pi adapter's state from pi's snapshottranscriptevent only when published messages are gone from the transcript. Otherwise it emitsmessageevents, so a replacement that only adds messages does not reset surfaces.Unchanged after all four stages: A1, A2, A3, A4, A6, A10, A12, A13, P1 to P4, and the rest of A11.
Known gaps, not addressed here
doneorunansweredstatuses are not replayed, so a turn can stay open until Channels attaches again.auto_retry_*is still dropped, so chunks from a failed attempt are never withdrawn.tool_execution_updateis still dropped, so tools show no live output.AiSdkHarnessintegration tests are deleted with the harness. Channels' own tests use a scripted harness, and the new pi adapter tests run againstPiHarness.Compatibility
agents/harness/ai-sdkis gone, includingAiSdkHarnessandcreateSendMessageTool. UseThinkHarnessfromagents/harness/think. The AI SDK conversions move toagents/experimental/channels/projections/ai-sdk.{ type: "reset" }emits{ type: "transcript", messages }instead.