diff --git a/ai.pb.go b/ai.pb.go index a6bb371..bbcc546 100644 --- a/ai.pb.go +++ b/ai.pb.go @@ -21,6 +21,56 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// ResponseKind — тип синхронного ответа GenerateAnswer (кроме deferred jobs). +type ResponseKind int32 + +const ( + ResponseKind_RESPONSE_KIND_UNSPECIFIED ResponseKind = 0 // трактуется как TEXT (обратная совместимость) + ResponseKind_RESPONSE_KIND_TEXT ResponseKind = 1 // content — текстовый ответ + ResponseKind_RESPONSE_KIND_IMAGE ResponseKind = 2 // image_base64 — сгенерированное изображение +) + +// Enum value maps for ResponseKind. +var ( + ResponseKind_name = map[int32]string{ + 0: "RESPONSE_KIND_UNSPECIFIED", + 1: "RESPONSE_KIND_TEXT", + 2: "RESPONSE_KIND_IMAGE", + } + ResponseKind_value = map[string]int32{ + "RESPONSE_KIND_UNSPECIFIED": 0, + "RESPONSE_KIND_TEXT": 1, + "RESPONSE_KIND_IMAGE": 2, + } +) + +func (x ResponseKind) Enum() *ResponseKind { + p := new(ResponseKind) + *p = x + return p +} + +func (x ResponseKind) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ResponseKind) Descriptor() protoreflect.EnumDescriptor { + return file_ai_proto_enumTypes[0].Descriptor() +} + +func (ResponseKind) Type() protoreflect.EnumType { + return &file_ai_proto_enumTypes[0] +} + +func (x ResponseKind) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ResponseKind.Descriptor instead. +func (ResponseKind) EnumDescriptor() ([]byte, []int) { + return file_ai_proto_rawDescGZIP(), []int{0} +} + // AnswerStatus описывает, готов ли ответ синхронно или отложен в job. type AnswerStatus int32 @@ -55,11 +105,11 @@ func (x AnswerStatus) String() string { } func (AnswerStatus) Descriptor() protoreflect.EnumDescriptor { - return file_ai_proto_enumTypes[0].Descriptor() + return file_ai_proto_enumTypes[1].Descriptor() } func (AnswerStatus) Type() protoreflect.EnumType { - return &file_ai_proto_enumTypes[0] + return &file_ai_proto_enumTypes[1] } func (x AnswerStatus) Number() protoreflect.EnumNumber { @@ -68,7 +118,7 @@ func (x AnswerStatus) Number() protoreflect.EnumNumber { // Deprecated: Use AnswerStatus.Descriptor instead. func (AnswerStatus) EnumDescriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{0} + return file_ai_proto_rawDescGZIP(), []int{1} } // AnswerJobState — состояние отложенной генерации ответа. @@ -123,11 +173,11 @@ func (x AnswerJobState) String() string { } func (AnswerJobState) Descriptor() protoreflect.EnumDescriptor { - return file_ai_proto_enumTypes[1].Descriptor() + return file_ai_proto_enumTypes[2].Descriptor() } func (AnswerJobState) Type() protoreflect.EnumType { - return &file_ai_proto_enumTypes[1] + return &file_ai_proto_enumTypes[2] } func (x AnswerJobState) Number() protoreflect.EnumNumber { @@ -136,7 +186,7 @@ func (x AnswerJobState) Number() protoreflect.EnumNumber { // Deprecated: Use AnswerJobState.Descriptor instead. func (AnswerJobState) EnumDescriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{1} + return file_ai_proto_rawDescGZIP(), []int{2} } // AgentOutputFormat — требуемый формат финального ответа. @@ -176,11 +226,11 @@ func (x AgentOutputFormat) String() string { } func (AgentOutputFormat) Descriptor() protoreflect.EnumDescriptor { - return file_ai_proto_enumTypes[2].Descriptor() + return file_ai_proto_enumTypes[3].Descriptor() } func (AgentOutputFormat) Type() protoreflect.EnumType { - return &file_ai_proto_enumTypes[2] + return &file_ai_proto_enumTypes[3] } func (x AgentOutputFormat) Number() protoreflect.EnumNumber { @@ -189,7 +239,7 @@ func (x AgentOutputFormat) Number() protoreflect.EnumNumber { // Deprecated: Use AgentOutputFormat.Descriptor instead. func (AgentOutputFormat) EnumDescriptor() ([]byte, []int) { - return file_ai_proto_rawDescGZIP(), []int{2} + return file_ai_proto_rawDescGZIP(), []int{3} } // AIRequest содержит запрос к AI модели @@ -206,7 +256,11 @@ type AIRequest struct { SupportsDeferred bool `protobuf:"varint,9,opt,name=supports_deferred,json=supportsDeferred,proto3" json:"supports_deferred,omitempty"` // Клиент умеет обрабатывать status=PENDING + GetAnswerJob (async тяжёлые тулзы). Старые клиенты не ставят — тяжёлые тулзы исполняются синхронно, как раньше. // Структурированные воспоминания, которые клиент уже вложил в text (для debug-trace). // Core сохраняет их as-is на ai_response_traces — не перезапрашивает memories-сервис. - UsedMemories []*UsedMemory `protobuf:"bytes,10,rep,name=used_memories,json=usedMemories,proto3" json:"used_memories,omitempty"` + UsedMemories []*UsedMemory `protobuf:"bytes,10,rep,name=used_memories,json=usedMemories,proto3" json:"used_memories,omitempty"` + // 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"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -311,6 +365,13 @@ func (x *AIRequest) GetUsedMemories() []*UsedMemory { return nil } +func (x *AIRequest) GetUserMessage() string { + if x != nil { + return x.UserMessage + } + return "" +} + // UsedMemory — снимок одного воспоминания, участвовавшего в генерации ответа. type UsedMemory struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -466,8 +527,12 @@ type AIResponse struct { ReasoningContent string `protobuf:"bytes,4,opt,name=reasoning_content,json=reasoningContent,proto3" json:"reasoning_content,omitempty"` // Текст рассуждений (если включён режим reasoning) Status AnswerStatus `protobuf:"varint,5,opt,name=status,proto3,enum=ai.AnswerStatus" json:"status,omitempty"` // COMPLETE (или UNSPECIFIED для старых клиентов) — content финальный; // PENDING — запущена долгая job, content это interim, финал тянуть через GetAnswerJob(job_id) - JobId string `protobuf:"bytes,6,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` // Идентификатор отложенной job (только при status=PENDING) - ResponseId string `protobuf:"bytes,7,opt,name=response_id,json=responseId,proto3" json:"response_id,omitempty"` // UUID (hex) debug-trace; доступен уже при PENDING + JobId string `protobuf:"bytes,6,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` // Идентификатор отложенной job (только при status=PENDING) + ResponseId string `protobuf:"bytes,7,opt,name=response_id,json=responseId,proto3" json:"response_id,omitempty"` // UUID (hex) debug-trace; доступен уже при PENDING + Kind ResponseKind `protobuf:"varint,8,opt,name=kind,proto3,enum=ai.ResponseKind" json:"kind,omitempty"` // TEXT (default) или IMAGE + ImageBase64 string `protobuf:"bytes,9,opt,name=image_base64,json=imageBase64,proto3" json:"image_base64,omitempty"` // base64-encoded image bytes when kind=IMAGE + ImageMimeType string `protobuf:"bytes,10,opt,name=image_mime_type,json=imageMimeType,proto3" json:"image_mime_type,omitempty"` // e.g. image/png when kind=IMAGE + ImagePrompt string `protobuf:"bytes,11,opt,name=image_prompt,json=imagePrompt,proto3" json:"image_prompt,omitempty"` // final Muse Image prompt when kind=IMAGE (for client-side history) unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -551,6 +616,34 @@ func (x *AIResponse) GetResponseId() string { return "" } +func (x *AIResponse) GetKind() ResponseKind { + if x != nil { + return x.Kind + } + return ResponseKind_RESPONSE_KIND_UNSPECIFIED +} + +func (x *AIResponse) GetImageBase64() string { + if x != nil { + return x.ImageBase64 + } + return "" +} + +func (x *AIResponse) GetImageMimeType() string { + if x != nil { + return x.ImageMimeType + } + return "" +} + +func (x *AIResponse) GetImagePrompt() string { + if x != nil { + return x.ImagePrompt + } + return "" +} + // GetAnswerJobRequest запрашивает статус отложенной генерации ответа. type GetAnswerJobRequest struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -2011,7 +2104,7 @@ var File_ai_proto protoreflect.FileDescriptor const file_ai_proto_rawDesc = "" + "\n" + - "\bai.proto\x12\x02ai\"\x99\x03\n" + + "\bai.proto\x12\x02ai\"\xbc\x03\n" + "\tAIRequest\x12\x12\n" + "\x04text\x18\x01 \x01(\tR\x04text\x12!\n" + "\fbot_username\x18\x02 \x01(\tR\vbotUsername\x12\x1d\n" + @@ -2024,7 +2117,8 @@ const file_ai_proto_rawDesc = "" + "\rsteam_user_id\x18\b \x01(\x03R\vsteamUserId\x12+\n" + "\x11supports_deferred\x18\t \x01(\bR\x10supportsDeferred\x123\n" + "\rused_memories\x18\n" + - " \x03(\v2\x0e.ai.UsedMemoryR\fusedMemories\"\xd4\x01\n" + + " \x03(\v2\x0e.ai.UsedMemoryR\fusedMemories\x12!\n" + + "\fuser_message\x18\v \x01(\tR\vuserMessage\"\xd4\x01\n" + "\n" + "UsedMemory\x12\x0e\n" + "\x02id\x18\x01 \x01(\x03R\x02id\x12\x17\n" + @@ -2036,7 +2130,7 @@ const file_ai_proto_rawDesc = "" + "\bpriority\x18\a \x01(\tR\bpriority\x12!\n" + "\fsource_label\x18\b \x01(\tR\vsourceLabel\"M\n" + "\x17AnswerGenerationOptions\x122\n" + - "\x15include_user_memories\x18\x01 \x01(\bR\x13includeUserMemories\"\xec\x01\n" + + "\x15include_user_memories\x18\x01 \x01(\bR\x13includeUserMemories\"\x80\x03\n" + "\n" + "AIResponse\x12\x18\n" + "\acontent\x18\x01 \x01(\tR\acontent\x12\x14\n" + @@ -2047,7 +2141,12 @@ const file_ai_proto_rawDesc = "" + "\x06status\x18\x05 \x01(\x0e2\x10.ai.AnswerStatusR\x06status\x12\x15\n" + "\x06job_id\x18\x06 \x01(\tR\x05jobId\x12\x1f\n" + "\vresponse_id\x18\a \x01(\tR\n" + - "responseId\",\n" + + "responseId\x12$\n" + + "\x04kind\x18\b \x01(\x0e2\x10.ai.ResponseKindR\x04kind\x12!\n" + + "\fimage_base64\x18\t \x01(\tR\vimageBase64\x12&\n" + + "\x0fimage_mime_type\x18\n" + + " \x01(\tR\rimageMimeType\x12!\n" + + "\fimage_prompt\x18\v \x01(\tR\vimagePrompt\",\n" + "\x13GetAnswerJobRequest\x12\x15\n" + "\x06job_id\x18\x01 \x01(\tR\x05jobId\"\xe0\x01\n" + "\x11AnswerJobResponse\x12(\n" + @@ -2181,7 +2280,11 @@ const file_ai_proto_rawDesc = "" + "\x17CancelAnswerJobResponse\x12(\n" + "\x05state\x18\x01 \x01(\x0e2\x12.ai.AnswerJobStateR\x05state\x12\x1c\n" + "\tcancelled\x18\x02 \x01(\bR\tcancelled\x12\x14\n" + - "\x05error\x18\x03 \x01(\tR\x05error*d\n" + + "\x05error\x18\x03 \x01(\tR\x05error*^\n" + + "\fResponseKind\x12\x1d\n" + + "\x19RESPONSE_KIND_UNSPECIFIED\x10\x00\x12\x16\n" + + "\x12RESPONSE_KIND_TEXT\x10\x01\x12\x17\n" + + "\x13RESPONSE_KIND_IMAGE\x10\x02*d\n" + "\fAnswerStatus\x12\x1d\n" + "\x19ANSWER_STATUS_UNSPECIFIED\x10\x00\x12\x1a\n" + "\x16ANSWER_STATUS_COMPLETE\x10\x01\x12\x19\n" + @@ -2223,79 +2326,81 @@ func file_ai_proto_rawDescGZIP() []byte { return file_ai_proto_rawDescData } -var file_ai_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_ai_proto_enumTypes = make([]protoimpl.EnumInfo, 4) var file_ai_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_ai_proto_goTypes = []any{ - (AnswerStatus)(0), // 0: ai.AnswerStatus - (AnswerJobState)(0), // 1: ai.AnswerJobState - (AgentOutputFormat)(0), // 2: ai.AgentOutputFormat - (*AIRequest)(nil), // 3: ai.AIRequest - (*UsedMemory)(nil), // 4: ai.UsedMemory - (*AnswerGenerationOptions)(nil), // 5: ai.AnswerGenerationOptions - (*AIResponse)(nil), // 6: ai.AIResponse - (*GetAnswerJobRequest)(nil), // 7: ai.GetAnswerJobRequest - (*AnswerJobResponse)(nil), // 8: ai.AnswerJobResponse - (*ToolCallTrace)(nil), // 9: ai.ToolCallTrace - (*GetAIResponseTraceRequest)(nil), // 10: ai.GetAIResponseTraceRequest - (*GetAIResponseTraceResponse)(nil), // 11: ai.GetAIResponseTraceResponse - (*CreateSessionRequest)(nil), // 12: ai.CreateSessionRequest - (*CreateSessionResponse)(nil), // 13: ai.CreateSessionResponse - (*AskInSessionRequest)(nil), // 14: ai.AskInSessionRequest - (*SessionStatusResponse)(nil), // 15: ai.SessionStatusResponse - (*StatelessMessage)(nil), // 16: ai.StatelessMessage - (*StatelessRequest)(nil), // 17: ai.StatelessRequest - (*HealthCheckRequest)(nil), // 18: ai.HealthCheckRequest - (*HealthCheckResponse)(nil), // 19: ai.HealthCheckResponse - (*AgentToolLoopOptions)(nil), // 20: ai.AgentToolLoopOptions - (*AgentResponseContract)(nil), // 21: ai.AgentResponseContract - (*AgentRequest)(nil), // 22: ai.AgentRequest - (*AgentUsage)(nil), // 23: ai.AgentUsage - (*AgentResponse)(nil), // 24: ai.AgentResponse - (*CancelAnswerJobRequest)(nil), // 25: ai.CancelAnswerJobRequest - (*CancelAnswerJobResponse)(nil), // 26: ai.CancelAnswerJobResponse - nil, // 27: ai.AgentRequest.MetadataEntry + (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 } var file_ai_proto_depIdxs = []int32{ - 5, // 0: ai.AIRequest.options:type_name -> ai.AnswerGenerationOptions - 4, // 1: ai.AIRequest.used_memories:type_name -> ai.UsedMemory - 0, // 2: ai.AIResponse.status:type_name -> ai.AnswerStatus - 1, // 3: ai.AnswerJobResponse.state:type_name -> ai.AnswerJobState - 23, // 4: ai.AnswerJobResponse.agent_usage:type_name -> ai.AgentUsage - 4, // 5: ai.GetAIResponseTraceResponse.memories:type_name -> ai.UsedMemory - 9, // 6: ai.GetAIResponseTraceResponse.tool_calls:type_name -> ai.ToolCallTrace - 5, // 7: ai.AskInSessionRequest.options:type_name -> ai.AnswerGenerationOptions - 16, // 8: ai.StatelessRequest.messages:type_name -> ai.StatelessMessage - 2, // 9: ai.AgentResponseContract.format:type_name -> ai.AgentOutputFormat - 16, // 10: ai.AgentRequest.messages:type_name -> ai.StatelessMessage - 20, // 11: ai.AgentRequest.tool_loop:type_name -> ai.AgentToolLoopOptions - 21, // 12: ai.AgentRequest.response_contract:type_name -> ai.AgentResponseContract - 27, // 13: ai.AgentRequest.metadata:type_name -> ai.AgentRequest.MetadataEntry - 0, // 14: ai.AgentResponse.status:type_name -> ai.AnswerStatus - 23, // 15: ai.AgentResponse.usage:type_name -> ai.AgentUsage - 1, // 16: ai.CancelAnswerJobResponse.state:type_name -> ai.AnswerJobState - 22, // 17: ai.AIService.RunAgent:input_type -> ai.AgentRequest - 25, // 18: ai.AIService.CancelAnswerJob:input_type -> ai.CancelAnswerJobRequest - 3, // 19: ai.AIService.GenerateAnswer:input_type -> ai.AIRequest - 17, // 20: ai.AIService.GenerateStateless:input_type -> ai.StatelessRequest - 18, // 21: ai.AIService.HealthCheck:input_type -> ai.HealthCheckRequest - 12, // 22: ai.AIService.CreateSession:input_type -> ai.CreateSessionRequest - 14, // 23: ai.AIService.AskInSession:input_type -> ai.AskInSessionRequest - 7, // 24: ai.AIService.GetAnswerJob:input_type -> ai.GetAnswerJobRequest - 10, // 25: ai.AIService.GetAIResponseTrace:input_type -> ai.GetAIResponseTraceRequest - 24, // 26: ai.AIService.RunAgent:output_type -> ai.AgentResponse - 26, // 27: ai.AIService.CancelAnswerJob:output_type -> ai.CancelAnswerJobResponse - 6, // 28: ai.AIService.GenerateAnswer:output_type -> ai.AIResponse - 6, // 29: ai.AIService.GenerateStateless:output_type -> ai.AIResponse - 19, // 30: ai.AIService.HealthCheck:output_type -> ai.HealthCheckResponse - 13, // 31: ai.AIService.CreateSession:output_type -> ai.CreateSessionResponse - 15, // 32: ai.AIService.AskInSession:output_type -> ai.SessionStatusResponse - 8, // 33: ai.AIService.GetAnswerJob:output_type -> ai.AnswerJobResponse - 11, // 34: ai.AIService.GetAIResponseTrace:output_type -> ai.GetAIResponseTraceResponse - 26, // [26:35] is the sub-list for method output_type - 17, // [17:26] is the sub-list for method input_type - 17, // [17:17] is the sub-list for extension type_name - 17, // [17:17] is the sub-list for extension extendee - 0, // [0:17] is the sub-list for field type_name + 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 } func init() { file_ai_proto_init() } @@ -2308,7 +2413,7 @@ func file_ai_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_ai_proto_rawDesc), len(file_ai_proto_rawDesc)), - NumEnums: 3, + NumEnums: 4, NumMessages: 25, NumExtensions: 0, NumServices: 1, diff --git a/ai.proto b/ai.proto index 68ab78d..4244504 100644 --- a/ai.proto +++ b/ai.proto @@ -18,6 +18,10 @@ message AIRequest { // Структурированные воспоминания, которые клиент уже вложил в text (для debug-trace). // Core сохраняет их as-is на ai_response_traces — не перезапрашивает memories-сервис. repeated UsedMemory used_memories = 10; + // 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. + string user_message = 11; } // UsedMemory — снимок одного воспоминания, участвовавшего в генерации ответа. @@ -37,6 +41,13 @@ message AnswerGenerationOptions { bool include_user_memories = 1; // Включить воспоминания о пользователе в промпт } +// ResponseKind — тип синхронного ответа GenerateAnswer (кроме deferred jobs). +enum ResponseKind { + RESPONSE_KIND_UNSPECIFIED = 0; // трактуется как TEXT (обратная совместимость) + RESPONSE_KIND_TEXT = 1; // content — текстовый ответ + RESPONSE_KIND_IMAGE = 2; // image_base64 — сгенерированное изображение +} + // AIResponse содержит ответ от AI модели message AIResponse { string content = 1; // Текст ответа (при status=PENDING — interim-сообщение) @@ -47,6 +58,10 @@ message AIResponse { // PENDING — запущена долгая job, content это interim, финал тянуть через GetAnswerJob(job_id) string job_id = 6; // Идентификатор отложенной job (только при status=PENDING) string response_id = 7; // UUID (hex) debug-trace; доступен уже при PENDING + ResponseKind kind = 8; // TEXT (default) или IMAGE + string image_base64 = 9; // base64-encoded image bytes when kind=IMAGE + string image_mime_type = 10; // e.g. image/png when kind=IMAGE + string image_prompt = 11; // final Muse Image prompt when kind=IMAGE (for client-side history) } // AnswerStatus описывает, готов ли ответ синхронно или отложен в job.