feat(proto): GenerateAnswer image response and intent classification fields.

Add user_message on AIRequest, ResponseKind/image bytes on AIResponse, and
image_prompt so clients can persist image context in chat history.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Kaien 2026-09-01 01:10:12 +03:00
parent 37ed4e0a86
commit ea73b19a88
2 changed files with 207 additions and 87 deletions

273
ai.pb.go
View File

@ -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 модели
@ -207,6 +257,10 @@ type AIRequest struct {
// Структурированные воспоминания, которые клиент уже вложил в 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"`
// 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"`
@ -468,6 +529,10 @@ type AIResponse struct {
// 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
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,

View File

@ -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.