Repository navigation
feat(agents): OpenCodeHarness session events, and Workspace tools in the example - #2568
Conversation
…the example
session.events() now returns { snapshot, start, stop } with OpenCodeSessionEvents,
the same kinds of event PiHarness and ContainerHarness report, translated from
OpenCode's typed events. OpenCode's raw events stay available from session.log().
The example replaces its notes plugin with the Workspace tools from
@cloudflare/computer, offered to the model by name.
Takes the event union and the Workspace tools from #2483 (Aron).
🦋 Changeset detectedLatest commit: 908912e 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 |
| const snapshot = await this.#snapshot(opencode); | ||
| projector = new SessionEventProjector(snapshot); | ||
| for (const event of early.splice(0)) deliver(projector.project(event)); |
There was a problem hiding this comment.
🔴 Snapshot overlap duplicates operation completions
If delivery occurs during events() snapshot reads, SessionEventProjector can seed and replay the same running operation. The stream then emits two operation_end events for one submission.
Learn more
The stream subscribes before reading session state and buffers incoming OpenCode events in early. The pending read can observe an input already delivered while early still contains its delivery event. SessionEventProjector seeds its running IDs from snapshot.pending and then appends the delivered ID during replay. The same input gets two results at run end. Other overlapping events can also reset the answer reconstructed from the snapshot.
Example: A submit delivers op-1 while events() reads the snapshot. The snapshot includes op-1 as running, and early includes its session.inbox.delivered event. Replaying it appends op-1 twice; the next run end reports op-1 twice.
Recommended fix: Reconcile buffered events with the captured snapshot using a consistent event position, or make replay idempotent against snapshot state, including operation IDs and assistant state. Test delivery and step events interleaved with each snapshot read.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
Fixed in 908912e. Replay is now idempotent against the snapshot: the projector skips a delivery for an input it already has as running or has already ended, so overlap can't start or end it twice. Unit tests in tests/events.test.ts cover a delivery that repeats the snapshot, and a repeat after the input ended.
🔴 agents import sizes: 1 entry point over threshold
Changed exports (56)
…and 6 more exports in the workflow artifact. 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: |
… after stop - An input delivered while events() reads the snapshot was both seeded from pending and replayed, so it ended twice. The projector now skips deliveries of inputs it already has or has ended. - The answer is reset when inputs settle and when a new run starts, so a run with no assistant step no longer reports the previous run's text. - start() after stop() delivers nothing, and stop() drops buffered events.
OpenCodeHarness'ssession.events()now returns a snapshot of the session and then its events, in the same shape asPiHarnessandContainerHarness. The OpenCode example gives the model the Workspace tools from@cloudflare/computer(read,write,edit,delete,ls,find,grep, andexecwith git) in place of its notes plugin.This takes the parts of #2483 (thanks @aron-cf) we want on top of the harness from #2513:
harness.fetchfor the OpenCode CLI is left out: OpenCode doesn't expose its in-process handler, and getting it means patchingOpenCode.make. Tracked in OpenCodeHarness: serve OpenCode's HTTP API with harness.fetch #2567 / [FEATURE]: sdk: expose the embedded server's fetch handler on PromiseSdk.Interface anomalyco/opencode#54803.agents/streamscopy of events and the globalfetchpatch are not taken. OpenCode already keeps a durable, numbered log (session.log()), and the wake job already covers recovery after eviction.events.tstranslates OpenCode's typed events. It keeps what they leave out: tool names (session.tool.calledhas only the call id), and which inputs the current answer is for, sooperation_endcarries the same resultwait()returns.start(), so nothing falls in between.events()used to be an async iterable of OpenCode's raw events. Those are still available fromlog().pnpm exec vitest run --project harness-opencoderan, with new tests for the stream, tool names, queued follow-ups, abort and failure. Ran the example against Workers AI: write and read a file, and clone a repo withexec.