From 72125c137a9be49949586c91a0128bc5d55c27f2 Mon Sep 17 00:00:00 2001 From: Kaien Date: Wed, 9 Sep 2026 18:18:30 +0300 Subject: [PATCH] feat(proto): AIRequest.images for vision multimodal input. Co-authored-by: Cursor --- ai.pb.go | 358 ++++++++++++++++++++++++++++++++++--------------------- ai.proto | 11 ++ 2 files changed, 230 insertions(+), 139 deletions(-) diff --git a/ai.pb.go b/ai.pb.go index bbcc546..e34e9fb 100644 --- a/ai.pb.go +++ b/ai.pb.go @@ -260,7 +260,11 @@ type AIRequest struct { // Raw user message for intent classification (no history/memories/tools). // Live chat clients (Telegram/Steam) send this; when empty, image intent // detection is skipped and the request is treated as normal chat. - UserMessage string `protobuf:"bytes,11,opt,name=user_message,json=userMessage,proto3" json:"user_message,omitempty"` + UserMessage string `protobuf:"bytes,11,opt,name=user_message,json=userMessage,proto3" json:"user_message,omitempty"` + // Optional image attachments for vision models (photo/sticker/GIF frame). + // When non-empty, GenerateAnswer routes to LLM_VISION_MODEL and builds a + // multimodal user message; image-generation intent is skipped. + Images []*InputImage `protobuf:"bytes,12,rep,name=images,proto3" json:"images,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -372,6 +376,74 @@ func (x *AIRequest) GetUserMessage() string { return "" } +func (x *AIRequest) GetImages() []*InputImage { + if x != nil { + return x.Images + } + return nil +} + +// InputImage — one vision attachment (raw bytes, not base64). +type InputImage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` // raw image bytes (jpeg/png/webp/gif) + MimeType string `protobuf:"bytes,2,opt,name=mime_type,json=mimeType,proto3" json:"mime_type,omitempty"` // e.g. image/jpeg + Source string `protobuf:"bytes,3,opt,name=source,proto3" json:"source,omitempty"` // optional client hint: photo, sticker, animation, reply_photo, … + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *InputImage) Reset() { + *x = InputImage{} + mi := &file_ai_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *InputImage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*InputImage) ProtoMessage() {} + +func (x *InputImage) ProtoReflect() protoreflect.Message { + mi := &file_ai_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use InputImage.ProtoReflect.Descriptor instead. +func (*InputImage) Descriptor() ([]byte, []int) { + return file_ai_proto_rawDescGZIP(), []int{1} +} + +func (x *InputImage) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +func (x *InputImage) GetMimeType() string { + if x != nil { + return x.MimeType + } + return "" +} + +func (x *InputImage) GetSource() string { + if x != nil { + return x.Source + } + return "" +} + // UsedMemory — снимок одного воспоминания, участвовавшего в генерации ответа. type UsedMemory struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -389,7 +461,7 @@ type UsedMemory struct { func (x *UsedMemory) Reset() { *x = UsedMemory{} - mi := &file_ai_proto_msgTypes[1] + mi := &file_ai_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -401,7 +473,7 @@ func (x *UsedMemory) String() string { func (*UsedMemory) ProtoMessage() {} func (x *UsedMemory) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[1] + mi := &file_ai_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -414,7 +486,7 @@ func (x *UsedMemory) ProtoReflect() protoreflect.Message { // Deprecated: Use UsedMemory.ProtoReflect.Descriptor instead. func (*UsedMemory) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{1} + return file_ai_proto_rawDescGZIP(), []int{2} } func (x *UsedMemory) GetId() int64 { @@ -483,7 +555,7 @@ type AnswerGenerationOptions struct { func (x *AnswerGenerationOptions) Reset() { *x = AnswerGenerationOptions{} - mi := &file_ai_proto_msgTypes[2] + mi := &file_ai_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -495,7 +567,7 @@ func (x *AnswerGenerationOptions) String() string { func (*AnswerGenerationOptions) ProtoMessage() {} func (x *AnswerGenerationOptions) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[2] + mi := &file_ai_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -508,7 +580,7 @@ func (x *AnswerGenerationOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use AnswerGenerationOptions.ProtoReflect.Descriptor instead. func (*AnswerGenerationOptions) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{2} + return file_ai_proto_rawDescGZIP(), []int{3} } func (x *AnswerGenerationOptions) GetIncludeUserMemories() bool { @@ -539,7 +611,7 @@ type AIResponse struct { func (x *AIResponse) Reset() { *x = AIResponse{} - mi := &file_ai_proto_msgTypes[3] + mi := &file_ai_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -551,7 +623,7 @@ func (x *AIResponse) String() string { func (*AIResponse) ProtoMessage() {} func (x *AIResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[3] + mi := &file_ai_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -564,7 +636,7 @@ func (x *AIResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AIResponse.ProtoReflect.Descriptor instead. func (*AIResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{3} + return file_ai_proto_rawDescGZIP(), []int{4} } func (x *AIResponse) GetContent() string { @@ -654,7 +726,7 @@ type GetAnswerJobRequest struct { func (x *GetAnswerJobRequest) Reset() { *x = GetAnswerJobRequest{} - mi := &file_ai_proto_msgTypes[4] + mi := &file_ai_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -666,7 +738,7 @@ func (x *GetAnswerJobRequest) String() string { func (*GetAnswerJobRequest) ProtoMessage() {} func (x *GetAnswerJobRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[4] + mi := &file_ai_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -679,7 +751,7 @@ func (x *GetAnswerJobRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAnswerJobRequest.ProtoReflect.Descriptor instead. func (*GetAnswerJobRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{4} + return file_ai_proto_rawDescGZIP(), []int{5} } func (x *GetAnswerJobRequest) GetJobId() string { @@ -707,7 +779,7 @@ type AnswerJobResponse struct { func (x *AnswerJobResponse) Reset() { *x = AnswerJobResponse{} - mi := &file_ai_proto_msgTypes[5] + mi := &file_ai_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -719,7 +791,7 @@ func (x *AnswerJobResponse) String() string { func (*AnswerJobResponse) ProtoMessage() {} func (x *AnswerJobResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[5] + mi := &file_ai_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -732,7 +804,7 @@ func (x *AnswerJobResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AnswerJobResponse.ProtoReflect.Descriptor instead. func (*AnswerJobResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{5} + return file_ai_proto_rawDescGZIP(), []int{6} } func (x *AnswerJobResponse) GetState() AnswerJobState { @@ -792,7 +864,7 @@ type ToolCallTrace struct { func (x *ToolCallTrace) Reset() { *x = ToolCallTrace{} - mi := &file_ai_proto_msgTypes[6] + mi := &file_ai_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -804,7 +876,7 @@ func (x *ToolCallTrace) String() string { func (*ToolCallTrace) ProtoMessage() {} func (x *ToolCallTrace) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[6] + mi := &file_ai_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -817,7 +889,7 @@ func (x *ToolCallTrace) ProtoReflect() protoreflect.Message { // Deprecated: Use ToolCallTrace.ProtoReflect.Descriptor instead. func (*ToolCallTrace) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{6} + return file_ai_proto_rawDescGZIP(), []int{7} } func (x *ToolCallTrace) GetCallId() string { @@ -872,7 +944,7 @@ type GetAIResponseTraceRequest struct { func (x *GetAIResponseTraceRequest) Reset() { *x = GetAIResponseTraceRequest{} - mi := &file_ai_proto_msgTypes[7] + mi := &file_ai_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -884,7 +956,7 @@ func (x *GetAIResponseTraceRequest) String() string { func (*GetAIResponseTraceRequest) ProtoMessage() {} func (x *GetAIResponseTraceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[7] + mi := &file_ai_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -897,7 +969,7 @@ func (x *GetAIResponseTraceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAIResponseTraceRequest.ProtoReflect.Descriptor instead. func (*GetAIResponseTraceRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{7} + return file_ai_proto_rawDescGZIP(), []int{8} } func (x *GetAIResponseTraceRequest) GetId() string { @@ -931,7 +1003,7 @@ type GetAIResponseTraceResponse struct { func (x *GetAIResponseTraceResponse) Reset() { *x = GetAIResponseTraceResponse{} - mi := &file_ai_proto_msgTypes[8] + mi := &file_ai_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -943,7 +1015,7 @@ func (x *GetAIResponseTraceResponse) String() string { func (*GetAIResponseTraceResponse) ProtoMessage() {} func (x *GetAIResponseTraceResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[8] + mi := &file_ai_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -956,7 +1028,7 @@ func (x *GetAIResponseTraceResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAIResponseTraceResponse.ProtoReflect.Descriptor instead. func (*GetAIResponseTraceResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{8} + return file_ai_proto_rawDescGZIP(), []int{9} } func (x *GetAIResponseTraceResponse) GetId() string { @@ -1077,7 +1149,7 @@ type CreateSessionRequest struct { func (x *CreateSessionRequest) Reset() { *x = CreateSessionRequest{} - mi := &file_ai_proto_msgTypes[9] + mi := &file_ai_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1089,7 +1161,7 @@ func (x *CreateSessionRequest) String() string { func (*CreateSessionRequest) ProtoMessage() {} func (x *CreateSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[9] + mi := &file_ai_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1102,7 +1174,7 @@ func (x *CreateSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSessionRequest.ProtoReflect.Descriptor instead. func (*CreateSessionRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{9} + return file_ai_proto_rawDescGZIP(), []int{10} } func (x *CreateSessionRequest) GetUserId() string { @@ -1145,7 +1217,7 @@ type CreateSessionResponse struct { func (x *CreateSessionResponse) Reset() { *x = CreateSessionResponse{} - mi := &file_ai_proto_msgTypes[10] + mi := &file_ai_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1157,7 +1229,7 @@ func (x *CreateSessionResponse) String() string { func (*CreateSessionResponse) ProtoMessage() {} func (x *CreateSessionResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[10] + mi := &file_ai_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1170,7 +1242,7 @@ func (x *CreateSessionResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSessionResponse.ProtoReflect.Descriptor instead. func (*CreateSessionResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{10} + return file_ai_proto_rawDescGZIP(), []int{11} } func (x *CreateSessionResponse) GetSessionId() string { @@ -1208,7 +1280,7 @@ type AskInSessionRequest struct { func (x *AskInSessionRequest) Reset() { *x = AskInSessionRequest{} - mi := &file_ai_proto_msgTypes[11] + mi := &file_ai_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1220,7 +1292,7 @@ func (x *AskInSessionRequest) String() string { func (*AskInSessionRequest) ProtoMessage() {} func (x *AskInSessionRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[11] + mi := &file_ai_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1233,7 +1305,7 @@ func (x *AskInSessionRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AskInSessionRequest.ProtoReflect.Descriptor instead. func (*AskInSessionRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{11} + return file_ai_proto_rawDescGZIP(), []int{12} } func (x *AskInSessionRequest) GetSessionId() string { @@ -1286,7 +1358,7 @@ type SessionStatusResponse struct { func (x *SessionStatusResponse) Reset() { *x = SessionStatusResponse{} - mi := &file_ai_proto_msgTypes[12] + mi := &file_ai_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1298,7 +1370,7 @@ func (x *SessionStatusResponse) String() string { func (*SessionStatusResponse) ProtoMessage() {} func (x *SessionStatusResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[12] + mi := &file_ai_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1311,7 +1383,7 @@ func (x *SessionStatusResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SessionStatusResponse.ProtoReflect.Descriptor instead. func (*SessionStatusResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{12} + return file_ai_proto_rawDescGZIP(), []int{13} } func (x *SessionStatusResponse) GetSessionId() string { @@ -1367,7 +1439,7 @@ type StatelessMessage struct { func (x *StatelessMessage) Reset() { *x = StatelessMessage{} - mi := &file_ai_proto_msgTypes[13] + mi := &file_ai_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1379,7 +1451,7 @@ func (x *StatelessMessage) String() string { func (*StatelessMessage) ProtoMessage() {} func (x *StatelessMessage) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[13] + mi := &file_ai_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1392,7 +1464,7 @@ func (x *StatelessMessage) ProtoReflect() protoreflect.Message { // Deprecated: Use StatelessMessage.ProtoReflect.Descriptor instead. func (*StatelessMessage) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{13} + return file_ai_proto_rawDescGZIP(), []int{14} } func (x *StatelessMessage) GetRole() string { @@ -1420,7 +1492,7 @@ type StatelessRequest struct { func (x *StatelessRequest) Reset() { *x = StatelessRequest{} - mi := &file_ai_proto_msgTypes[14] + mi := &file_ai_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1432,7 +1504,7 @@ func (x *StatelessRequest) String() string { func (*StatelessRequest) ProtoMessage() {} func (x *StatelessRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[14] + mi := &file_ai_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1445,7 +1517,7 @@ func (x *StatelessRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StatelessRequest.ProtoReflect.Descriptor instead. func (*StatelessRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{14} + return file_ai_proto_rawDescGZIP(), []int{15} } func (x *StatelessRequest) GetMessages() []*StatelessMessage { @@ -1471,7 +1543,7 @@ type HealthCheckRequest struct { func (x *HealthCheckRequest) Reset() { *x = HealthCheckRequest{} - mi := &file_ai_proto_msgTypes[15] + mi := &file_ai_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1483,7 +1555,7 @@ func (x *HealthCheckRequest) String() string { func (*HealthCheckRequest) ProtoMessage() {} func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[15] + mi := &file_ai_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1496,7 +1568,7 @@ func (x *HealthCheckRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckRequest.ProtoReflect.Descriptor instead. func (*HealthCheckRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{15} + return file_ai_proto_rawDescGZIP(), []int{16} } // HealthCheckResponse для ответа на проверку здоровья @@ -1510,7 +1582,7 @@ type HealthCheckResponse struct { func (x *HealthCheckResponse) Reset() { *x = HealthCheckResponse{} - mi := &file_ai_proto_msgTypes[16] + mi := &file_ai_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1522,7 +1594,7 @@ func (x *HealthCheckResponse) String() string { func (*HealthCheckResponse) ProtoMessage() {} func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[16] + mi := &file_ai_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1535,7 +1607,7 @@ func (x *HealthCheckResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use HealthCheckResponse.ProtoReflect.Descriptor instead. func (*HealthCheckResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{16} + return file_ai_proto_rawDescGZIP(), []int{17} } func (x *HealthCheckResponse) GetServing() bool { @@ -1567,7 +1639,7 @@ type AgentToolLoopOptions struct { func (x *AgentToolLoopOptions) Reset() { *x = AgentToolLoopOptions{} - mi := &file_ai_proto_msgTypes[17] + mi := &file_ai_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1579,7 +1651,7 @@ func (x *AgentToolLoopOptions) String() string { func (*AgentToolLoopOptions) ProtoMessage() {} func (x *AgentToolLoopOptions) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[17] + mi := &file_ai_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1592,7 +1664,7 @@ func (x *AgentToolLoopOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentToolLoopOptions.ProtoReflect.Descriptor instead. func (*AgentToolLoopOptions) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{17} + return file_ai_proto_rawDescGZIP(), []int{18} } func (x *AgentToolLoopOptions) GetToolsEnabled() bool { @@ -1642,7 +1714,7 @@ type AgentResponseContract struct { func (x *AgentResponseContract) Reset() { *x = AgentResponseContract{} - mi := &file_ai_proto_msgTypes[18] + mi := &file_ai_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1654,7 +1726,7 @@ func (x *AgentResponseContract) String() string { func (*AgentResponseContract) ProtoMessage() {} func (x *AgentResponseContract) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[18] + mi := &file_ai_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1667,7 +1739,7 @@ func (x *AgentResponseContract) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentResponseContract.ProtoReflect.Descriptor instead. func (*AgentResponseContract) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{18} + return file_ai_proto_rawDescGZIP(), []int{19} } func (x *AgentResponseContract) GetFormat() AgentOutputFormat { @@ -1712,7 +1784,7 @@ type AgentRequest struct { func (x *AgentRequest) Reset() { *x = AgentRequest{} - mi := &file_ai_proto_msgTypes[19] + mi := &file_ai_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1724,7 +1796,7 @@ func (x *AgentRequest) String() string { func (*AgentRequest) ProtoMessage() {} func (x *AgentRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[19] + mi := &file_ai_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1737,7 +1809,7 @@ func (x *AgentRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentRequest.ProtoReflect.Descriptor instead. func (*AgentRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{19} + return file_ai_proto_rawDescGZIP(), []int{20} } func (x *AgentRequest) GetMessages() []*StatelessMessage { @@ -1838,7 +1910,7 @@ type AgentUsage struct { func (x *AgentUsage) Reset() { *x = AgentUsage{} - mi := &file_ai_proto_msgTypes[20] + mi := &file_ai_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1850,7 +1922,7 @@ func (x *AgentUsage) String() string { func (*AgentUsage) ProtoMessage() {} func (x *AgentUsage) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[20] + mi := &file_ai_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1863,7 +1935,7 @@ func (x *AgentUsage) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentUsage.ProtoReflect.Descriptor instead. func (*AgentUsage) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{20} + return file_ai_proto_rawDescGZIP(), []int{21} } func (x *AgentUsage) GetToolIterations() uint32 { @@ -1916,7 +1988,7 @@ type AgentResponse struct { func (x *AgentResponse) Reset() { *x = AgentResponse{} - mi := &file_ai_proto_msgTypes[21] + mi := &file_ai_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1928,7 +2000,7 @@ func (x *AgentResponse) String() string { func (*AgentResponse) ProtoMessage() {} func (x *AgentResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[21] + mi := &file_ai_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1941,7 +2013,7 @@ func (x *AgentResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use AgentResponse.ProtoReflect.Descriptor instead. func (*AgentResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{21} + return file_ai_proto_rawDescGZIP(), []int{22} } func (x *AgentResponse) GetStatus() AnswerStatus { @@ -1997,7 +2069,7 @@ type CancelAnswerJobRequest struct { func (x *CancelAnswerJobRequest) Reset() { *x = CancelAnswerJobRequest{} - mi := &file_ai_proto_msgTypes[22] + mi := &file_ai_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2009,7 +2081,7 @@ func (x *CancelAnswerJobRequest) String() string { func (*CancelAnswerJobRequest) ProtoMessage() {} func (x *CancelAnswerJobRequest) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[22] + mi := &file_ai_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2022,7 +2094,7 @@ func (x *CancelAnswerJobRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelAnswerJobRequest.ProtoReflect.Descriptor instead. func (*CancelAnswerJobRequest) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{22} + return file_ai_proto_rawDescGZIP(), []int{23} } func (x *CancelAnswerJobRequest) GetJobId() string { @@ -2051,7 +2123,7 @@ type CancelAnswerJobResponse struct { func (x *CancelAnswerJobResponse) Reset() { *x = CancelAnswerJobResponse{} - mi := &file_ai_proto_msgTypes[23] + mi := &file_ai_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2063,7 +2135,7 @@ func (x *CancelAnswerJobResponse) String() string { func (*CancelAnswerJobResponse) ProtoMessage() {} func (x *CancelAnswerJobResponse) ProtoReflect() protoreflect.Message { - mi := &file_ai_proto_msgTypes[23] + mi := &file_ai_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2076,7 +2148,7 @@ func (x *CancelAnswerJobResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CancelAnswerJobResponse.ProtoReflect.Descriptor instead. func (*CancelAnswerJobResponse) Descriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{23} + return file_ai_proto_rawDescGZIP(), []int{24} } func (x *CancelAnswerJobResponse) GetState() AnswerJobState { @@ -2104,7 +2176,7 @@ var File_ai_proto protoreflect.FileDescriptor const file_ai_proto_rawDesc = "" + "\n" + - "\bai.proto\x12\x02ai\"\xbc\x03\n" + + "\bai.proto\x12\x02ai\"\xe4\x03\n" + "\tAIRequest\x12\x12\n" + "\x04text\x18\x01 \x01(\tR\x04text\x12!\n" + "\fbot_username\x18\x02 \x01(\tR\vbotUsername\x12\x1d\n" + @@ -2118,7 +2190,13 @@ const file_ai_proto_rawDesc = "" + "\x11supports_deferred\x18\t \x01(\bR\x10supportsDeferred\x123\n" + "\rused_memories\x18\n" + " \x03(\v2\x0e.ai.UsedMemoryR\fusedMemories\x12!\n" + - "\fuser_message\x18\v \x01(\tR\vuserMessage\"\xd4\x01\n" + + "\fuser_message\x18\v \x01(\tR\vuserMessage\x12&\n" + + "\x06images\x18\f \x03(\v2\x0e.ai.InputImageR\x06images\"U\n" + + "\n" + + "InputImage\x12\x12\n" + + "\x04data\x18\x01 \x01(\fR\x04data\x12\x1b\n" + + "\tmime_type\x18\x02 \x01(\tR\bmimeType\x12\x16\n" + + "\x06source\x18\x03 \x01(\tR\x06source\"\xd4\x01\n" + "\n" + "UsedMemory\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x17\n" + @@ -2327,80 +2405,82 @@ func file_ai_proto_rawDescGZIP() []byte { } var file_ai_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_ai_proto_msgTypes = make([]protoimpl.MessageInfo, 25) +var file_ai_proto_msgTypes = make([]protoimpl.MessageInfo, 26) var file_ai_proto_goTypes = []any{ (ResponseKind)(0), // 0: ai.ResponseKind (AnswerStatus)(0), // 1: ai.AnswerStatus (AnswerJobState)(0), // 2: ai.AnswerJobState (AgentOutputFormat)(0), // 3: ai.AgentOutputFormat (*AIRequest)(nil), // 4: ai.AIRequest - (*UsedMemory)(nil), // 5: ai.UsedMemory - (*AnswerGenerationOptions)(nil), // 6: ai.AnswerGenerationOptions - (*AIResponse)(nil), // 7: ai.AIResponse - (*GetAnswerJobRequest)(nil), // 8: ai.GetAnswerJobRequest - (*AnswerJobResponse)(nil), // 9: ai.AnswerJobResponse - (*ToolCallTrace)(nil), // 10: ai.ToolCallTrace - (*GetAIResponseTraceRequest)(nil), // 11: ai.GetAIResponseTraceRequest - (*GetAIResponseTraceResponse)(nil), // 12: ai.GetAIResponseTraceResponse - (*CreateSessionRequest)(nil), // 13: ai.CreateSessionRequest - (*CreateSessionResponse)(nil), // 14: ai.CreateSessionResponse - (*AskInSessionRequest)(nil), // 15: ai.AskInSessionRequest - (*SessionStatusResponse)(nil), // 16: ai.SessionStatusResponse - (*StatelessMessage)(nil), // 17: ai.StatelessMessage - (*StatelessRequest)(nil), // 18: ai.StatelessRequest - (*HealthCheckRequest)(nil), // 19: ai.HealthCheckRequest - (*HealthCheckResponse)(nil), // 20: ai.HealthCheckResponse - (*AgentToolLoopOptions)(nil), // 21: ai.AgentToolLoopOptions - (*AgentResponseContract)(nil), // 22: ai.AgentResponseContract - (*AgentRequest)(nil), // 23: ai.AgentRequest - (*AgentUsage)(nil), // 24: ai.AgentUsage - (*AgentResponse)(nil), // 25: ai.AgentResponse - (*CancelAnswerJobRequest)(nil), // 26: ai.CancelAnswerJobRequest - (*CancelAnswerJobResponse)(nil), // 27: ai.CancelAnswerJobResponse - nil, // 28: ai.AgentRequest.MetadataEntry + (*InputImage)(nil), // 5: ai.InputImage + (*UsedMemory)(nil), // 6: ai.UsedMemory + (*AnswerGenerationOptions)(nil), // 7: ai.AnswerGenerationOptions + (*AIResponse)(nil), // 8: ai.AIResponse + (*GetAnswerJobRequest)(nil), // 9: ai.GetAnswerJobRequest + (*AnswerJobResponse)(nil), // 10: ai.AnswerJobResponse + (*ToolCallTrace)(nil), // 11: ai.ToolCallTrace + (*GetAIResponseTraceRequest)(nil), // 12: ai.GetAIResponseTraceRequest + (*GetAIResponseTraceResponse)(nil), // 13: ai.GetAIResponseTraceResponse + (*CreateSessionRequest)(nil), // 14: ai.CreateSessionRequest + (*CreateSessionResponse)(nil), // 15: ai.CreateSessionResponse + (*AskInSessionRequest)(nil), // 16: ai.AskInSessionRequest + (*SessionStatusResponse)(nil), // 17: ai.SessionStatusResponse + (*StatelessMessage)(nil), // 18: ai.StatelessMessage + (*StatelessRequest)(nil), // 19: ai.StatelessRequest + (*HealthCheckRequest)(nil), // 20: ai.HealthCheckRequest + (*HealthCheckResponse)(nil), // 21: ai.HealthCheckResponse + (*AgentToolLoopOptions)(nil), // 22: ai.AgentToolLoopOptions + (*AgentResponseContract)(nil), // 23: ai.AgentResponseContract + (*AgentRequest)(nil), // 24: ai.AgentRequest + (*AgentUsage)(nil), // 25: ai.AgentUsage + (*AgentResponse)(nil), // 26: ai.AgentResponse + (*CancelAnswerJobRequest)(nil), // 27: ai.CancelAnswerJobRequest + (*CancelAnswerJobResponse)(nil), // 28: ai.CancelAnswerJobResponse + nil, // 29: ai.AgentRequest.MetadataEntry } var file_ai_proto_depIdxs = []int32{ - 6, // 0: ai.AIRequest.options:type_name -> ai.AnswerGenerationOptions - 5, // 1: ai.AIRequest.used_memories:type_name -> ai.UsedMemory - 1, // 2: ai.AIResponse.status:type_name -> ai.AnswerStatus - 0, // 3: ai.AIResponse.kind:type_name -> ai.ResponseKind - 2, // 4: ai.AnswerJobResponse.state:type_name -> ai.AnswerJobState - 24, // 5: ai.AnswerJobResponse.agent_usage:type_name -> ai.AgentUsage - 5, // 6: ai.GetAIResponseTraceResponse.memories:type_name -> ai.UsedMemory - 10, // 7: ai.GetAIResponseTraceResponse.tool_calls:type_name -> ai.ToolCallTrace - 6, // 8: ai.AskInSessionRequest.options:type_name -> ai.AnswerGenerationOptions - 17, // 9: ai.StatelessRequest.messages:type_name -> ai.StatelessMessage - 3, // 10: ai.AgentResponseContract.format:type_name -> ai.AgentOutputFormat - 17, // 11: ai.AgentRequest.messages:type_name -> ai.StatelessMessage - 21, // 12: ai.AgentRequest.tool_loop:type_name -> ai.AgentToolLoopOptions - 22, // 13: ai.AgentRequest.response_contract:type_name -> ai.AgentResponseContract - 28, // 14: ai.AgentRequest.metadata:type_name -> ai.AgentRequest.MetadataEntry - 1, // 15: ai.AgentResponse.status:type_name -> ai.AnswerStatus - 24, // 16: ai.AgentResponse.usage:type_name -> ai.AgentUsage - 2, // 17: ai.CancelAnswerJobResponse.state:type_name -> ai.AnswerJobState - 23, // 18: ai.AIService.RunAgent:input_type -> ai.AgentRequest - 26, // 19: ai.AIService.CancelAnswerJob:input_type -> ai.CancelAnswerJobRequest - 4, // 20: ai.AIService.GenerateAnswer:input_type -> ai.AIRequest - 18, // 21: ai.AIService.GenerateStateless:input_type -> ai.StatelessRequest - 19, // 22: ai.AIService.HealthCheck:input_type -> ai.HealthCheckRequest - 13, // 23: ai.AIService.CreateSession:input_type -> ai.CreateSessionRequest - 15, // 24: ai.AIService.AskInSession:input_type -> ai.AskInSessionRequest - 8, // 25: ai.AIService.GetAnswerJob:input_type -> ai.GetAnswerJobRequest - 11, // 26: ai.AIService.GetAIResponseTrace:input_type -> ai.GetAIResponseTraceRequest - 25, // 27: ai.AIService.RunAgent:output_type -> ai.AgentResponse - 27, // 28: ai.AIService.CancelAnswerJob:output_type -> ai.CancelAnswerJobResponse - 7, // 29: ai.AIService.GenerateAnswer:output_type -> ai.AIResponse - 7, // 30: ai.AIService.GenerateStateless:output_type -> ai.AIResponse - 20, // 31: ai.AIService.HealthCheck:output_type -> ai.HealthCheckResponse - 14, // 32: ai.AIService.CreateSession:output_type -> ai.CreateSessionResponse - 16, // 33: ai.AIService.AskInSession:output_type -> ai.SessionStatusResponse - 9, // 34: ai.AIService.GetAnswerJob:output_type -> ai.AnswerJobResponse - 12, // 35: ai.AIService.GetAIResponseTrace:output_type -> ai.GetAIResponseTraceResponse - 27, // [27:36] is the sub-list for method output_type - 18, // [18:27] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 7, // 0: ai.AIRequest.options:type_name -> ai.AnswerGenerationOptions + 6, // 1: ai.AIRequest.used_memories:type_name -> ai.UsedMemory + 5, // 2: ai.AIRequest.images:type_name -> ai.InputImage + 1, // 3: ai.AIResponse.status:type_name -> ai.AnswerStatus + 0, // 4: ai.AIResponse.kind:type_name -> ai.ResponseKind + 2, // 5: ai.AnswerJobResponse.state:type_name -> ai.AnswerJobState + 25, // 6: ai.AnswerJobResponse.agent_usage:type_name -> ai.AgentUsage + 6, // 7: ai.GetAIResponseTraceResponse.memories:type_name -> ai.UsedMemory + 11, // 8: ai.GetAIResponseTraceResponse.tool_calls:type_name -> ai.ToolCallTrace + 7, // 9: ai.AskInSessionRequest.options:type_name -> ai.AnswerGenerationOptions + 18, // 10: ai.StatelessRequest.messages:type_name -> ai.StatelessMessage + 3, // 11: ai.AgentResponseContract.format:type_name -> ai.AgentOutputFormat + 18, // 12: ai.AgentRequest.messages:type_name -> ai.StatelessMessage + 22, // 13: ai.AgentRequest.tool_loop:type_name -> ai.AgentToolLoopOptions + 23, // 14: ai.AgentRequest.response_contract:type_name -> ai.AgentResponseContract + 29, // 15: ai.AgentRequest.metadata:type_name -> ai.AgentRequest.MetadataEntry + 1, // 16: ai.AgentResponse.status:type_name -> ai.AnswerStatus + 25, // 17: ai.AgentResponse.usage:type_name -> ai.AgentUsage + 2, // 18: ai.CancelAnswerJobResponse.state:type_name -> ai.AnswerJobState + 24, // 19: ai.AIService.RunAgent:input_type -> ai.AgentRequest + 27, // 20: ai.AIService.CancelAnswerJob:input_type -> ai.CancelAnswerJobRequest + 4, // 21: ai.AIService.GenerateAnswer:input_type -> ai.AIRequest + 19, // 22: ai.AIService.GenerateStateless:input_type -> ai.StatelessRequest + 20, // 23: ai.AIService.HealthCheck:input_type -> ai.HealthCheckRequest + 14, // 24: ai.AIService.CreateSession:input_type -> ai.CreateSessionRequest + 16, // 25: ai.AIService.AskInSession:input_type -> ai.AskInSessionRequest + 9, // 26: ai.AIService.GetAnswerJob:input_type -> ai.GetAnswerJobRequest + 12, // 27: ai.AIService.GetAIResponseTrace:input_type -> ai.GetAIResponseTraceRequest + 26, // 28: ai.AIService.RunAgent:output_type -> ai.AgentResponse + 28, // 29: ai.AIService.CancelAnswerJob:output_type -> ai.CancelAnswerJobResponse + 8, // 30: ai.AIService.GenerateAnswer:output_type -> ai.AIResponse + 8, // 31: ai.AIService.GenerateStateless:output_type -> ai.AIResponse + 21, // 32: ai.AIService.HealthCheck:output_type -> ai.HealthCheckResponse + 15, // 33: ai.AIService.CreateSession:output_type -> ai.CreateSessionResponse + 17, // 34: ai.AIService.AskInSession:output_type -> ai.SessionStatusResponse + 10, // 35: ai.AIService.GetAnswerJob:output_type -> ai.AnswerJobResponse + 13, // 36: ai.AIService.GetAIResponseTrace:output_type -> ai.GetAIResponseTraceResponse + 28, // [28:37] is the sub-list for method output_type + 19, // [19:28] is the sub-list for method input_type + 19, // [19:19] is the sub-list for extension type_name + 19, // [19:19] is the sub-list for extension extendee + 0, // [0:19] is the sub-list for field type_name } func init() { file_ai_proto_init() } @@ -2414,7 +2494,7 @@ func file_ai_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_ai_proto_rawDesc), len(file_ai_proto_rawDesc)), NumEnums: 4, - NumMessages: 25, + NumMessages: 26, NumExtensions: 0, NumServices: 1, }, diff --git a/ai.proto b/ai.proto index 4244504..415b5f6 100644 --- a/ai.proto +++ b/ai.proto @@ -22,6 +22,17 @@ message AIRequest { // Live chat clients (Telegram/Steam) send this; when empty, image intent // detection is skipped and the request is treated as normal chat. string user_message = 11; + // Optional image attachments for vision models (photo/sticker/GIF frame). + // When non-empty, GenerateAnswer routes to LLM_VISION_MODEL and builds a + // multimodal user message; image-generation intent is skipped. + repeated InputImage images = 12; +} + +// InputImage — one vision attachment (raw bytes, not base64). +message InputImage { + bytes data = 1; // raw image bytes (jpeg/png/webp/gif) + string mime_type = 2; // e.g. image/jpeg + string source = 3; // optional client hint: photo, sticker, animation, reply_photo, … } // UsedMemory — снимок одного воспоминания, участвовавшего в генерации ответа.