feat(go): native Go server — parity with the Rust/C# server - #61
Merged
Conversation
…g smooth-operator-core/go/core
Fills the Go server gap: until now Go shipped only a protocol client. This adds a
native Go smooth-operator service mirroring the proven C# server and the Rust
reference, in a new module `go/server`.
- FrameDispatcher / SessionStore / TurnRunner / ProtocolEvents ported from the C#
server (dotnet/server/src), verified against the Rust reference
(rust/smooth-operator-server/src/{server,handler,runner,protocol,local}.rs).
- WebSocket transport (coder/websocket): per-connection read loop + single outbound
writer goroutine fed by a channel.
- Graceful SIGTERM/SIGINT drain: one shared drain context; an in-flight turn finishes
and flushes its terminal event before the loop exits and detaches from the backplane.
- Auth verifier seam (permissive + HS256 LocalTokenVerifier, fail-closed) and an
in-memory Backplane stub (Redis/NATS seam left open).
- ServeLocal / SpawnLocal in-memory loopback entrypoint (mirrors Rust local.rs).
- Consumes the published engine module github.com/SmooAI/smooth-operator-core/go/core
(NewSmoothAgent + RunStream; MockLlmProvider in tests).
Tests (go test -race): spec conformance (every emitted event validated against the
spec/ schemas + round-tripped through the Go client's parser), boot, turn round-trip
on MockLlmProvider, no-engine clean-error path, unknown-session NOT_FOUND, and the
graceful-drain guarantee (in-flight turn finishes → detach runs).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U7Mn93HpqhSgEmX6tRdPAv
|
This was referenced Jun 24, 2026
brentrager
added a commit
that referenced
this pull request
Jun 24, 2026
… shared parity corpus (#69) The TS/Python/Go servers landed (#59/#60/#61) and all five now run the shared spec/conformance/scenarios corpus (#62-#67) — tested protocol parity. Updates the servers row + tests section from 'in progress' to the real state. Claude-Session: https://claude.ai/code/session_01U7Mn93HpqhSgEmX6tRdPAv Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Problem
Today only Rust and C# have a smooth-operator server. Go shipped only a client (
go/protocol). This fills the gap with a native Go server that consumes the Go engine in-process per turn.Solution
New module
go/server(github.com/SmooAI/smooth-operator/go/server), a parity port of the proven C# server, verified against the Rust reference.dotnet/server/src/{FrameDispatcher,TurnRunner,SessionStore,ProtocolEvents,Auth}.cs, cross-checked againstrust/smooth-operator-server/src/{server,handler,runner,protocol,local}.rs.github.com/coder/websocket, already the client's dep) — one/wsendpoint, per-connection read loop + a single outbound writer goroutine fed by a channel (the Rustsink_tx/writer split, the C# channel/writer task).selectis random on ties, so the cancel is preferred explicitly), the writer kept on a separate teardown-only context so an in-flight turn flushes its terminal event, then a backplane detach-after-loop always runs.LocalTokenVerifier(fail-closed), chosen at connect from?token=(mirrors the Rust verifier).ServeLocal/SpawnLocal— in-memory, loopback, auth-off entrypoint (mirrors Rustlocal.rs), embeddable in-process.github.com/SmooAI/smooth-operator-core/go/core(NewSmoothAgent+RunStream;MockLlmProviderin tests). Engine stream events (text/tool_call/tool_result/done) map to protocolstream_token/stream_chunk→ terminaleventual_response.error(the keyless path) — never a panic or dropped socket.Stubbed seams (MVP): in-memory
Backplaneonly (Redis/NATS cross-pod fan-out is the seam), ACL-filtered retrieval + rerank in the turn, and HITL tool-confirmation.The client/protocol module (
go/protocol,go/go.mod) is untouched; the server is its own module so the published client stays dependency-light, consuming the protocol locally via areplacedirective.Verification
go test -race ./...— all pass:spec/events/*.schema.jsonand round-tripped through the Go client'sprotocol.ParseServerEvent.SpawnLocalstarts on an ephemeral port and accepts a connection (ping round-trips).create_conversation_session→send_message(engine onMockLlmProvider) → streamedstream_tokens concatenate to the scripted reply + terminaleventual_responsecarries it.NOT_FOUND.Shutdown()lets it finish (terminal event still arrives), the loop exits, and the backplane detach runs (verified under-race).🤖 Generated with Claude Code