tunnel

package
v1.3.45 Latest Latest
Warning

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

Go to latest
Published: May 28, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Index

Constants

View Source
const (
	EventConnected             = "connected"
	EventActiveSession         = "active_session"
	EventSessionInfo           = "session_info"
	EventActivity              = "activity"     // main-agent activity text change
	EventUserMessage           = "user_message" // user text from desktop
	EventSystemMessage         = "system_message"
	EventText                  = "text"      // streaming text chunk
	EventTextDone              = "text_done" // text stream complete
	EventReasoning             = "reasoning"
	EventReasoningDone         = "reasoning_done"
	EventStatus                = "status" // agent status change
	EventToolCall              = "tool_call"
	EventToolResult            = "tool_result"
	EventApprovalRequest       = "approval_request"
	EventApprovalResult        = "approval_result"
	EventAskUserRequest        = "ask_user_request"
	EventAskUserResponse       = "ask_user_response"
	EventSubagentSpawn         = "subagent_spawn"
	EventSubagentText          = "subagent_text"
	EventSubagentReasoning     = "subagent_reasoning"
	EventSubagentReasoningDone = "subagent_reasoning_done"
	EventSubagentStatus        = "subagent_status"
	EventSubagentToolCall      = "subagent_tool_call"
	EventSubagentToolResult    = "subagent_tool_result"
	EventSubagentComplete      = "subagent_complete"
	EventResumeMiss            = "resume_miss"
	EventSnapshotReset         = "snapshot_reset"
	EventLanguageChange        = "language_change" // bidirectional language sync
	EventError                 = "error"
	EventPing                  = "ping"
	EventDisconnected          = "disconnected"
	EventServerOffline         = "server_offline"
	EventSharingStopped        = "sharing_stopped"
	EventRelayAck              = "relay_ack"  // Relay → Client: relay received the message
	EventServerAck             = "server_ack" // Server → Client: desktop processed the message
)

Server → Client event types.

View Source
const (
	CmdResumeHello      = "resume_hello"
	CmdResumeFrom       = "resume_from"
	CmdMessage          = "message"
	CmdApprovalResponse = "approval_response"
	CmdInterrupt        = "interrupt"
	CmdModeChange       = "mode_change"
	CmdAskUserResponse  = "ask_user_response"
	CmdPong             = "pong"
	CmdLanguageChange   = "language_change"
)

Client → Server command types.

View Source
const (
	StatusIdle     = "idle"
	StatusBusy     = "busy"
	StatusThinking = "thinking"
	StatusRunning  = "running"
	StatusWaiting  = "waiting" // waiting for approval
	StatusError    = "error"
)

Agent status values.

View Source
const (
	ModeSupervised = "supervised"
	ModeAuto       = "auto"
	ModeBypass     = "bypass"
	ModeAutopilot  = "autopilot"
)

Mode values.

View Source
const (
	DecisionAllow       = "allow"
	DecisionDeny        = "deny"
	DecisionAlwaysAllow = "always_allow"
)

Approval decisions.

View Source
const (
	ResumeModeIncremental      = "incremental"
	ResumeModeFullHistory      = "full_history"
	ResumeModeSnapshotRequired = "snapshot_required"
)

Resume mode values used by resume_ack.

View Source
const (
	MessageKindCron         = "cron"
	MessageKindShellCommand = "shell_command"
	MessageKindShellOutput  = "shell_output"
)
View Source
const (
	RedactedReasoningSentinel    = "__redacted_thinking__"
	RedactedReasoningPlaceholder = "Reasoning hidden by model."
)
View Source
const CmdThemeChange = "theme_change"

CmdThemeChange is the command name for theme change requests.

View Source
const DefaultRelayURL = "wss://gateway.ggcode.dev"

DefaultRelayURL is the default ggcode-relay server URL.

View Source
const EventThemeChange = "theme_change"

EventThemeChange is the event name for theme changes across clients.

Variables

This section is empty.

Functions

func NormalizeReasoningChunk added in v1.3.31

func NormalizeReasoningChunk(text string) string

func QRCodeForURL

func QRCodeForURL(url string) (string, error)

QRCodeForURL generates a QR code string for the given URL using terminal-friendly block characters. Returns a string that can be printed directly to a terminal.

func QRCodeLines

func QRCodeLines(url string) ([]string, error)

QRCodeLines returns the QR code as a slice of strings (one per line).

func QRCodePNG

func QRCodePNG(url string) ([]byte, error)

QRCodePNG generates a PNG image of the QR code for the given URL. Returns raw PNG bytes suitable for displaying in an image widget.

Types

type AckData added in v1.3.28

type AckData struct {
	MessageID string `json:"message_id"`
}

AckData carries an acknowledgement for a previously sent message.

type ActiveSessionData added in v1.3.20

type ActiveSessionData struct {
	SessionID string `json:"session_id"`
}

ActiveSessionData declares the authoritative TUI/GUI session bound to the current tunnel room.

type ActivityData added in v1.3.25

type ActivityData struct {
	Activity string `json:"activity,omitempty"`
}

ActivityData carries the current main-agent activity text.

type ApprovalRequestData

type ApprovalRequestData struct {
	ID       string `json:"id"`
	ToolName string `json:"tool_name"`
	Input    string `json:"input"`
}

ApprovalRequestData carries an approval request to the mobile client.

type ApprovalResponseData

type ApprovalResponseData struct {
	ID       string `json:"id"`
	Decision string `json:"decision"` // allow/deny/always_allow
}

ApprovalResponseData carries the user's approval decision back.

type AskUserAnswer

type AskUserAnswer struct {
	QuestionID   string   `json:"question_id"`
	ChoiceIDs    []string `json:"choice_ids,omitempty"`
	FreeformText string   `json:"freeform_text,omitempty"`
}

AskUserAnswer carries a single question answer.

type AskUserChoice

type AskUserChoice struct {
	ID    string `json:"id"`
	Label string `json:"label"`
}

AskUserChoice represents a selectable choice.

type AskUserQuestion

type AskUserQuestion struct {
	ID            string          `json:"id"`
	Prompt        string          `json:"prompt"`
	Kind          string          `json:"kind"` // single/multi/text
	Choices       []AskUserChoice `json:"choices,omitempty"`
	AllowFreeform bool            `json:"allow_freeform,omitempty"`
	Placeholder   string          `json:"placeholder,omitempty"`
}

AskUserQuestion represents a single question in the questionnaire.

type AskUserRequestData

type AskUserRequestData struct {
	ID        string            `json:"id"`
	Title     string            `json:"title,omitempty"`
	Questions []AskUserQuestion `json:"questions"`
}

AskUserRequestData carries a structured questionnaire from the agent. This is NOT the same as approval_request — it's a multi-question form with single/multi/text question types.

type AskUserResponseData

type AskUserResponseData struct {
	ID      string          `json:"id"`
	Status  string          `json:"status"` // submitted/cancelled
	Answers []AskUserAnswer `json:"answers,omitempty"`
}

AskUserResponseData carries the user's answers back.

type Broker

type Broker struct {
	// contains filtered or unexported fields
}

Broker bridges agent events and the WebSocket tunnel protocol.

Delivery guarantees:

  • Text chunks are batched: PushText appends to a per-msgID buffer; a 300ms ticker flushes all accumulated text as a single message.
  • Every outbound message carries a stable session_id + event_id.
  • The broker only produces ordered events for the current active session.
  • Relay owns per-client replay; broker only emits the canonical event stream.

func NewBroker

func NewBroker(sess *Session) *Broker

func (*Broker) AnnounceActiveSession added in v1.3.20

func (b *Broker) AnnounceActiveSession(sessionID string)

func (*Broker) BindSession added in v1.3.30

func (b *Broker) BindSession(sessionID string) bool

func (*Broker) CurrentActivity added in v1.3.25

func (b *Broker) CurrentActivity() (ActivityData, bool)

func (*Broker) CurrentStatus added in v1.3.14

func (b *Broker) CurrentStatus() (StatusData, bool)

func (*Broker) NextMessageID

func (b *Broker) NextMessageID() string

func (*Broker) OnCommand

func (b *Broker) OnCommand(fn func(cmd GatewayMessage))

func (*Broker) OnRelayConnected added in v1.3.19

