chatprotocol

package
v1.0.25 Latest Latest
Warning

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

Go to latest
Published: Aug 27, 2026 License: AGPL-3.0 Imports: 2 Imported by: 0

Documentation

Overview

Package chatprotocol defines the ChatEvent wire protocol exchanged over the workbench chat WebSocket between the in-container bridge process and any consumer (web frontend, Telegram bot relay). Canonical source — deploy/workbench/bridge/internal/chatprotocol/events.go is a hand-mirrored copy for the bridge's standalone Go module (it can't import this module directly; keep the two files byte-identical on any change).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Event

type Event struct {
	Type EventType `json:"type"`

	// Correlation id: ties tool_call_started -> tool_call_result, and
	// permission_request -> permission_decision.
	ID string `json:"id,omitempty"`

	// assistant_text_delta / assistant_text_done / user_message / error
	Text string `json:"text,omitempty"`

	// tool_call_started / tool_call_result / permission_request
	ToolName     string          `json:"tool_name,omitempty"`
	Input        json.RawMessage `json:"input,omitempty"`
	InputSummary string          `json:"input_summary,omitempty"`
	Output       string          `json:"output,omitempty"`
	IsError      bool            `json:"is_error,omitempty"`

	// permission_request / permission_decision
	Options  []PermissionDecision `json:"options,omitempty"`
	Decision PermissionDecision   `json:"decision,omitempty"`

	// turn_done
	SessionID string  `json:"session_id,omitempty"`
	CostUSD   float64 `json:"cost_usd,omitempty"`

	// Model attributes which model produced an assistant_text_delta/assistant_text_done/
	// turn_done event. Populated only by Simple Chat's in-process engine — the Docker
	// workbench bridge never sets this field.
	Model string `json:"model,omitempty"`

	// auth_link / auth_code_submit
	URL  string `json:"url,omitempty"`
	Code string `json:"code,omitempty"`

	// Seq is a monotonically increasing sequence number assigned by Hub.publish, used by a
	// consumer to skip events it has already applied when the backlog is replayed to it
	// (on first attach or after a reconnect), instead of re-rendering/duplicating them.
	Seq uint64 `json:"seq,omitempty"`
}

Event is the single envelope type for every message on the chat WebSocket, in both directions. Only the fields relevant to Type are populated; the rest are zero/omitted.

type EventSink

type EventSink interface {
	// Send delivers one outbound event to the client. It is called from the goroutine the turn
	// runs on, which is not the connection's read loop, so implementations must be safe to call
	// concurrently with that read loop.
	Send(event Event) error

	// AwaitPermissionDecision blocks until a permission_decision event carrying requestId
	// arrives from the client, or ctx is done. The connection's read loop is responsible for
	// routing an incoming decision to whichever call is parked on that id.
	AwaitPermissionDecision(ctx context.Context, requestId string) (PermissionDecision, error)
}

EventSink is the transport seam for a producer of chat events — today Simple Chat's in-process agent loop (internal/service/v1/simplechat), which produces Events and consumes permission decisions through it without knowing a WebSocket is on the other side.

It lives here, rather than in the simplechat package, so that both service.SimpleChatService and the transport layer can name it without either importing an internal/service/v1 implementation package. It is deliberately in its own file: events.go is mirrored byte-identically into deploy/workbench/bridge's standalone module, and this interface is not part of that mirrored wire contract.

Implementations are per-connection: one sink per WebSocket, constructed fresh, never shared.

type EventType

type EventType string
const (
	// EventSystemInit: bridge → consumer, carries no payload fields.
	EventSystemInit EventType = "system_init"
	// EventUserMessage: consumer → bridge, carries Text.
	EventUserMessage EventType = "user_message"
	// EventNewChat: consumer → bridge, carries no payload fields. Broadcast back to every attached
	// consumer via Hub.Reset (see hub.go) as the sole backlog entry going forward — a consumer
	// reconnecting afterward replays only the new conversation, not the one this discarded.
	EventNewChat EventType = "new_chat"
	// EventAssistantTextDelta: bridge → consumer, carries Text and ID.
	EventAssistantTextDelta EventType = "assistant_text_delta"
	// EventAssistantTextDone: bridge → consumer, carries Text and ID.
	EventAssistantTextDone EventType = "assistant_text_done"
	// EventToolCallStarted: bridge → consumer, carries ID/ToolName/InputSummary.
	EventToolCallStarted EventType = "tool_call_started"
	// EventToolCallResult: bridge → consumer, carries ID/ToolName/Output/IsError.
	EventToolCallResult EventType = "tool_call_result"
	// EventPermissionRequest: bridge → consumer, carries ID/ToolName/InputSummary/Options.
	EventPermissionRequest EventType = "permission_request"
	// EventPermissionDecision: consumer → bridge, carries ID/Decision.
	EventPermissionDecision EventType = "permission_decision"
	// EventTurnDone: bridge → consumer, carries SessionID/CostUSD.
	EventTurnDone EventType = "turn_done"
	// EventError: bridge → consumer, carries Text.
	EventError EventType = "error"
	// EventAuthLink: bridge → consumer, carries URL.
	EventAuthLink EventType = "auth_link"
	// EventAuthCodeNeeded: bridge → consumer, carries no payload fields.
	EventAuthCodeNeeded EventType = "auth_code_needed"
	// EventAuthCodeSubmit: consumer → bridge, carries Code.
	EventAuthCodeSubmit EventType = "auth_code_submit"
	// EventAuthComplete: bridge → consumer, carries no payload fields. Broadcast once, immediately
	// after the bridge's startup auth check finishes — whether a subscription login actually ran,
	// was skipped (api_key mode / token already present), or failed — since the bridge falls
	// through to normal operation in every case. This is the one unambiguous signal a consumer can
	// use to switch off an "auth pending" UI, instead of inferring completion from the absence of
	// further auth_link/auth_code_needed events.
	EventAuthComplete EventType = "auth_complete"
)

type PermissionDecision

type PermissionDecision string
const (
	DecisionAllowOnce   PermissionDecision = "allow_once"
	DecisionAllowAlways PermissionDecision = "allow_always"
	DecisionDeny        PermissionDecision = "deny"
)

Jump to

Keyboard shortcuts

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