feat!: replace msgpack with protobuf for all NATS messages
Some checks failed
CI / Lint (push) Failing after 3m2s
CI / Test (push) Successful in 3m44s
CI / Release (push) Has been skipped
CI / Notify Downstream (chat-handler) (push) Has been skipped
CI / Notify Downstream (pipeline-bridge) (push) Has been skipped
CI / Notify Downstream (stt-module) (push) Has been skipped
CI / Notify Downstream (tts-module) (push) Has been skipped
CI / Notify Downstream (voice-assistant) (push) Has been skipped
CI / Notify (push) Successful in 1s
Some checks failed
CI / Lint (push) Failing after 3m2s
CI / Test (push) Successful in 3m44s
CI / Release (push) Has been skipped
CI / Notify Downstream (chat-handler) (push) Has been skipped
CI / Notify Downstream (pipeline-bridge) (push) Has been skipped
CI / Notify Downstream (stt-module) (push) Has been skipped
CI / Notify Downstream (tts-module) (push) Has been skipped
CI / Notify Downstream (voice-assistant) (push) Has been skipped
CI / Notify (push) Successful in 1s
BREAKING CHANGE: All NATS message serialization now uses Protocol Buffers. - Added proto/messages/v1/messages.proto with 22 message types - Generated Go code at gen/messagespb/ - messages/ package now exports type aliases to proto types - natsutil.Publish/Request/Decode use proto.Marshal/Unmarshal - Removed legacy MessageHandler, OnMessage, wrapMapHandler - TypedMessageHandler now returns (proto.Message, error) - EffectiveQuery is now a free function: messages.EffectiveQuery(req) - Removed msgpack dependency entirely
This commit is contained in:
@@ -1,224 +1,69 @@
|
||||
// Package messages defines typed NATS message structs for all services.
|
||||
// Package messages re-exports protobuf message types and provides NATS
|
||||
// subject constants plus helper functions.
|
||||
//
|
||||
// Using typed structs with short msgpack field tags instead of map[string]any
|
||||
// provides compile-time safety, smaller wire size (integer-like short keys vs
|
||||
// full string keys), and faster encode/decode by avoiding interface{} boxing.
|
||||
//
|
||||
// Audio data uses raw []byte instead of base64-encoded strings — msgpack
|
||||
// supports binary natively, eliminating the 33% base64 overhead.
|
||||
// The canonical type definitions live in the generated package
|
||||
// gen/messagespb (from proto/messages/v1/messages.proto).
|
||||
// This package provides type aliases so existing callers can keep using
|
||||
// messages.ChatRequest, etc., while the wire format is now protobuf.
|
||||
package messages
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// Pipeline Bridge
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
pb "git.daviestechlabs.io/daviestechlabs/handler-base/gen/messagespb"
|
||||
)
|
||||
|
||||
// PipelineTrigger is the request to start a pipeline.
|
||||
type PipelineTrigger struct {
|
||||
RequestID string `msgpack:"request_id" json:"request_id"`
|
||||
Pipeline string `msgpack:"pipeline" json:"pipeline"`
|
||||
Parameters map[string]any `msgpack:"parameters,omitempty" json:"parameters,omitempty"`
|
||||
}
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Type aliases — use these or import gen/messagespb directly.
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
// PipelineStatus is the response / status update for a pipeline run.
|
||||
type PipelineStatus struct {
|
||||
RequestID string `msgpack:"request_id" json:"request_id"`
|
||||
Status string `msgpack:"status" json:"status"`
|
||||
RunID string `msgpack:"run_id,omitempty" json:"run_id,omitempty"`
|
||||
Engine string `msgpack:"engine,omitempty" json:"engine,omitempty"`
|
||||
Pipeline string `msgpack:"pipeline,omitempty" json:"pipeline,omitempty"`
|
||||
SubmittedAt string `msgpack:"submitted_at,omitempty" json:"submitted_at,omitempty"`
|
||||
Error string `msgpack:"error,omitempty" json:"error,omitempty"`
|
||||
AvailablePipelines []string `msgpack:"available_pipelines,omitempty" json:"available_pipelines,omitempty"`
|
||||
}
|
||||
// Common
|
||||
type ErrorResponse = pb.ErrorResponse
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// Chat Handler
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// Chat
|
||||
type LoginEvent = pb.LoginEvent
|
||||
type GreetingRequest = pb.GreetingRequest
|
||||
type GreetingResponse = pb.GreetingResponse
|
||||
type ChatRequest = pb.ChatRequest
|
||||
type ChatResponse = pb.ChatResponse
|
||||
type ChatStreamChunk = pb.ChatStreamChunk
|
||||
|
||||
// ChatRequest is an incoming chat message.
|
||||
type ChatRequest struct {
|
||||
RequestID string `msgpack:"request_id" json:"request_id"`
|
||||
UserID string `msgpack:"user_id" json:"user_id"`
|
||||
Message string `msgpack:"message" json:"message"`
|
||||
Query string `msgpack:"query,omitempty" json:"query,omitempty"`
|
||||
Premium bool `msgpack:"premium,omitempty" json:"premium,omitempty"`
|
||||
EnableRAG bool `msgpack:"enable_rag,omitempty" json:"enable_rag,omitempty"`
|
||||
EnableReranker bool `msgpack:"enable_reranker,omitempty" json:"enable_reranker,omitempty"`
|
||||
EnableStreaming bool `msgpack:"enable_streaming,omitempty" json:"enable_streaming,omitempty"`
|
||||
TopK int `msgpack:"top_k,omitempty" json:"top_k,omitempty"`
|
||||
Collection string `msgpack:"collection,omitempty" json:"collection,omitempty"`
|
||||
EnableTTS bool `msgpack:"enable_tts,omitempty" json:"enable_tts,omitempty"`
|
||||
SystemPrompt string `msgpack:"system_prompt,omitempty" json:"system_prompt,omitempty"`
|
||||
ResponseSubject string `msgpack:"response_subject,omitempty" json:"response_subject,omitempty"`
|
||||
}
|
||||
// Voice
|
||||
type VoiceRequest = pb.VoiceRequest
|
||||
type VoiceResponse = pb.VoiceResponse
|
||||
type DocumentSource = pb.DocumentSource
|
||||
|
||||
// TTS
|
||||
type TTSRequest = pb.TTSRequest
|
||||
type TTSAudioChunk = pb.TTSAudioChunk
|
||||
type TTSFullResponse = pb.TTSFullResponse
|
||||
type TTSStatus = pb.TTSStatus
|
||||
type TTSVoiceInfo = pb.TTSVoiceInfo
|
||||
type TTSVoiceListResponse = pb.TTSVoiceListResponse
|
||||
type TTSVoiceRefreshResponse = pb.TTSVoiceRefreshResponse
|
||||
|
||||
// STT
|
||||
type STTStreamMessage = pb.STTStreamMessage
|
||||
type STTTranscription = pb.STTTranscription
|
||||
type STTInterrupt = pb.STTInterrupt
|
||||
|
||||
// Pipeline
|
||||
type PipelineTrigger = pb.PipelineTrigger
|
||||
type PipelineStatus = pb.PipelineStatus
|
||||
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
// Helpers
|
||||
// ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
// EffectiveQuery returns Message or falls back to Query.
|
||||
func (c *ChatRequest) EffectiveQuery() string {
|
||||
if c.Message != "" {
|
||||
return c.Message
|
||||
func EffectiveQuery(c *ChatRequest) string {
|
||||
if c.GetMessage() != "" {
|
||||
return c.GetMessage()
|
||||
}
|
||||
return c.Query
|
||||
return c.GetQuery()
|
||||
}
|
||||
|
||||
// ChatResponse is the full reply to a chat request.
|
||||
type ChatResponse struct {
|
||||
UserID string `msgpack:"user_id" json:"user_id"`
|
||||
Response string `msgpack:"response" json:"response"`
|
||||
ResponseText string `msgpack:"response_text" json:"response_text"`
|
||||
UsedRAG bool `msgpack:"used_rag" json:"used_rag"`
|
||||
RAGSources []string `msgpack:"rag_sources,omitempty" json:"rag_sources,omitempty"`
|
||||
Success bool `msgpack:"success" json:"success"`
|
||||
Audio []byte `msgpack:"audio,omitempty" json:"audio,omitempty"`
|
||||
Error string `msgpack:"error,omitempty" json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ChatStreamChunk is a single streaming chunk from an LLM response.
|
||||
type ChatStreamChunk struct {
|
||||
RequestID string `msgpack:"request_id" json:"request_id"`
|
||||
Type string `msgpack:"type" json:"type"`
|
||||
Content string `msgpack:"content" json:"content"`
|
||||
Done bool `msgpack:"done" json:"done"`
|
||||
Timestamp int64 `msgpack:"timestamp" json:"timestamp"`
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// Voice Assistant
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// VoiceRequest is an incoming voice-to-voice request.
|
||||
type VoiceRequest struct {
|
||||
RequestID string `msgpack:"request_id" json:"request_id"`
|
||||
Audio []byte `msgpack:"audio" json:"audio"`
|
||||
Language string `msgpack:"language,omitempty" json:"language,omitempty"`
|
||||
Collection string `msgpack:"collection,omitempty" json:"collection,omitempty"`
|
||||
}
|
||||
|
||||
// VoiceResponse is the reply to a voice request.
|
||||
type VoiceResponse struct {
|
||||
RequestID string `msgpack:"request_id" json:"request_id"`
|
||||
Response string `msgpack:"response" json:"response"`
|
||||
Audio []byte `msgpack:"audio" json:"audio"`
|
||||
Transcription string `msgpack:"transcription,omitempty" json:"transcription,omitempty"`
|
||||
Sources []DocumentSource `msgpack:"sources,omitempty" json:"sources,omitempty"`
|
||||
Error string `msgpack:"error,omitempty" json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// DocumentSource is a RAG search result source.
|
||||
type DocumentSource struct {
|
||||
Text string `msgpack:"text" json:"text"`
|
||||
Score float64 `msgpack:"score" json:"score"`
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// TTS Module
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// TTSRequest is a text-to-speech synthesis request.
|
||||
type TTSRequest struct {
|
||||
Text string `msgpack:"text" json:"text"`
|
||||
Speaker string `msgpack:"speaker,omitempty" json:"speaker,omitempty"`
|
||||
Language string `msgpack:"language,omitempty" json:"language,omitempty"`
|
||||
SpeakerWavB64 string `msgpack:"speaker_wav_b64,omitempty" json:"speaker_wav_b64,omitempty"`
|
||||
Stream bool `msgpack:"stream,omitempty" json:"stream,omitempty"`
|
||||
}
|
||||
|
||||
// TTSAudioChunk is a streamed audio chunk from TTS synthesis.
|
||||
type TTSAudioChunk struct {
|
||||
SessionID string `msgpack:"session_id" json:"session_id"`
|
||||
ChunkIndex int `msgpack:"chunk_index" json:"chunk_index"`
|
||||
TotalChunks int `msgpack:"total_chunks" json:"total_chunks"`
|
||||
Audio []byte `msgpack:"audio" json:"audio"`
|
||||
IsLast bool `msgpack:"is_last" json:"is_last"`
|
||||
Timestamp int64 `msgpack:"timestamp" json:"timestamp"`
|
||||
SampleRate int `msgpack:"sample_rate" json:"sample_rate"`
|
||||
}
|
||||
|
||||
// TTSFullResponse is a non-streamed TTS response (whole audio).
|
||||
type TTSFullResponse struct {
|
||||
SessionID string `msgpack:"session_id" json:"session_id"`
|
||||
Audio []byte `msgpack:"audio" json:"audio"`
|
||||
Timestamp int64 `msgpack:"timestamp" json:"timestamp"`
|
||||
SampleRate int `msgpack:"sample_rate" json:"sample_rate"`
|
||||
}
|
||||
|
||||
// TTSStatus is a TTS processing status update.
|
||||
type TTSStatus struct {
|
||||
SessionID string `msgpack:"session_id" json:"session_id"`
|
||||
Status string `msgpack:"status" json:"status"`
|
||||
Message string `msgpack:"message" json:"message"`
|
||||
Timestamp int64 `msgpack:"timestamp" json:"timestamp"`
|
||||
}
|
||||
|
||||
// TTSVoiceListResponse is the reply to a voice list request.
|
||||
type TTSVoiceListResponse struct {
|
||||
DefaultSpeaker string `msgpack:"default_speaker" json:"default_speaker"`
|
||||
CustomVoices []TTSVoiceInfo `msgpack:"custom_voices" json:"custom_voices"`
|
||||
LastRefresh int64 `msgpack:"last_refresh" json:"last_refresh"`
|
||||
Timestamp int64 `msgpack:"timestamp" json:"timestamp"`
|
||||
}
|
||||
|
||||
// TTSVoiceInfo is summary info about a custom voice.
|
||||
type TTSVoiceInfo struct {
|
||||
Name string `msgpack:"name" json:"name"`
|
||||
Language string `msgpack:"language" json:"language"`
|
||||
ModelType string `msgpack:"model_type" json:"model_type"`
|
||||
CreatedAt string `msgpack:"created_at" json:"created_at"`
|
||||
}
|
||||
|
||||
// TTSVoiceRefreshResponse is the reply to a voice refresh request.
|
||||
type TTSVoiceRefreshResponse struct {
|
||||
Count int `msgpack:"count" json:"count"`
|
||||
CustomVoices []TTSVoiceInfo `msgpack:"custom_voices" json:"custom_voices"`
|
||||
Timestamp int64 `msgpack:"timestamp" json:"timestamp"`
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// STT Module
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// STTStreamMessage is any message on the ai.voice.stream.{session} subject.
|
||||
type STTStreamMessage struct {
|
||||
Type string `msgpack:"type" json:"type"`
|
||||
Audio []byte `msgpack:"audio,omitempty" json:"audio,omitempty"`
|
||||
State string `msgpack:"state,omitempty" json:"state,omitempty"`
|
||||
SpeakerID string `msgpack:"speaker_id,omitempty" json:"speaker_id,omitempty"`
|
||||
}
|
||||
|
||||
// STTTranscription is the transcription result published by the STT module.
|
||||
type STTTranscription struct {
|
||||
SessionID string `msgpack:"session_id" json:"session_id"`
|
||||
Transcript string `msgpack:"transcript" json:"transcript"`
|
||||
Sequence int `msgpack:"sequence" json:"sequence"`
|
||||
IsPartial bool `msgpack:"is_partial" json:"is_partial"`
|
||||
IsFinal bool `msgpack:"is_final" json:"is_final"`
|
||||
Timestamp int64 `msgpack:"timestamp" json:"timestamp"`
|
||||
SpeakerID string `msgpack:"speaker_id" json:"speaker_id"`
|
||||
HasVoiceActivity bool `msgpack:"has_voice_activity" json:"has_voice_activity"`
|
||||
State string `msgpack:"state" json:"state"`
|
||||
}
|
||||
|
||||
// STTInterrupt is published when the STT module detects a user interrupt.
|
||||
type STTInterrupt struct {
|
||||
SessionID string `msgpack:"session_id" json:"session_id"`
|
||||
Type string `msgpack:"type" json:"type"`
|
||||
Timestamp int64 `msgpack:"timestamp" json:"timestamp"`
|
||||
SpeakerID string `msgpack:"speaker_id" json:"speaker_id"`
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
// Common / Error
|
||||
// ────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
// ErrorResponse is the standard error reply from any handler.
|
||||
type ErrorResponse struct {
|
||||
Error bool `msgpack:"error" json:"error"`
|
||||
Message string `msgpack:"message" json:"message"`
|
||||
Type string `msgpack:"type" json:"type"`
|
||||
}
|
||||
|
||||
// Timestamp returns the current Unix timestamp (helper for message construction).
|
||||
// Timestamp returns the current Unix timestamp.
|
||||
func Timestamp() int64 {
|
||||
return time.Now().Unix()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user