func (b *Broker) OnRelayConnected(fn func(info RelayConnectedState))

func (*Broker) PushActivity added in v1.3.25

func (b *Broker) PushActivity(activity string)

func (*Broker) PushApprovalRequest

func (b *Broker) PushApprovalRequest(id, toolName, input string)

func (*Broker) PushApprovalResult

func (b *Broker) PushApprovalResult(id, decision string)

func (*Broker) PushAskUserRequest

func (b *Broker) PushAskUserRequest(id, title string, questions []AskUserQuestion)

func (*Broker) PushAskUserResponse

func (b *Broker) PushAskUserResponse(id, status string, answers []AskUserAnswer)

func (*Broker) PushError

func (b *Broker) PushError(message string)

func (*Broker) PushReasoning added in v1.3.31

func (b *Broker) PushReasoning(id, chunk string)

func (*Broker) PushReasoningDone added in v1.3.31

func (b *Broker) PushReasoningDone(id string)

func (*Broker) PushServerAck added in v1.3.28

func (b *Broker) PushServerAck(messageID string)

func (*Broker) PushSharingStopped

func (b *Broker) PushSharingStopped()

func (*Broker) PushStatus

func (b *Broker) PushStatus(status, message string)

func (*Broker) PushSubagentComplete

func (b *Broker) PushSubagentComplete(agentID, name, summary string, success bool)

func (*Broker) PushSubagentReasoning added in v1.3.31

func (b *Broker) PushSubagentReasoning(agentID, msgID, chunk string, done bool)

func (*Broker) PushSubagentSpawn

func (b *Broker) PushSubagentSpawn(agentID, name, task, color, parentID string)

func (*Broker) PushSubagentStatus

func (b *Broker) PushSubagentStatus(agentID, status, message string)

func (*Broker) PushSubagentText

func (b *Broker) PushSubagentText(agentID, msgID, chunk string, done bool)

func (*Broker) PushSubagentToolCall

func (b *Broker) PushSubagentToolCall(agentID, toolID, toolName, displayName, args, detail string)

func (*Broker) PushSubagentToolResult

func (b *Broker) PushSubagentToolResult(agentID, toolID, toolName, result string, isError bool)

func (*Broker) PushSystemMessage added in v1.3.22

func (b *Broker) PushSystemMessage(text string)

func (*Broker) PushSystemMessageData added in v1.3.22

func (b *Broker) PushSystemMessageData(data MessageData)

func (*Broker) PushText

func (b *Broker) PushText(id, chunk string)

func (*Broker) PushTextData added in v1.3.23

func (b *Broker) PushTextData(data TextData)

func (*Broker) PushTextDone

func (b *Broker) PushTextDone(id string)

func (*Broker) PushToolCall

func (b *Broker) PushToolCall(toolID, toolName, displayName, args, detail string)

func (*Broker) PushToolResult

func (b *Broker) PushToolResult(toolID, toolName, result string, isError bool)

func (*Broker) PushUserMessage

func (b *Broker) PushUserMessage(text string)

func (*Broker) PushUserMessageData added in v1.3.14

func (b *Broker) PushUserMessageData(data MessageData)

func (*Broker) ReplayEvents added in v1.3.20

func (b *Broker) ReplayEvents(events []GatewayMessage, reset bool)

func (*Broker) ResetSession added in v1.3.13

func (b *Broker) ResetSession()

func (*Broker) SeedHistory added in v1.3.13

func (b *Broker) SeedHistory(messages []HistoryEntry)

func (*Broker) SendLanguageChange added in v1.3.15

func (b *Broker) SendLanguageChange(lang string)

func (*Broker) SendSessionInfo

func (b *Broker) SendSessionInfo(data SessionInfoData)

func (*Broker) SendSnapshot added in v1.3.14

func (b *Broker) SendSnapshot(snapshot BrokerSnapshot)

func (*Broker) SendThemeChange added in v1.3.16

func (b *Broker) SendThemeChange(theme string)

func (*Broker) SessionID added in v1.3.13

func (b *Broker) SessionID() string

func (*Broker) SetEventRecorder added in v1.3.20

func (b *Broker) SetEventRecorder(fn func(msg GatewayMessage))

func (*Broker) SetReplayProvider added in v1.3.20

func (b *Broker) SetReplayProvider(fn func() []GatewayMessage)

func (*Broker) SetSnapshotProvider added in v1.3.13

func (b *Broker) SetSnapshotProvider(fn func() BrokerSnapshot)

func (*Broker) Stop

func (b *Broker) Stop()

func (*Broker) StopSharingGracefully added in v1.3.13

func (b *Broker) StopSharingGracefully(timeout time.Duration)

func (*Broker) SwitchSession added in v1.3.20

func (b *Broker) SwitchSession(sessionID string)

type BrokerSnapshot added in v1.3.13

type BrokerSnapshot struct {
	SessionInfo SessionInfoData
	History     []HistoryEntry
	Status      StatusData
	Activity    ActivityData
	ExtraEvents []SnapshotEvent
}

type Crypto

type Crypto struct {
	// contains filtered or unexported fields
}

Crypto provides AES-GCM encryption/decryption using the token as key.

func NewCrypto

func NewCrypto(tokenHex string) (*Crypto, error)

NewCrypto creates a Crypto instance from a hex-encoded token (32+ hex chars = 16+ byte key). The token hex string is decoded to bytes and used directly as AES-128/256 key.

func (*Crypto) Decrypt

func (c *Crypto) Decrypt(nonceB64, ciphertextB64 string) ([]byte, error)

Decrypt decrypts base64-encoded nonce + ciphertext and returns plaintext.

func (*Crypto) Encrypt

func (c *Crypto) Encrypt(plaintext []byte) (nonce string, ciphertext string, err error)

Encrypt encrypts plaintext and returns (nonce_base64, ciphertext_base64).

type ErrorData

type ErrorData struct {
	Message string `json:"message"`
	Code    string `json:"code,omitempty"`
}

ErrorData carries an error.

type GatewayMessage

type GatewayMessage struct {
	SessionID string          `json:"session_id,omitempty"`
	EventID   string          `json:"event_id,omitempty"`
	StreamID  string          `json:"stream_id,omitempty"`
	MessageID string          `json:"message_id,omitempty"` // client-generated ID for ack tracking
	Type      string          `json:"type"`
	Data      json.RawMessage `json:"data,omitempty"`
}

GatewayMessage is a JSON message exchanged over the encrypted channel.

type HistoryEntry

type HistoryEntry struct {
	Role        string `json:"role"`
	Content     string `json:"content"`
	DisplayText string `json:"display_text,omitempty"`
	Kind        string `json:"kind,omitempty"`
	// Tool fields (role == "tool_call" or "tool_result")
	ToolID          string `json:"tool_id,omitempty"`
	ToolName        string `json:"tool_name,omitempty"`
	ToolDisplayName string `json:"tool_display_name,omitempty"`
	ToolArgs        string `json:"tool_args,omitempty"`
	ToolDetail      string `json:"tool_detail,omitempty"`
	Result          string `json:"result,omitempty"`
	IsError         bool   `json:"is_error,omitempty"`
}

type LanguageChangeData added in v1.3.15

type LanguageChangeData struct {
	Language string `json:"language"` // "en" or "zh-CN"
}

LanguageChangeData carries a language preference change (bidirectional sync).

type MessageData

type MessageData struct {
	Text        string `json:"text"`
	DisplayText string `json:"display_text,omitempty"`
	Kind        string `json:"kind,omitempty"`
	MessageID   string `json:"message_id,omitempty"` // client-generated ID for ack tracking
}

MessageData carries a user message.

type ModeChangeData

type ModeChangeData struct {
	Mode string `json:"mode"`
}

ModeChangeData carries a mode change request.

type RelayClient

type RelayClient struct {
	// contains filtered or unexported fields
}

RelayClient connects to the ggcode-relay server as the "server" role. It auto-reconnects on disconnect with exponential backoff.

func NewRelayClient

func NewRelayClient(relayURL, token string) (*RelayClient, error)

func (*RelayClient) Close

func (rc *RelayClient) Close()

func (*RelayClient) CloseGracefully added in v1.3.13

func (rc *RelayClient) CloseGracefully(timeout time.Duration)

func (*RelayClient) Connect

func (rc *RelayClient) Connect() error

Connect starts the connection loop. It connects, runs pumps, and auto-reconnects.

func (*RelayClient) ConnectURL

func (rc *RelayClient) ConnectURL() string

func (*RelayClient) DestroyRoom added in v1.3.22

func (rc *RelayClient) DestroyRoom() error

func (*RelayClient) OnAck added in v1.3.28

func (rc *RelayClient) OnAck(fn func(ackType, messageID string))

func (*RelayClient) OnConnected added in v1.3.13

func (rc *RelayClient) OnConnected(fn func(info RelayConnectedState))

func (*RelayClient) OnMessage

func (rc *RelayClient) OnMessage(fn func(msg GatewayMessage))

func (*RelayClient) Send

func (rc *RelayClient) Send(msg GatewayMessage) error

Send encrypts and enqueues a GatewayMessage for delivery to the relay. It applies backpressure instead of dropping when the relay is reconnecting or the write pump is briefly saturated. Safe to call after Close — returns error instead of panicking.

func (*RelayClient) SendActiveSession added in v1.3.20

func (rc *RelayClient) SendActiveSession(sessionID string) error

func (*RelayClient) Token

func (rc *RelayClient) Token() string

type RelayConnectedState added in v1.3.13

type RelayConnectedState struct {
	Role         string
	SessionID    string
	HistoryCount int
	LastEventID  string
}

type ResumeAckData added in v1.3.13

type ResumeAckData struct {
	ClientID   string `json:"client_id"`
	SessionID  string `json:"session_id,omitempty"`
	ResumeMode string `json:"resume_mode"`
}

ResumeAckData tells the client how the gateway will recover state.

type ResumeFromData added in v1.3.13

type ResumeFromData struct {
	ClientID    string `json:"client_id"`
	SessionID   string `json:"session_id,omitempty"`
	LastEventID string `json:"last_event_id,omitempty"`
}

ResumeFromData requests replay starting after the caller's last good cursor.

type ResumeHelloData added in v1.3.13

type ResumeHelloData struct {
	ClientID    string `json:"client_id"`
	SessionID   string `json:"session_id,omitempty"`
	LastEventID string `json:"last_event_id,omitempty"`
}

ResumeHelloData requests either incremental replay or full session replay.

type Session

type Session struct {
	// contains filtered or unexported fields
}

Session manages a relay session: connects to ggcode-relay, generates QR code.

Usage:

sess := tunnel.NewSession("wss://relay.ggcode.app")
info, err := sess.Start(ctx)
fmt.Println(info.ConnectURL)
fmt.Println(info.QRCode)
sess.Send(msg)
sess.OnMessage(func(m) { ... })
sess.Stop()

func NewSession

func NewSession(relayURL string) *Session

NewSession creates a new relay session.

func (*Session) DestroyGracefully added in v1.3.22

func (s *Session) DestroyGracefully(timeout time.Duration)

func (*Session) Info

func (s *Session) Info() *SessionInfo

func (*Session) OnConnected added in v1.3.13

func (s *Session) OnConnected(fn func(info RelayConnectedState))

func (*Session) OnMessage

func (s *Session) OnMessage(fn func(msg GatewayMessage))

func (*Session) Send

func (s *Session) Send(msg GatewayMessage) error

func (*Session) SendActiveSession added in v1.3.20

func (s *Session) SendActiveSession(sessionID string) error

func (*Session) Start

func (s *Session) Start(ctx context.Context) (*SessionInfo, error)

Start connects to the relay server and returns connection info.

func (*Session) Stop

func (s *Session) Stop()

func (*Session) StopGracefully added in v1.3.13

func (s *Session) StopGracefully(timeout time.Duration)

type SessionInfo

type SessionInfo struct {
	ConnectURL string // wss://relay.ggcode.app/ws?role=client&token=abc123
	Token      string
	QRCode     string // terminal-friendly QR code (text)
	QRCodePNG  []byte // PNG image bytes for GUI display
	QRLines    []string
}

SessionInfo contains the connection details after a session starts.

type SessionInfoData

type SessionInfoData struct {
	Workspace string `json:"workspace"`
	Model     string `json:"model"`
	Provider  string `json:"provider"`
	Mode      string `json:"mode"`
	Version   string `json:"version"`
	Language  string `json:"language,omitempty"`
	Theme     string `json:"theme,omitempty"`
}

SessionInfoData carries session metadata sent after connection.

type SnapshotEvent added in v1.3.22

type SnapshotEvent struct {
	Type     string
	StreamID string
	Data     json.RawMessage
}

type StatusData

type StatusData struct {
	Status  string `json:"status"`
	Message string `json:"message,omitempty"`
}

StatusData carries an agent status change.

type SubagentCompleteData

type SubagentCompleteData struct {
	AgentID string `json:"agent_id"`
	Name    string `json:"name"`
	Summary string `json:"summary"` // one-line summary of what was done
	Success bool   `json:"success"`
}

SubagentCompleteData notifies that a sub-agent has finished.

type SubagentSpawnData

type SubagentSpawnData struct {
	AgentID  string `json:"agent_id"`
	Name     string `json:"name"`                // e.g. "Researcher", "Coder"
	Task     string `json:"task"`                // brief task description
	Color    string `json:"color,omitempty"`     // e.g. "#4CAF50"
	ParentID string `json:"parent_id,omitempty"` // empty for top-level
}

SubagentSpawnData notifies mobile that a sub-agent has been spawned. Mobile should show a live activity card for this agent.

type SubagentStatusData

type SubagentStatusData struct {
	AgentID string `json:"agent_id"`
	Status  string `json:"status"` // running/waiting_approval/completed/failed
	Message string `json:"message,omitempty"`
}

SubagentStatusData carries status updates for a sub-agent.

type SubagentTextData

type SubagentTextData struct {
	AgentID string `json:"agent_id"`
	ID      string `json:"id"` // message ID for grouping chunks
	Chunk   string `json:"chunk"`
	Done    bool   `json:"done"`
}

SubagentTextData carries streaming text from a sub-agent.

type SubagentToolCallData

type SubagentToolCallData struct {
	AgentID     string `json:"agent_id"`
	ToolID      string `json:"tool_id"`
	ToolName    string `json:"tool_name"`
	DisplayName string `json:"display_name,omitempty"`
	Args        string `json:"args,omitempty"`
	Detail      string `json:"detail,omitempty"`
}

SubagentToolCallData carries tool call info from a sub-agent.

type SubagentToolResultData

type SubagentToolResultData struct {
	AgentID     string `json:"agent_id"`
	ToolID      string `json:"tool_id"`
	ToolName    string `json:"tool_name"`
	Result      string `json:"result"`
	Summary     string `json:"summary,omitempty"`
	Payload     string `json:"payload,omitempty"`
	PayloadMode string `json:"payload_mode,omitempty"`
	IsError     bool   `json:"is_error"`
}

SubagentToolResultData carries tool result from a sub-agent.

type TextData

type TextData struct {
	ID    string `json:"id"`             // message ID to group chunks
	Chunk string `json:"chunk"`          // text content
	Done  bool   `json:"done"`           // true on last chunk
	Kind  string `json:"kind,omitempty"` // optional semantic hint for rendering
}

TextData carries a streaming text chunk.

type ThemeChangeData added in v1.3.16

type ThemeChangeData struct {
	Theme string `json:"theme"` // "midnight", "oled", "nord", "rose", "forest", "light"
}

ThemeChangeData carries a theme change (bidirectional sync).

type ToolCallData

type ToolCallData struct {
	ToolID      string `json:"tool_id"`
	ToolName    string `json:"tool_name"`
	DisplayName string `json:"display_name,omitempty"`
	Args        string `json:"args,omitempty"`
	Detail      string `json:"detail,omitempty"`
}

ToolCallData carries a tool call notification.

type ToolResultData

type ToolResultData struct {
	ToolID      string `json:"tool_id"`
	ToolName    string `json:"tool_name"`
	Result      string `json:"result,omitempty"`
	Summary     string `json:"summary,omitempty"`
	Payload     string `json:"payload,omitempty"`
	PayloadMode string `json:"payload_mode,omitempty"`
	IsError     bool   `json:"is_error,omitempty"`
}

ToolResultData carries a tool result.

Jump to

Keyboard shortcuts

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