e2e

package module
v0.0.0-...-914a3ab Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 3, 2026 License: MIT Imports: 0 Imported by: 0

README

Smooth

smooth-operator — Go client. An idiomatic, transport-agnostic, race-clean Go client for the smooth-operator protocol.

MIT License 26 tests passing lom.smoo.ai


What is this?

The native Go client for the smooth-operator WebSocket protocol. Wire types are generated from the language-neutral JSON Schemas in ../spec/ (committed, so you don't need the generator); the ergonomic layer gives you typed As* event accessors and a streaming MessageTurn that's both range-able and awaitable.


30-second quickstart

go get github.com/SmooAI/smooth-operator-core/go/protocol
package main

import (
	"context"
	"fmt"

	"github.com/SmooAI/smooth-operator-core/go/protocol"
)

func main() {
	ctx := context.Background()

	c, _ := protocol.New(protocol.Options{
		Transport: protocol.NewWebSocketTransport("ws://127.0.0.1:8787/ws", nil),
	})
	_ = c.Connect(ctx)
	defer c.Close()

	sess, _ := c.CreateConversationSession(ctx, protocol.CreateConversationSessionParams{
		AgentID:  "11111111-1111-1111-1111-111111111111",
		UserName: "Alice",
	})

	turn := c.SendMessage(protocol.SendMessageParams{SessionID: sess.SessionID, Message: "How long is your return window?"})
	final, _ := turn.Wait(ctx)
	fmt.Println("messageId:", final.Data.Data.MessageID)
}

(Point the transport at your own smooth-operator-server or the hosted endpoint.)


Watch it stream

SendMessage returns a MessageTurn — range over Events() for live tokens, then Wait() for the authoritative terminal response. Go has no sum types, so a ServerEvent carries the common envelope fields plus the raw frame; switch on Type and call the matching As* accessor.

turn := c.SendMessage(protocol.SendMessageParams{SessionID: sess.SessionID, Message: "Where's my order?"})

for ev := range turn.Events() {
	switch ev.Type {
	case protocol.EventStreamToken:
		tok, _ := ev.AsStreamToken()
		fmt.Print(tok.Data.Token)                 // tokens, live
	case protocol.EventStreamChunk:
		chunk, _ := ev.AsStreamChunk()
		fmt.Printf("\n  ↳ node: %s\n", chunk.Node) // workflow node boundary
	case protocol.EventWriteConfirmationRequired:
		// HITL: approve and the resumed stream flows back into this same turn.
		c.ConfirmToolAction(protocol.ConfirmToolActionParams{
			SessionID: sess.SessionID, RequestID: turn.RequestID(), Approved: true,
		})
	}
}

final, _ := turn.Wait(ctx)
fmt.Println("\nmessageId:", final.Data.Data.MessageID)
%%{init: {'theme':'base','themeVariables':{'background':'#020618','primaryColor':'#0b1426','primaryTextColor':'#e6edf6','primaryBorderColor':'#2b3a52','lineColor':'#7c8aa0','actorBkg':'#0b1426','actorBorder':'#2b3a52','actorTextColor':'#e6edf6','signalColor':'#7c8aa0','signalTextColor':'#e6edf6','noteBkgColor':'#f49f0a','noteTextColor':'#1a0f00','noteBorderColor':'#ff6b6c','fontFamily':'ui-sans-serif, system-ui, sans-serif'}}}%%
sequenceDiagram
  participant App
  participant C as protocol.Client
  participant S as Service
  App->>C: SendMessage(...)
  C->>S: { action: send_message }
  S-->>C: immediate_response (202)
  S-->>C: stream_token / stream_chunk …
  S-->>C: eventual_response (200)
  C-->>App: range Events() · Wait() returns final

Layout

File Purpose
protocol/types_gen.go Generated wire types (one struct per schema / $def). Do not edit.
protocol/events.go Ergonomic ServerEvent discrimination + typed As* accessors.
protocol/transport.go Transport interface + default coder/websocket implementation.
protocol/client.go Client with the action methods.
protocol/turn.go MessageTurn (streaming events + awaitable terminal) + ProtocolError.
protocol/validate.go Optional runtime JSON Schema validation against ../spec/.

The Transport interface is mockable, so the test suite drives real client code (correlation, event discrimination, HITL routing) without a network.


Polyglot — one spec, five clients

%%{init: {'theme':'base','themeVariables':{'background':'#020618','primaryColor':'#0b1426','primaryTextColor':'#e6edf6','primaryBorderColor':'#2b3a52','lineColor':'#7c8aa0','secondaryColor':'#0b1426','tertiaryColor':'#0b1426','fontFamily':'ui-sans-serif, system-ui, sans-serif','clusterBkg':'#0b1426','clusterBorder':'#22304a'}}}%%
flowchart LR
  SPEC["spec/ (JSON Schema)"] --> GO["Go<br/>github.com/SmooAI/smooth-operator-core/go"]
  SPEC --> TS["TypeScript"]
  SPEC --> NET[".NET (+ MEAI IChatClient facade)"]
  SPEC --> PY["Python"]
  SPEC --> RS["Rust"]

Test-driven by default

Nothing here is vibe-coded — it's verified against a real LLM gateway.

%%{init: {'theme':'base','themeVariables':{'background':'#020618','primaryColor':'#0b1426','primaryTextColor':'#e6edf6','primaryBorderColor':'#2b3a52','lineColor':'#7c8aa0','secondaryColor':'#0b1426','tertiaryColor':'#0b1426','fontFamily':'ui-sans-serif, system-ui, sans-serif','clusterBkg':'#0b1426','clusterBorder':'#22304a'}}}%%
flowchart TD
  J["🎯 LLM-as-judge quality evals (Rust harness)"]
  E["🌐 Live cross-language E2E — this client boots the real server + drives a real claude-haiku-4-5 turn"]
  C["🧪 Conformance fixtures (shared across all 5 clients)"]
  U["⚡ Unit tests (event discrimination, transport, correlation) — race-clean"]
  J --> E --> C --> U

26 tests, race-clean (go test -race). In the live cross-language E2E (e2e_live_test.go), this client boots a real smooth-operator-server subprocess (KB seeded) and drives a real claude-haiku-4-5 turn over WebSocket — asserting ≥1 streamed event, a knowledge-grounded "17", and per-session memory.

The proof story: an LLM-as-judge scored a multi-turn answer 1/5 (the runtime forgot turn 1's context); the failing eval drove a per-session-memory fix; it now scores 5/5 — a regression a substring test would have missed. See docs/EVALS.md.

Live tests are gated, never silently skipped — they run with SMOOTH_AGENT_E2E=1 + SMOOAI_GATEWAY_KEY and skip cleanly otherwise.

go test -race ./...                                   # no creds
SMOOTH_AGENT_E2E=1 go test -race ./... -run Live      # live cross-language E2E

Regenerating types

Generated with go-jsonschema (pure Go, offline). --only-models is intentional: plain structs with no generated enum validation, so the client tolerates forward-compatible wire values and the conformance fixtures round-trip cleanly. Full command in the original spec; run it after any ../spec change.

Smoo-powered or bring-your-own

Point the transport at the hosted lom.smoo.ai endpoint, or at your own self-hosted smooth-operator-server — same protocol, same client.

License

MIT © 2026 Smoo AI

Documentation

Overview

Package e2e is the module root for the Go implementation of smooth-operator.

Index

Constants

View Source
const Version = "1.1.0"

Version is the shared, lockstep release version for all smooth-operator language artifacts. The real Go "publish" is a git tag (go/v<Version>); this constant is the anchor that scripts/sync-versions.mjs keeps in sync with the canonical npm version on every changeset release.

Variables

This section is empty.

Functions

This section is empty.

Types

This section is empty.

Directories

Path Synopsis
Package core is the native Go smooth-operator engine — an in-process agentic tool-calling loop over an OpenAI-compatible chat client, with in-memory knowledge grounding.
Package core is the native Go smooth-operator engine — an in-process agentic tool-calling loop over an OpenAI-compatible chat client, with in-memory knowledge grounding.
extension
Package extension is the Go engine's implementation of SEP, the Smooth Extension Protocol.
Package extension is the Go engine's implementation of SEP, the Smooth Extension Protocol.
Package protocol is the Go client for the smooth-operator WebSocket protocol.
Package protocol is the Go client for the smooth-operator WebSocket protocol.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL