From 716c7f12ef1c6589caa1150240b107bb3ae6f061 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Thu, 5 Mar 2026 14:50:07 +0200 Subject: [PATCH 01/13] feat: record model thoughts Signed-off-by: Danny Kopping --- coderd/database/dbauthz/dbauthz.go | 7 + coderd/database/dbmetrics/querymetrics.go | 8 + coderd/database/dbmock/dbmock.go | 15 + coderd/database/dump.sql | 13 + .../000429_aibridge_model_thoughts.down.sql | 3 + .../000429_aibridge_model_thoughts.up.sql | 12 + .../000428_aibridge_model_thoughts.up.sql | 17 + coderd/database/models.go | 10 + coderd/database/querier.go | 1 + coderd/database/queries.sql.go | 45 ++ coderd/database/queries/aibridge.sql | 14 + coderd/database/sqlc.yaml | 1 + .../aibridged/aibridgedmock/clientmock.go | 2 +- enterprise/aibridged/proto/aibridged.pb.go | 526 +++++++++++------- enterprise/aibridged/proto/aibridged.proto | 11 +- enterprise/aibridged/translator.go | 10 + enterprise/aibridgedserver/aibridgedserver.go | 37 +- .../aibridgedserver/aibridgedserver_test.go | 97 +++- go.mod | 2 + go.sum | 2 - 20 files changed, 619 insertions(+), 214 deletions(-) create mode 100644 coderd/database/migrations/000429_aibridge_model_thoughts.down.sql create mode 100644 coderd/database/migrations/000429_aibridge_model_thoughts.up.sql create mode 100644 coderd/database/migrations/testdata/fixtures/000428_aibridge_model_thoughts.up.sql diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 95e5ce3a40289..12473140b2580 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -4441,6 +4441,13 @@ func (q *querier) InsertAIBridgeInterception(ctx context.Context, arg database.I return insert(q.log, q.auth, rbac.ResourceAibridgeInterception.WithOwner(arg.InitiatorID.String()), q.db.InsertAIBridgeInterception)(ctx, arg) } +func (q *querier) InsertAIBridgeModelThought(ctx context.Context, arg database.InsertAIBridgeModelThoughtParams) (database.AIBridgeModelThought, error) { + if err := q.authorizeAIBridgeInterceptionAction(ctx, policy.ActionUpdate, arg.InterceptionID); err != nil { + return database.AIBridgeModelThought{}, err + } + return q.db.InsertAIBridgeModelThought(ctx, arg) +} + func (q *querier) InsertAIBridgeTokenUsage(ctx context.Context, arg database.InsertAIBridgeTokenUsageParams) (database.AIBridgeTokenUsage, error) { // All aibridge_token_usages records belong to the initiator of their associated interception. if err := q.authorizeAIBridgeInterceptionAction(ctx, policy.ActionUpdate, arg.InterceptionID); err != nil { diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index f6b021086bc3b..9312c7d70d875 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -2887,6 +2887,14 @@ func (m queryMetricsStore) InsertAIBridgeInterception(ctx context.Context, arg d return r0, r1 } +func (m queryMetricsStore) InsertAIBridgeModelThought(ctx context.Context, arg database.InsertAIBridgeModelThoughtParams) (database.AIBridgeModelThought, error) { + start := time.Now() + r0, r1 := m.s.InsertAIBridgeModelThought(ctx, arg) + m.queryLatencies.WithLabelValues("InsertAIBridgeModelThought").Observe(time.Since(start).Seconds()) + m.queryCounts.WithLabelValues(httpmw.ExtractHTTPRoute(ctx), httpmw.ExtractHTTPMethod(ctx), "InsertAIBridgeModelThought").Inc() + return r0, r1 +} + func (m queryMetricsStore) InsertAIBridgeTokenUsage(ctx context.Context, arg database.InsertAIBridgeTokenUsageParams) (database.AIBridgeTokenUsage, error) { start := time.Now() r0, r1 := m.s.InsertAIBridgeTokenUsage(ctx, arg) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index bb56ae3e17aad..e3593e37355e4 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -5392,6 +5392,21 @@ func (mr *MockStoreMockRecorder) InsertAIBridgeInterception(ctx, arg any) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertAIBridgeInterception", reflect.TypeOf((*MockStore)(nil).InsertAIBridgeInterception), ctx, arg) } +// InsertAIBridgeModelThought mocks base method. +func (m *MockStore) InsertAIBridgeModelThought(ctx context.Context, arg database.InsertAIBridgeModelThoughtParams) (database.AIBridgeModelThought, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertAIBridgeModelThought", ctx, arg) + ret0, _ := ret[0].(database.AIBridgeModelThought) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertAIBridgeModelThought indicates an expected call of InsertAIBridgeModelThought. +func (mr *MockStoreMockRecorder) InsertAIBridgeModelThought(ctx, arg any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertAIBridgeModelThought", reflect.TypeOf((*MockStore)(nil).InsertAIBridgeModelThought), ctx, arg) +} + // InsertAIBridgeTokenUsage mocks base method. func (m *MockStore) InsertAIBridgeTokenUsage(ctx context.Context, arg database.InsertAIBridgeTokenUsageParams) (database.AIBridgeTokenUsage, error) { m.ctrl.T.Helper() diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index d1a7b91539c3d..de94b29773c5b 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -1085,6 +1085,17 @@ COMMENT ON COLUMN aibridge_interceptions.thread_root_id IS 'The root interceptio COMMENT ON COLUMN aibridge_interceptions.client_session_id IS 'The session ID supplied by the client (optional and not universally supported).'; +CREATE TABLE aibridge_model_thoughts ( + id uuid, + interception_id uuid NOT NULL, + tool_usage_id uuid NOT NULL, + content text, + metadata jsonb, + created_at timestamp with time zone NOT NULL +); + +COMMENT ON TABLE aibridge_model_thoughts IS 'Audit log of model thinking in intercepted requests in AI Bridge'; + CREATE TABLE aibridge_token_usages ( id uuid NOT NULL, interception_id uuid NOT NULL, @@ -3527,6 +3538,8 @@ CREATE INDEX idx_aibridge_interceptions_thread_parent_id ON aibridge_interceptio CREATE INDEX idx_aibridge_interceptions_thread_root_id ON aibridge_interceptions USING btree (thread_root_id); +CREATE INDEX idx_aibridge_model_thoughts_interception_id ON aibridge_model_thoughts USING btree (interception_id); + CREATE INDEX idx_aibridge_token_usages_interception_id ON aibridge_token_usages USING btree (interception_id); CREATE INDEX idx_aibridge_token_usages_provider_response_id ON aibridge_token_usages USING btree (provider_response_id); diff --git a/coderd/database/migrations/000429_aibridge_model_thoughts.down.sql b/coderd/database/migrations/000429_aibridge_model_thoughts.down.sql new file mode 100644 index 0000000000000..b258d1da0273d --- /dev/null +++ b/coderd/database/migrations/000429_aibridge_model_thoughts.down.sql @@ -0,0 +1,3 @@ +DROP INDEX idx_aibridge_model_thoughts_interception_id; + +DROP TABLE aibridge_model_thoughts; diff --git a/coderd/database/migrations/000429_aibridge_model_thoughts.up.sql b/coderd/database/migrations/000429_aibridge_model_thoughts.up.sql new file mode 100644 index 0000000000000..fdca71236e5b1 --- /dev/null +++ b/coderd/database/migrations/000429_aibridge_model_thoughts.up.sql @@ -0,0 +1,12 @@ +CREATE TABLE aibridge_model_thoughts ( + id UUID, + interception_id UUID NOT NULL, + tool_usage_id UUID NOT NULL, + content TEXT, + metadata jsonb, + created_at TIMESTAMPTZ NOT NULL +); + +COMMENT ON TABLE aibridge_model_thoughts IS 'Audit log of model thinking in intercepted requests in AI Bridge'; + +CREATE INDEX idx_aibridge_model_thoughts_interception_id ON aibridge_model_thoughts(interception_id); diff --git a/coderd/database/migrations/testdata/fixtures/000428_aibridge_model_thoughts.up.sql b/coderd/database/migrations/testdata/fixtures/000428_aibridge_model_thoughts.up.sql new file mode 100644 index 0000000000000..7579b41ea354d --- /dev/null +++ b/coderd/database/migrations/testdata/fixtures/000428_aibridge_model_thoughts.up.sql @@ -0,0 +1,17 @@ +INSERT INTO + aibridge_model_thoughts ( + id, + interception_id, + tool_usage_id, + content, + metadata, + created_at + ) +VALUES ( + 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', + 'be003e1e-b38f-43bf-847d-928074dd0aa8', -- from 000370_aibridge.up.sql + '613b4cfa-a257-4e88-99e6-4d2e99ea25f0', -- from 000370_aibridge.up.sql (tool usage) + 'The user is asking about their workspaces. I should use the coder_list_workspaces tool to retrieve this information.', + '{"thinking_tokens": 42}', + '2025-09-15 12:45:19.123456+00' +); diff --git a/coderd/database/models.go b/coderd/database/models.go index 9b07ae580a45c..e007498faa045 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -3974,6 +3974,16 @@ type AIBridgeInterception struct { ClientSessionID sql.NullString `db:"client_session_id" json:"client_session_id"` } +// Audit log of model thinking in intercepted requests in AI Bridge +type AIBridgeModelThought struct { + ID uuid.NullUUID `db:"id" json:"id"` + InterceptionID uuid.UUID `db:"interception_id" json:"interception_id"` + ToolUsageID uuid.UUID `db:"tool_usage_id" json:"tool_usage_id"` + Content sql.NullString `db:"content" json:"content"` + Metadata pqtype.NullRawMessage `db:"metadata" json:"metadata"` + CreatedAt time.Time `db:"created_at" json:"created_at"` +} + // Audit log of tokens used by intercepted requests in AI Bridge type AIBridgeTokenUsage struct { ID uuid.UUID `db:"id" json:"id"` diff --git a/coderd/database/querier.go b/coderd/database/querier.go index c25219148319e..4e9dfab4c4194 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -600,6 +600,7 @@ type sqlcQuerier interface { GetWorkspacesEligibleForTransition(ctx context.Context, now time.Time) ([]GetWorkspacesEligibleForTransitionRow, error) GetWorkspacesForWorkspaceMetrics(ctx context.Context) ([]GetWorkspacesForWorkspaceMetricsRow, error) InsertAIBridgeInterception(ctx context.Context, arg InsertAIBridgeInterceptionParams) (AIBridgeInterception, error) + InsertAIBridgeModelThought(ctx context.Context, arg InsertAIBridgeModelThoughtParams) (AIBridgeModelThought, error) InsertAIBridgeTokenUsage(ctx context.Context, arg InsertAIBridgeTokenUsageParams) (AIBridgeTokenUsage, error) InsertAIBridgeToolUsage(ctx context.Context, arg InsertAIBridgeToolUsageParams) (AIBridgeToolUsage, error) InsertAIBridgeUserPrompt(ctx context.Context, arg InsertAIBridgeUserPromptParams) (AIBridgeUserPrompt, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 79283ac791a2c..1d8e18817a097 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -340,6 +340,11 @@ WITH WHERE started_at < $1::timestamp with time zone ), -- CTEs are executed in order. + model_thoughts AS ( + DELETE FROM aibridge_model_thoughts + WHERE interception_id IN (SELECT id FROM to_delete) + RETURNING 1 + ), tool_usages AS ( DELETE FROM aibridge_tool_usages WHERE interception_id IN (SELECT id FROM to_delete) @@ -361,6 +366,7 @@ WITH RETURNING 1 ) SELECT ( + (SELECT COUNT(*) FROM model_thoughts) + (SELECT COUNT(*) FROM tool_usages) + (SELECT COUNT(*) FROM token_usages) + (SELECT COUNT(*) FROM user_prompts) + @@ -661,6 +667,45 @@ func (q *sqlQuerier) InsertAIBridgeInterception(ctx context.Context, arg InsertA return i, err } +const insertAIBridgeModelThought = `-- name: InsertAIBridgeModelThought :one +INSERT INTO aibridge_model_thoughts ( + id, interception_id, tool_usage_id, content, metadata, created_at +) VALUES ( + $1, $2, $3, $4, COALESCE($5::jsonb, '{}'::jsonb), $6 +) +RETURNING id, interception_id, tool_usage_id, content, metadata, created_at +` + +type InsertAIBridgeModelThoughtParams struct { + ID uuid.NullUUID `db:"id" json:"id"` + InterceptionID uuid.UUID `db:"interception_id" json:"interception_id"` + ToolUsageID uuid.UUID `db:"tool_usage_id" json:"tool_usage_id"` + Content sql.NullString `db:"content" json:"content"` + Metadata json.RawMessage `db:"metadata" json:"metadata"` + CreatedAt time.Time `db:"created_at" json:"created_at"` +} + +func (q *sqlQuerier) InsertAIBridgeModelThought(ctx context.Context, arg InsertAIBridgeModelThoughtParams) (AIBridgeModelThought, error) { + row := q.db.QueryRowContext(ctx, insertAIBridgeModelThought, + arg.ID, + arg.InterceptionID, + arg.ToolUsageID, + arg.Content, + arg.Metadata, + arg.CreatedAt, + ) + var i AIBridgeModelThought + err := row.Scan( + &i.ID, + &i.InterceptionID, + &i.ToolUsageID, + &i.Content, + &i.Metadata, + &i.CreatedAt, + ) + return i, err +} + const insertAIBridgeTokenUsage = `-- name: InsertAIBridgeTokenUsage :one INSERT INTO aibridge_token_usages ( id, interception_id, provider_response_id, input_tokens, output_tokens, metadata, created_at diff --git a/coderd/database/queries/aibridge.sql b/coderd/database/queries/aibridge.sql index ae0e796b12dad..3ea05fc8c6ee2 100644 --- a/coderd/database/queries/aibridge.sql +++ b/coderd/database/queries/aibridge.sql @@ -53,6 +53,14 @@ INSERT INTO aibridge_tool_usages ( ) RETURNING *; +-- name: InsertAIBridgeModelThought :one +INSERT INTO aibridge_model_thoughts ( + id, interception_id, tool_usage_id, content, metadata, created_at +) VALUES ( + @id, @interception_id, @tool_usage_id, @content, COALESCE(@metadata::jsonb, '{}'::jsonb), @created_at +) +RETURNING *; + -- name: GetAIBridgeInterceptionByID :one SELECT * @@ -362,6 +370,11 @@ WITH WHERE started_at < @before_time::timestamp with time zone ), -- CTEs are executed in order. + model_thoughts AS ( + DELETE FROM aibridge_model_thoughts + WHERE interception_id IN (SELECT id FROM to_delete) + RETURNING 1 + ), tool_usages AS ( DELETE FROM aibridge_tool_usages WHERE interception_id IN (SELECT id FROM to_delete) @@ -384,6 +397,7 @@ WITH ) -- Cumulative count. SELECT ( + (SELECT COUNT(*) FROM model_thoughts) + (SELECT COUNT(*) FROM tool_usages) + (SELECT COUNT(*) FROM token_usages) + (SELECT COUNT(*) FROM user_prompts) + diff --git a/coderd/database/sqlc.yaml b/coderd/database/sqlc.yaml index b692606fab309..72c968fcd8843 100644 --- a/coderd/database/sqlc.yaml +++ b/coderd/database/sqlc.yaml @@ -235,6 +235,7 @@ sql: aibridge_tool_usage: AIBridgeToolUsage aibridge_token_usage: AIBridgeTokenUsage aibridge_user_prompt: AIBridgeUserPrompt + aibridge_model_thought: AIBridgeModelThought rules: - name: do-not-use-public-schema-in-queries message: "do not use public schema in queries" diff --git a/enterprise/aibridged/aibridgedmock/clientmock.go b/enterprise/aibridged/aibridgedmock/clientmock.go index 2bb7083e10924..b5cf662c2973d 100644 --- a/enterprise/aibridged/aibridgedmock/clientmock.go +++ b/enterprise/aibridged/aibridgedmock/clientmock.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -destination ./clientmock.go -package aibridgedmock github.com/coder/coder/v2/enterprise/aibridged DRPCClient +// mockgen -destination ./enterprise/aibridged/aibridgedmock/clientmock.go -package aibridgedmock github.com/coder/coder/v2/enterprise/aibridged DRPCClient // // Package aibridgedmock is a generated GoMock package. diff --git a/enterprise/aibridged/proto/aibridged.pb.go b/enterprise/aibridged/proto/aibridged.pb.go index 683c53780373c..20fe3e6523806 100644 --- a/enterprise/aibridged/proto/aibridged.pb.go +++ b/enterprise/aibridged/proto/aibridged.pb.go @@ -536,7 +536,8 @@ type RecordToolUsageRequest struct { InvocationError *string `protobuf:"bytes,7,opt,name=invocation_error,json=invocationError,proto3,oneof" json:"invocation_error,omitempty"` // Only injected tools are invoked. Metadata map[string]*anypb.Any `protobuf:"bytes,8,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` CreatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - ToolCallId string `protobuf:"bytes,10,opt,name=tool_call_id,json=toolCallId,proto3" json:"tool_call_id,omitempty"` // The ID of the tool call provided by the AI provider. + ToolCallId string `protobuf:"bytes,10,opt,name=tool_call_id,json=toolCallId,proto3" json:"tool_call_id,omitempty"` // The ID of the tool call provided by the AI provider. + ModelThoughts []*ModelThought `protobuf:"bytes,11,rep,name=model_thoughts,json=modelThoughts,proto3" json:"model_thoughts,omitempty"` // Model thinking associated with this tool call. } func (x *RecordToolUsageRequest) Reset() { @@ -641,6 +642,13 @@ func (x *RecordToolUsageRequest) GetToolCallId() string { return "" } +func (x *RecordToolUsageRequest) GetModelThoughts() []*ModelThought { + if x != nil { + return x.ModelThoughts + } + return nil +} + type RecordToolUsageResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -679,6 +687,71 @@ func (*RecordToolUsageResponse) Descriptor() ([]byte, []int) { return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{9} } +// ModelThought represents a model's thinking/reasoning associated with +// a tool call. +type ModelThought struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` + Metadata map[string]*anypb.Any `protobuf:"bytes,2,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` +} + +func (x *ModelThought) Reset() { + *x = ModelThought{} + if protoimpl.UnsafeEnabled { + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ModelThought) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ModelThought) ProtoMessage() {} + +func (x *ModelThought) ProtoReflect() protoreflect.Message { + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ModelThought.ProtoReflect.Descriptor instead. +func (*ModelThought) Descriptor() ([]byte, []int) { + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{10} +} + +func (x *ModelThought) GetContent() string { + if x != nil { + return x.Content + } + return "" +} + +func (x *ModelThought) GetMetadata() map[string]*anypb.Any { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *ModelThought) GetCreatedAt() *timestamppb.Timestamp { + if x != nil { + return x.CreatedAt + } + return nil +} + type GetMCPServerConfigsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -690,7 +763,7 @@ type GetMCPServerConfigsRequest struct { func (x *GetMCPServerConfigsRequest) Reset() { *x = GetMCPServerConfigsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[10] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -703,7 +776,7 @@ func (x *GetMCPServerConfigsRequest) String() string { func (*GetMCPServerConfigsRequest) ProtoMessage() {} func (x *GetMCPServerConfigsRequest) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[10] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -716,7 +789,7 @@ func (x *GetMCPServerConfigsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMCPServerConfigsRequest.ProtoReflect.Descriptor instead. func (*GetMCPServerConfigsRequest) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{10} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{11} } func (x *GetMCPServerConfigsRequest) GetUserId() string { @@ -738,7 +811,7 @@ type GetMCPServerConfigsResponse struct { func (x *GetMCPServerConfigsResponse) Reset() { *x = GetMCPServerConfigsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[11] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -751,7 +824,7 @@ func (x *GetMCPServerConfigsResponse) String() string { func (*GetMCPServerConfigsResponse) ProtoMessage() {} func (x *GetMCPServerConfigsResponse) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[11] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -764,7 +837,7 @@ func (x *GetMCPServerConfigsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMCPServerConfigsResponse.ProtoReflect.Descriptor instead. func (*GetMCPServerConfigsResponse) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{11} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{12} } func (x *GetMCPServerConfigsResponse) GetCoderMcpConfig() *MCPServerConfig { @@ -795,7 +868,7 @@ type MCPServerConfig struct { func (x *MCPServerConfig) Reset() { *x = MCPServerConfig{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[12] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -808,7 +881,7 @@ func (x *MCPServerConfig) String() string { func (*MCPServerConfig) ProtoMessage() {} func (x *MCPServerConfig) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[12] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -821,7 +894,7 @@ func (x *MCPServerConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use MCPServerConfig.ProtoReflect.Descriptor instead. func (*MCPServerConfig) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{12} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{13} } func (x *MCPServerConfig) GetId() string { @@ -864,7 +937,7 @@ type GetMCPServerAccessTokensBatchRequest struct { func (x *GetMCPServerAccessTokensBatchRequest) Reset() { *x = GetMCPServerAccessTokensBatchRequest{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[13] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -877,7 +950,7 @@ func (x *GetMCPServerAccessTokensBatchRequest) String() string { func (*GetMCPServerAccessTokensBatchRequest) ProtoMessage() {} func (x *GetMCPServerAccessTokensBatchRequest) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[13] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -890,7 +963,7 @@ func (x *GetMCPServerAccessTokensBatchRequest) ProtoReflect() protoreflect.Messa // Deprecated: Use GetMCPServerAccessTokensBatchRequest.ProtoReflect.Descriptor instead. func (*GetMCPServerAccessTokensBatchRequest) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{13} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{14} } func (x *GetMCPServerAccessTokensBatchRequest) GetUserId() string { @@ -921,7 +994,7 @@ type GetMCPServerAccessTokensBatchResponse struct { func (x *GetMCPServerAccessTokensBatchResponse) Reset() { *x = GetMCPServerAccessTokensBatchResponse{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[14] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -934,7 +1007,7 @@ func (x *GetMCPServerAccessTokensBatchResponse) String() string { func (*GetMCPServerAccessTokensBatchResponse) ProtoMessage() {} func (x *GetMCPServerAccessTokensBatchResponse) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[14] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -947,7 +1020,7 @@ func (x *GetMCPServerAccessTokensBatchResponse) ProtoReflect() protoreflect.Mess // Deprecated: Use GetMCPServerAccessTokensBatchResponse.ProtoReflect.Descriptor instead. func (*GetMCPServerAccessTokensBatchResponse) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{14} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{15} } func (x *GetMCPServerAccessTokensBatchResponse) GetAccessTokens() map[string]string { @@ -975,7 +1048,7 @@ type IsAuthorizedRequest struct { func (x *IsAuthorizedRequest) Reset() { *x = IsAuthorizedRequest{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[15] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -988,7 +1061,7 @@ func (x *IsAuthorizedRequest) String() string { func (*IsAuthorizedRequest) ProtoMessage() {} func (x *IsAuthorizedRequest) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[15] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1001,7 +1074,7 @@ func (x *IsAuthorizedRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use IsAuthorizedRequest.ProtoReflect.Descriptor instead. func (*IsAuthorizedRequest) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{15} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{16} } func (x *IsAuthorizedRequest) GetKey() string { @@ -1024,7 +1097,7 @@ type IsAuthorizedResponse struct { func (x *IsAuthorizedResponse) Reset() { *x = IsAuthorizedResponse{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[16] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1037,7 +1110,7 @@ func (x *IsAuthorizedResponse) String() string { func (*IsAuthorizedResponse) ProtoMessage() {} func (x *IsAuthorizedResponse) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[16] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1050,7 +1123,7 @@ func (x *IsAuthorizedResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use IsAuthorizedResponse.ProtoReflect.Descriptor instead. func (*IsAuthorizedResponse) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{16} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{17} } func (x *IsAuthorizedResponse) GetOwnerId() string { @@ -1180,7 +1253,7 @@ var file_enterprise_aibridged_proto_aibridged_proto_rawDesc = []byte{ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x8f, 0x04, 0x0a, 0x16, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, + 0x22, 0xcb, 0x04, 0x0a, 0x16, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, @@ -1205,131 +1278,150 @@ var file_enterprise_aibridged_proto_aibridged_proto_rawDesc = []byte{ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x74, 0x6f, 0x6f, 0x6c, 0x43, 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x1a, 0x51, 0x0a, 0x0d, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, - 0x0a, 0x0b, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x13, 0x0a, - 0x11, 0x5f, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x22, 0x19, 0x0a, 0x17, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, - 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x0a, - 0x1a, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, - 0x65, 0x72, 0x49, 0x64, 0x22, 0xb2, 0x01, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x10, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x63, - 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x63, 0x70, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x51, 0x0a, 0x19, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, - 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x52, 0x16, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x4d, - 0x63, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x0f, 0x4d, 0x43, - 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0e, 0x0a, - 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, - 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, - 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x65, - 0x67, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, 0x6f, 0x6f, 0x6c, 0x41, - 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x6f, - 0x6c, 0x5f, 0x64, 0x65, 0x6e, 0x79, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x74, 0x6f, 0x6f, 0x6c, 0x44, 0x65, 0x6e, 0x79, 0x52, 0x65, 0x67, 0x65, - 0x78, 0x22, 0x72, 0x0a, 0x24, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, - 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x6d, 0x63, 0x70, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x12, 0x6d, 0x63, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x49, 0x64, 0x73, 0x22, 0xda, 0x02, 0x0a, 0x25, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, - 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x63, 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, - 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, - 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x50, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x02, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, - 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x1a, 0x3f, 0x0a, 0x11, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, - 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, - 0x38, 0x01, 0x22, 0x27, 0x0a, 0x13, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, - 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, 0x6b, 0x0a, 0x14, 0x49, - 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, - 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, - 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0xce, 0x03, 0x0a, 0x08, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x59, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, - 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, - 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, - 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x68, 0x0a, 0x17, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, - 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, - 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, - 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, - 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x56, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, - 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, - 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xeb, 0x01, 0x0a, 0x0f, 0x4d, 0x43, - 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x5c, 0x0a, - 0x13, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, + 0x0a, 0x74, 0x6f, 0x6f, 0x6c, 0x43, 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x0e, 0x6d, + 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x73, 0x18, 0x0b, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x6f, 0x64, 0x65, + 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, + 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x73, 0x1a, 0x51, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x69, 0x6e, + 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x19, + 0x0a, 0x17, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x0c, 0x4d, 0x6f, + 0x64, 0x65, 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, + 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, + 0x74, 0x65, 0x6e, 0x74, 0x12, 0x3d, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, + 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, + 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0x51, + 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x22, 0x35, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0xb2, 0x01, 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, - 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7a, 0x0a, 0x1d, 0x47, - 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, - 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x2b, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, - 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x55, 0x0a, 0x0a, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x72, 0x12, 0x47, 0x0a, 0x0c, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, - 0x72, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x73, - 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2b, - 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, - 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x61, 0x69, 0x62, 0x72, - 0x69, 0x64, 0x67, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x10, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x5f, 0x6d, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x43, 0x50, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x4d, 0x63, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x51, 0x0a, 0x19, 0x65, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x63, 0x70, 0x5f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x16, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, + 0x75, 0x74, 0x68, 0x4d, 0x63, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0x85, 0x01, + 0x0a, 0x0f, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x75, 0x72, 0x6c, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, + 0x77, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, + 0x6f, 0x6f, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x26, 0x0a, + 0x0f, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x64, 0x65, 0x6e, 0x79, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x6f, 0x6f, 0x6c, 0x44, 0x65, 0x6e, 0x79, + 0x52, 0x65, 0x67, 0x65, 0x78, 0x22, 0x72, 0x0a, 0x24, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, + 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x6d, 0x63, 0x70, 0x5f, 0x73, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x6d, 0x63, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x73, 0x22, 0xda, 0x02, 0x0a, 0x25, 0x47, 0x65, + 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, + 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, + 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x50, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, + 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x1a, 0x3f, 0x0a, 0x11, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x45, + 0x72, 0x72, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x27, 0x0a, 0x13, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, + 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, + 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, + 0x6b, 0x0a, 0x14, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x49, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0xce, 0x03, 0x0a, + 0x08, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x59, 0x0a, 0x12, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, + 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x17, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x12, + 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, + 0x0a, 0x10, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, + 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, + 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, + 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x52, + 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, + 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, + 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xeb, 0x01, + 0x0a, 0x0f, 0x4d, 0x43, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x6f, + 0x72, 0x12, 0x5c, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, + 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x7a, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, + 0x12, 0x2b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, + 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x55, 0x0a, 0x0a, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x72, 0x12, 0x47, 0x0a, 0x0c, 0x49, 0x73, 0x41, + 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x73, + 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, + 0x61, 0x69, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1344,7 +1436,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP() []byte { return file_enterprise_aibridged_proto_aibridged_proto_rawDescData } -var file_enterprise_aibridged_proto_aibridged_proto_msgTypes = make([]protoimpl.MessageInfo, 23) +var file_enterprise_aibridged_proto_aibridged_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_enterprise_aibridged_proto_aibridged_proto_goTypes = []interface{}{ (*RecordInterceptionRequest)(nil), // 0: proto.RecordInterceptionRequest (*RecordInterceptionResponse)(nil), // 1: proto.RecordInterceptionResponse @@ -1356,61 +1448,67 @@ var file_enterprise_aibridged_proto_aibridged_proto_goTypes = []interface{}{ (*RecordPromptUsageResponse)(nil), // 7: proto.RecordPromptUsageResponse (*RecordToolUsageRequest)(nil), // 8: proto.RecordToolUsageRequest (*RecordToolUsageResponse)(nil), // 9: proto.RecordToolUsageResponse - (*GetMCPServerConfigsRequest)(nil), // 10: proto.GetMCPServerConfigsRequest - (*GetMCPServerConfigsResponse)(nil), // 11: proto.GetMCPServerConfigsResponse - (*MCPServerConfig)(nil), // 12: proto.MCPServerConfig - (*GetMCPServerAccessTokensBatchRequest)(nil), // 13: proto.GetMCPServerAccessTokensBatchRequest - (*GetMCPServerAccessTokensBatchResponse)(nil), // 14: proto.GetMCPServerAccessTokensBatchResponse - (*IsAuthorizedRequest)(nil), // 15: proto.IsAuthorizedRequest - (*IsAuthorizedResponse)(nil), // 16: proto.IsAuthorizedResponse - nil, // 17: proto.RecordInterceptionRequest.MetadataEntry - nil, // 18: proto.RecordTokenUsageRequest.MetadataEntry - nil, // 19: proto.RecordPromptUsageRequest.MetadataEntry - nil, // 20: proto.RecordToolUsageRequest.MetadataEntry - nil, // 21: proto.GetMCPServerAccessTokensBatchResponse.AccessTokensEntry - nil, // 22: proto.GetMCPServerAccessTokensBatchResponse.ErrorsEntry - (*timestamppb.Timestamp)(nil), // 23: google.protobuf.Timestamp - (*anypb.Any)(nil), // 24: google.protobuf.Any + (*ModelThought)(nil), // 10: proto.ModelThought + (*GetMCPServerConfigsRequest)(nil), // 11: proto.GetMCPServerConfigsRequest + (*GetMCPServerConfigsResponse)(nil), // 12: proto.GetMCPServerConfigsResponse + (*MCPServerConfig)(nil), // 13: proto.MCPServerConfig + (*GetMCPServerAccessTokensBatchRequest)(nil), // 14: proto.GetMCPServerAccessTokensBatchRequest + (*GetMCPServerAccessTokensBatchResponse)(nil), // 15: proto.GetMCPServerAccessTokensBatchResponse + (*IsAuthorizedRequest)(nil), // 16: proto.IsAuthorizedRequest + (*IsAuthorizedResponse)(nil), // 17: proto.IsAuthorizedResponse + nil, // 18: proto.RecordInterceptionRequest.MetadataEntry + nil, // 19: proto.RecordTokenUsageRequest.MetadataEntry + nil, // 20: proto.RecordPromptUsageRequest.MetadataEntry + nil, // 21: proto.RecordToolUsageRequest.MetadataEntry + nil, // 22: proto.ModelThought.MetadataEntry + nil, // 23: proto.GetMCPServerAccessTokensBatchResponse.AccessTokensEntry + nil, // 24: proto.GetMCPServerAccessTokensBatchResponse.ErrorsEntry + (*timestamppb.Timestamp)(nil), // 25: google.protobuf.Timestamp + (*anypb.Any)(nil), // 26: google.protobuf.Any } var file_enterprise_aibridged_proto_aibridged_proto_depIdxs = []int32{ - 17, // 0: proto.RecordInterceptionRequest.metadata:type_name -> proto.RecordInterceptionRequest.MetadataEntry - 23, // 1: proto.RecordInterceptionRequest.started_at:type_name -> google.protobuf.Timestamp - 23, // 2: proto.RecordInterceptionEndedRequest.ended_at:type_name -> google.protobuf.Timestamp - 18, // 3: proto.RecordTokenUsageRequest.metadata:type_name -> proto.RecordTokenUsageRequest.MetadataEntry - 23, // 4: proto.RecordTokenUsageRequest.created_at:type_name -> google.protobuf.Timestamp - 19, // 5: proto.RecordPromptUsageRequest.metadata:type_name -> proto.RecordPromptUsageRequest.MetadataEntry - 23, // 6: proto.RecordPromptUsageRequest.created_at:type_name -> google.protobuf.Timestamp - 20, // 7: proto.RecordToolUsageRequest.metadata:type_name -> proto.RecordToolUsageRequest.MetadataEntry - 23, // 8: proto.RecordToolUsageRequest.created_at:type_name -> google.protobuf.Timestamp - 12, // 9: proto.GetMCPServerConfigsResponse.coder_mcp_config:type_name -> proto.MCPServerConfig - 12, // 10: proto.GetMCPServerConfigsResponse.external_auth_mcp_configs:type_name -> proto.MCPServerConfig - 21, // 11: proto.GetMCPServerAccessTokensBatchResponse.access_tokens:type_name -> proto.GetMCPServerAccessTokensBatchResponse.AccessTokensEntry - 22, // 12: proto.GetMCPServerAccessTokensBatchResponse.errors:type_name -> proto.GetMCPServerAccessTokensBatchResponse.ErrorsEntry - 24, // 13: proto.RecordInterceptionRequest.MetadataEntry.value:type_name -> google.protobuf.Any - 24, // 14: proto.RecordTokenUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any - 24, // 15: proto.RecordPromptUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any - 24, // 16: proto.RecordToolUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any - 0, // 17: proto.Recorder.RecordInterception:input_type -> proto.RecordInterceptionRequest - 2, // 18: proto.Recorder.RecordInterceptionEnded:input_type -> proto.RecordInterceptionEndedRequest - 4, // 19: proto.Recorder.RecordTokenUsage:input_type -> proto.RecordTokenUsageRequest - 6, // 20: proto.Recorder.RecordPromptUsage:input_type -> proto.RecordPromptUsageRequest - 8, // 21: proto.Recorder.RecordToolUsage:input_type -> proto.RecordToolUsageRequest - 10, // 22: proto.MCPConfigurator.GetMCPServerConfigs:input_type -> proto.GetMCPServerConfigsRequest - 13, // 23: proto.MCPConfigurator.GetMCPServerAccessTokensBatch:input_type -> proto.GetMCPServerAccessTokensBatchRequest - 15, // 24: proto.Authorizer.IsAuthorized:input_type -> proto.IsAuthorizedRequest - 1, // 25: proto.Recorder.RecordInterception:output_type -> proto.RecordInterceptionResponse - 3, // 26: proto.Recorder.RecordInterceptionEnded:output_type -> proto.RecordInterceptionEndedResponse - 5, // 27: proto.Recorder.RecordTokenUsage:output_type -> proto.RecordTokenUsageResponse - 7, // 28: proto.Recorder.RecordPromptUsage:output_type -> proto.RecordPromptUsageResponse - 9, // 29: proto.Recorder.RecordToolUsage:output_type -> proto.RecordToolUsageResponse - 11, // 30: proto.MCPConfigurator.GetMCPServerConfigs:output_type -> proto.GetMCPServerConfigsResponse - 14, // 31: proto.MCPConfigurator.GetMCPServerAccessTokensBatch:output_type -> proto.GetMCPServerAccessTokensBatchResponse - 16, // 32: proto.Authorizer.IsAuthorized:output_type -> proto.IsAuthorizedResponse - 25, // [25:33] is the sub-list for method output_type - 17, // [17:25] 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 + 18, // 0: proto.RecordInterceptionRequest.metadata:type_name -> proto.RecordInterceptionRequest.MetadataEntry + 25, // 1: proto.RecordInterceptionRequest.started_at:type_name -> google.protobuf.Timestamp + 25, // 2: proto.RecordInterceptionEndedRequest.ended_at:type_name -> google.protobuf.Timestamp + 19, // 3: proto.RecordTokenUsageRequest.metadata:type_name -> proto.RecordTokenUsageRequest.MetadataEntry + 25, // 4: proto.RecordTokenUsageRequest.created_at:type_name -> google.protobuf.Timestamp + 20, // 5: proto.RecordPromptUsageRequest.metadata:type_name -> proto.RecordPromptUsageRequest.MetadataEntry + 25, // 6: proto.RecordPromptUsageRequest.created_at:type_name -> google.protobuf.Timestamp + 21, // 7: proto.RecordToolUsageRequest.metadata:type_name -> proto.RecordToolUsageRequest.MetadataEntry + 25, // 8: proto.RecordToolUsageRequest.created_at:type_name -> google.protobuf.Timestamp + 10, // 9: proto.RecordToolUsageRequest.model_thoughts:type_name -> proto.ModelThought + 22, // 10: proto.ModelThought.metadata:type_name -> proto.ModelThought.MetadataEntry + 25, // 11: proto.ModelThought.created_at:type_name -> google.protobuf.Timestamp + 13, // 12: proto.GetMCPServerConfigsResponse.coder_mcp_config:type_name -> proto.MCPServerConfig + 13, // 13: proto.GetMCPServerConfigsResponse.external_auth_mcp_configs:type_name -> proto.MCPServerConfig + 23, // 14: proto.GetMCPServerAccessTokensBatchResponse.access_tokens:type_name -> proto.GetMCPServerAccessTokensBatchResponse.AccessTokensEntry + 24, // 15: proto.GetMCPServerAccessTokensBatchResponse.errors:type_name -> proto.GetMCPServerAccessTokensBatchResponse.ErrorsEntry + 26, // 16: proto.RecordInterceptionRequest.MetadataEntry.value:type_name -> google.protobuf.Any + 26, // 17: proto.RecordTokenUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any + 26, // 18: proto.RecordPromptUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any + 26, // 19: proto.RecordToolUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any + 26, // 20: proto.ModelThought.MetadataEntry.value:type_name -> google.protobuf.Any + 0, // 21: proto.Recorder.RecordInterception:input_type -> proto.RecordInterceptionRequest + 2, // 22: proto.Recorder.RecordInterceptionEnded:input_type -> proto.RecordInterceptionEndedRequest + 4, // 23: proto.Recorder.RecordTokenUsage:input_type -> proto.RecordTokenUsageRequest + 6, // 24: proto.Recorder.RecordPromptUsage:input_type -> proto.RecordPromptUsageRequest + 8, // 25: proto.Recorder.RecordToolUsage:input_type -> proto.RecordToolUsageRequest + 11, // 26: proto.MCPConfigurator.GetMCPServerConfigs:input_type -> proto.GetMCPServerConfigsRequest + 14, // 27: proto.MCPConfigurator.GetMCPServerAccessTokensBatch:input_type -> proto.GetMCPServerAccessTokensBatchRequest + 16, // 28: proto.Authorizer.IsAuthorized:input_type -> proto.IsAuthorizedRequest + 1, // 29: proto.Recorder.RecordInterception:output_type -> proto.RecordInterceptionResponse + 3, // 30: proto.Recorder.RecordInterceptionEnded:output_type -> proto.RecordInterceptionEndedResponse + 5, // 31: proto.Recorder.RecordTokenUsage:output_type -> proto.RecordTokenUsageResponse + 7, // 32: proto.Recorder.RecordPromptUsage:output_type -> proto.RecordPromptUsageResponse + 9, // 33: proto.Recorder.RecordToolUsage:output_type -> proto.RecordToolUsageResponse + 12, // 34: proto.MCPConfigurator.GetMCPServerConfigs:output_type -> proto.GetMCPServerConfigsResponse + 15, // 35: proto.MCPConfigurator.GetMCPServerAccessTokensBatch:output_type -> proto.GetMCPServerAccessTokensBatchResponse + 17, // 36: proto.Authorizer.IsAuthorized:output_type -> proto.IsAuthorizedResponse + 29, // [29:37] is the sub-list for method output_type + 21, // [21:29] is the sub-list for method input_type + 21, // [21:21] is the sub-list for extension type_name + 21, // [21:21] is the sub-list for extension extendee + 0, // [0:21] is the sub-list for field type_name } func init() { file_enterprise_aibridged_proto_aibridged_proto_init() } @@ -1540,7 +1638,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMCPServerConfigsRequest); i { + switch v := v.(*ModelThought); i { case 0: return &v.state case 1: @@ -1552,7 +1650,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMCPServerConfigsResponse); i { + switch v := v.(*GetMCPServerConfigsRequest); i { case 0: return &v.state case 1: @@ -1564,7 +1662,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MCPServerConfig); i { + switch v := v.(*GetMCPServerConfigsResponse); i { case 0: return &v.state case 1: @@ -1576,7 +1674,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMCPServerAccessTokensBatchRequest); i { + switch v := v.(*MCPServerConfig); i { case 0: return &v.state case 1: @@ -1588,7 +1686,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMCPServerAccessTokensBatchResponse); i { + switch v := v.(*GetMCPServerAccessTokensBatchRequest); i { case 0: return &v.state case 1: @@ -1600,7 +1698,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IsAuthorizedRequest); i { + switch v := v.(*GetMCPServerAccessTokensBatchResponse); i { case 0: return &v.state case 1: @@ -1612,6 +1710,18 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IsAuthorizedRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_enterprise_aibridged_proto_aibridged_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IsAuthorizedResponse); i { case 0: return &v.state @@ -1632,7 +1742,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_enterprise_aibridged_proto_aibridged_proto_rawDesc, NumEnums: 0, - NumMessages: 23, + NumMessages: 25, NumExtensions: 0, NumServices: 3, }, diff --git a/enterprise/aibridged/proto/aibridged.proto b/enterprise/aibridged/proto/aibridged.proto index 44fb35fe475bc..cf2457e43ce3a 100644 --- a/enterprise/aibridged/proto/aibridged.proto +++ b/enterprise/aibridged/proto/aibridged.proto @@ -9,7 +9,7 @@ import "google/protobuf/timestamp.proto"; // Recorder is responsible for persisting AI usage records along with their related interception. service Recorder { // RecordInterception creates a new interception record to which all other sub-resources - // (token, prompt, tool uses) will be related. + // (token, prompt, tool uses, model thoughts) will be related. rpc RecordInterception(RecordInterceptionRequest) returns (RecordInterceptionResponse); rpc RecordInterceptionEnded(RecordInterceptionEndedRequest) returns (RecordInterceptionEndedResponse); rpc RecordTokenUsage(RecordTokenUsageRequest) returns (RecordTokenUsageResponse); @@ -88,9 +88,18 @@ message RecordToolUsageRequest { map metadata = 8; google.protobuf.Timestamp created_at = 9; string tool_call_id = 10; // The ID of the tool call provided by the AI provider. + repeated ModelThought model_thoughts = 11; // Model thinking associated with this tool call. } message RecordToolUsageResponse {} +// ModelThought represents a model's thinking/reasoning associated with +// a tool call. +message ModelThought { + string content = 1; + map metadata = 2; + google.protobuf.Timestamp created_at = 3; +} + message GetMCPServerConfigsRequest { string user_id = 1; // UUID. // Not used yet, will be necessary for later RBAC purposes. } diff --git a/enterprise/aibridged/translator.go b/enterprise/aibridged/translator.go index 0e878bffaf4c0..122a2135413f0 100644 --- a/enterprise/aibridged/translator.go +++ b/enterprise/aibridged/translator.go @@ -92,6 +92,15 @@ func (t *recorderTranslation) RecordToolUsage(ctx context.Context, req *aibridge invErr = ptr.Ref(req.InvocationError.Error()) } + var thoughts []*proto.ModelThought + for _, thought := range req.ModelThoughts { + thoughts = append(thoughts, &proto.ModelThought{ + Content: thought.Content, + Metadata: marshalForProto(thought.Metadata), + CreatedAt: timestamppb.New(thought.CreatedAt), + }) + } + _, err = t.client.RecordToolUsage(ctx, &proto.RecordToolUsageRequest{ InterceptionId: req.InterceptionID, MsgId: req.MsgID, @@ -103,6 +112,7 @@ func (t *recorderTranslation) RecordToolUsage(ctx context.Context, req *aibridge InvocationError: invErr, Metadata: marshalForProto(req.Metadata), CreatedAt: timestamppb.New(req.CreatedAt), + ModelThoughts: thoughts, }) return err } diff --git a/enterprise/aibridgedserver/aibridgedserver.go b/enterprise/aibridgedserver/aibridgedserver.go index 49f6b51bc6715..c1df057822ba4 100644 --- a/enterprise/aibridgedserver/aibridgedserver.go +++ b/enterprise/aibridgedserver/aibridgedserver.go @@ -60,6 +60,7 @@ type store interface { InsertAIBridgeTokenUsage(ctx context.Context, arg database.InsertAIBridgeTokenUsageParams) (database.AIBridgeTokenUsage, error) InsertAIBridgeUserPrompt(ctx context.Context, arg database.InsertAIBridgeUserPromptParams) (database.AIBridgeUserPrompt, error) InsertAIBridgeToolUsage(ctx context.Context, arg database.InsertAIBridgeToolUsageParams) (database.AIBridgeToolUsage, error) + InsertAIBridgeModelThought(ctx context.Context, arg database.InsertAIBridgeModelThoughtParams) (database.AIBridgeModelThought, error) UpdateAIBridgeInterceptionEnded(ctx context.Context, intcID database.UpdateAIBridgeInterceptionEndedParams) (database.AIBridgeInterception, error) GetAIBridgeInterceptionLineageByToolCallID(ctx context.Context, toolCallID string) (database.GetAIBridgeInterceptionLineageByToolCallIDRow, error) @@ -339,8 +340,9 @@ func (s *Server) RecordToolUsage(ctx context.Context, in *proto.RecordToolUsageR s.logger.Warn(ctx, "failed to marshal aibridge metadata from proto to JSON", slog.F("metadata", in), slog.Error(err)) } + toolUsageID := uuid.New() _, err = s.store.InsertAIBridgeToolUsage(ctx, database.InsertAIBridgeToolUsageParams{ - ID: uuid.New(), + ID: toolUsageID, InterceptionID: intcID, ProviderResponseID: in.GetMsgId(), ProviderToolCallID: sql.NullString{String: in.GetToolCallId(), Valid: in.GetToolCallId() != ""}, @@ -356,6 +358,39 @@ func (s *Server) RecordToolUsage(ctx context.Context, in *proto.RecordToolUsageR return nil, xerrors.Errorf("insert tool usage: %w", err) } + // Insert any model thoughts associated with this tool call. + for _, thought := range in.GetModelThoughts() { + thoughtMetadata := metadataToMap(thought.GetMetadata()) + + if s.structuredLogging { + s.logger.Info(ctx, InterceptionLogMarker, + slog.F("record_type", "model_thought"), + slog.F("interception_id", intcID.String()), + slog.F("tool_usage_id", toolUsageID.String()), + slog.F("content", thought.GetContent()), + slog.F("created_at", thought.GetCreatedAt().AsTime()), + slog.F("metadata", thoughtMetadata), + ) + } + + thoughtMetadataJSON, err := json.Marshal(thoughtMetadata) + if err != nil { + s.logger.Warn(ctx, "failed to marshal aibridge model thought metadata from proto to JSON", slog.F("metadata", thought), slog.Error(err)) + } + + _, err = s.store.InsertAIBridgeModelThought(ctx, database.InsertAIBridgeModelThoughtParams{ + ID: uuid.NullUUID{UUID: uuid.New(), Valid: true}, + InterceptionID: intcID, + ToolUsageID: toolUsageID, + Content: sql.NullString{String: thought.GetContent(), Valid: thought.GetContent() != ""}, + Metadata: thoughtMetadataJSON, + CreatedAt: thought.GetCreatedAt().AsTime(), + }) + if err != nil { + s.logger.Warn(ctx, "failed to insert model thought", slog.Error(err)) + } + } + return &proto.RecordToolUsageResponse{}, nil } diff --git a/enterprise/aibridgedserver/aibridgedserver_test.go b/enterprise/aibridgedserver/aibridgedserver_test.go index b195829534b2c..d0262055d0c5e 100644 --- a/enterprise/aibridgedserver/aibridgedserver_test.go +++ b/enterprise/aibridgedserver/aibridgedserver_test.go @@ -982,6 +982,60 @@ func TestRecordToolUsage(t *testing.T) { }, expectedErr: "insert tool usage", }, + { + name: "tool usage with model thoughts", + request: &proto.RecordToolUsageRequest{ + InterceptionId: uuid.NewString(), + MsgId: "msg_456", + ToolCallId: "call_abc", + Tool: "bash", + Input: `{"command": "ls"}`, + Injected: true, + CreatedAt: timestamppb.Now(), + ModelThoughts: []*proto.ModelThought{ + { + Content: "I should list the files.", + Metadata: metadataProto, + CreatedAt: timestamppb.Now(), + }, + }, + }, + setupMocks: func(t *testing.T, db *dbmock.MockStore, req *proto.RecordToolUsageRequest) { + interceptionID, err := uuid.Parse(req.GetInterceptionId()) + assert.NoError(t, err, "parse interception UUID") + + var toolUsageID uuid.UUID + db.EXPECT().InsertAIBridgeToolUsage(gomock.Any(), gomock.Cond(func(p database.InsertAIBridgeToolUsageParams) bool { + toolUsageID = p.ID + return assert.Equal(t, interceptionID, p.InterceptionID, "interception ID") + })).Return(database.AIBridgeToolUsage{ + ID: uuid.New(), + InterceptionID: interceptionID, + Tool: req.GetTool(), + CreatedAt: req.GetCreatedAt().AsTime(), + }, nil) + + db.EXPECT().InsertAIBridgeModelThought(gomock.Any(), gomock.Cond(func(p database.InsertAIBridgeModelThoughtParams) bool { + if !assert.True(t, p.ID.Valid, "ID valid") || + !assert.Equal(t, interceptionID, p.InterceptionID, "interception ID") || + !assert.Equal(t, toolUsageID, p.ToolUsageID, "tool usage ID") || + !assert.Equal(t, sql.NullString{String: "I should list the files.", Valid: true}, p.Content, "content") || + !assert.JSONEq(t, metadataJSON, string(p.Metadata), "metadata") { + return false + } + return true + })).Return(database.AIBridgeModelThought{ + ID: uuid.NullUUID{UUID: uuid.New(), Valid: true}, + InterceptionID: interceptionID, + ToolUsageID: toolUsageID, + Content: sql.NullString{String: "I should list the files.", Valid: true}, + Metadata: pqtype.NullRawMessage{ + RawMessage: json.RawMessage(metadataJSON), + Valid: true, + }, + }, nil) + }, + }, }, ) } @@ -1294,6 +1348,47 @@ func TestStructuredLogging(t *testing.T) { "invocation_error": "permission denied", }, }, + { + name: "RecordToolUsage_with_model_thought_logs_when_enabled", + structuredLogging: true, + setupMocks: func(db *dbmock.MockStore, intcID uuid.UUID) { + db.EXPECT().InsertAIBridgeToolUsage(gomock.Any(), gomock.Any()).Return(database.AIBridgeToolUsage{ + ID: uuid.New(), + InterceptionID: intcID, + Tool: "bash", + }, nil) + db.EXPECT().InsertAIBridgeModelThought(gomock.Any(), gomock.Any()).Return(database.AIBridgeModelThought{ + ID: uuid.NullUUID{UUID: uuid.New(), Valid: true}, + InterceptionID: intcID, + }, nil) + }, + recordFn: func(srv *aibridgedserver.Server, ctx context.Context, intcID uuid.UUID) error { + _, err := srv.RecordToolUsage(ctx, &proto.RecordToolUsageRequest{ + InterceptionId: intcID.String(), + MsgId: "msg_789", + ToolCallId: "call_xyz", + Tool: "bash", + Input: `{"command": "ls"}`, + Injected: true, + CreatedAt: timestamppb.Now(), + ModelThoughts: []*proto.ModelThought{ + { + Content: "I need to list the files.", + Metadata: metadataProto, + CreatedAt: timestamppb.Now(), + }, + }, + }) + return err + }, + // The structured logging test checks for the first log line. + // RecordToolUsage logs both tool_usage and model_thought entries. + expectedFields: map[string]any{ + "record_type": "tool_usage", + "interception_id": interceptionID.String(), + "tool": "bash", + }, + }, } for _, tc := range cases { @@ -1326,7 +1421,7 @@ func TestStructuredLogging(t *testing.T) { require.Empty(t, lines) } else { matchedLines := getLogLinesWithMessage(lines, aibridgedserver.InterceptionLogMarker) - require.Len(t, matchedLines, 1, "expected exactly one log line with message %q", aibridgedserver.InterceptionLogMarker) + require.NotEmpty(t, matchedLines, "expected at least one log line with message %q", aibridgedserver.InterceptionLogMarker) fields := matchedLines[0].Fields for key, expected := range tc.expectedFields { diff --git a/go.mod b/go.mod index 763dd1a037527..c85d0432a921d 100644 --- a/go.mod +++ b/go.mod @@ -639,3 +639,5 @@ replace github.com/anthropics/anthropic-sdk-go v1.19.0 => github.com/dannykoppin // https://github.com/openai/openai-go/pull/602 replace github.com/openai/openai-go/v3 => github.com/SasSwart/openai-go/v3 v3.0.0-20260204134041-fb987b42a728 + +replace github.com/coder/aibridge => /home/coder/aibridge diff --git a/go.sum b/go.sum index 1091f00e2c61e..25ce8dbb81d56 100644 --- a/go.sum +++ b/go.sum @@ -313,8 +313,6 @@ github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225 h1:tRIViZ5JRmzdOEo5wUWngaGEFBG8OaE1o2GIHN5ujJ8= github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225/go.mod h1:rNLVpYgEVeu1Zk29K64z6Od8RBP9DwqCu9OfCzh8MR4= -github.com/coder/aibridge v1.0.8-0.20260306121236-1e9e0d835d7a h1:SgaJ/U2aasuBwK0dFZJSVP5wXhWhoBHMYU4VlQcx4t0= -github.com/coder/aibridge v1.0.8-0.20260306121236-1e9e0d835d7a/go.mod h1:3BTl243k7OhpqtaITARAw647uC2V0YrxGOTQrkscnkk= github.com/coder/aisdk-go v0.0.9 h1:Vzo/k2qwVGLTR10ESDeP2Ecek1SdPfZlEjtTfMveiVo= github.com/coder/aisdk-go v0.0.9/go.mod h1:KF6/Vkono0FJJOtWtveh5j7yfNrSctVTpwgweYWSp5M= github.com/coder/boundary v0.8.4-0.20260304164748-566aeea939ab h1:HrlxyTmMQpOHfSKzRU1vf5TxrmV6vL5OiWq+Dvn5qh0= From 3b98dd50aa5277f45067e1e3fcedd2d8e180a630 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Fri, 6 Mar 2026 15:29:00 +0200 Subject: [PATCH 02/13] chore: fix migration number Signed-off-by: Danny Kopping --- ...odel_thoughts.up.sql => 000429_aibridge_model_thoughts.up.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/testdata/fixtures/{000428_aibridge_model_thoughts.up.sql => 000429_aibridge_model_thoughts.up.sql} (100%) diff --git a/coderd/database/migrations/testdata/fixtures/000428_aibridge_model_thoughts.up.sql b/coderd/database/migrations/testdata/fixtures/000429_aibridge_model_thoughts.up.sql similarity index 100% rename from coderd/database/migrations/testdata/fixtures/000428_aibridge_model_thoughts.up.sql rename to coderd/database/migrations/testdata/fixtures/000429_aibridge_model_thoughts.up.sql From 7cfe16cbbb92c8e06a3760550e8f8b3f4bd5bf87 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Fri, 6 Mar 2026 15:29:10 +0200 Subject: [PATCH 03/13] chore: update aibridge lib Signed-off-by: Danny Kopping --- go.mod | 4 +--- go.sum | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c85d0432a921d..713162c025cfd 100644 --- a/go.mod +++ b/go.mod @@ -485,7 +485,7 @@ require ( github.com/anthropics/anthropic-sdk-go v1.19.0 github.com/brianvoe/gofakeit/v7 v7.14.0 github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225 - github.com/coder/aibridge v1.0.8-0.20260306121236-1e9e0d835d7a + github.com/coder/aibridge v1.0.8-0.20260306145130-a0ad39219bad // TODO: update with merge commit. github.com/coder/aisdk-go v0.0.9 github.com/coder/boundary v0.8.4-0.20260304164748-566aeea939ab github.com/coder/preview v1.0.8 @@ -639,5 +639,3 @@ replace github.com/anthropics/anthropic-sdk-go v1.19.0 => github.com/dannykoppin // https://github.com/openai/openai-go/pull/602 replace github.com/openai/openai-go/v3 => github.com/SasSwart/openai-go/v3 v3.0.0-20260204134041-fb987b42a728 - -replace github.com/coder/aibridge => /home/coder/aibridge diff --git a/go.sum b/go.sum index 25ce8dbb81d56..c8b264dd6cec2 100644 --- a/go.sum +++ b/go.sum @@ -313,6 +313,8 @@ github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225 h1:tRIViZ5JRmzdOEo5wUWngaGEFBG8OaE1o2GIHN5ujJ8= github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225/go.mod h1:rNLVpYgEVeu1Zk29K64z6Od8RBP9DwqCu9OfCzh8MR4= +github.com/coder/aibridge v1.0.8-0.20260306145130-a0ad39219bad h1:juS2+u/GmcPa1We/hcKLluMIEXS+zx8hO2ptEpFl5O4= +github.com/coder/aibridge v1.0.8-0.20260306145130-a0ad39219bad/go.mod h1:3BTl243k7OhpqtaITARAw647uC2V0YrxGOTQrkscnkk= github.com/coder/aisdk-go v0.0.9 h1:Vzo/k2qwVGLTR10ESDeP2Ecek1SdPfZlEjtTfMveiVo= github.com/coder/aisdk-go v0.0.9/go.mod h1:KF6/Vkono0FJJOtWtveh5j7yfNrSctVTpwgweYWSp5M= github.com/coder/boundary v0.8.4-0.20260304164748-566aeea939ab h1:HrlxyTmMQpOHfSKzRU1vf5TxrmV6vL5OiWq+Dvn5qh0= From ebb8ea48eeed78ef8effe3aaa4ffa8d88db56cba Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Fri, 6 Mar 2026 15:29:18 +0200 Subject: [PATCH 04/13] chore: add missing dbauthz test Signed-off-by: Danny Kopping --- coderd/database/dbauthz/dbauthz_test.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 4a3bcf15f6b20..e9d3e19d2d561 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -5027,6 +5027,17 @@ func (s *MethodTestSuite) TestAIBridge() { check.Args(params).Asserts(intc, policy.ActionCreate) })) + s.Run("InsertAIBridgeModelThought", s.Mocked(func(db *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { + intID := uuid.UUID{2} + intc := testutil.Fake(s.T(), faker, database.AIBridgeInterception{ID: intID}) + db.EXPECT().GetAIBridgeInterceptionByID(gomock.Any(), intID).Return(intc, nil).AnyTimes() // Validation. + + params := database.InsertAIBridgeModelThoughtParams{InterceptionID: intc.ID} + expected := testutil.Fake(s.T(), faker, database.AIBridgeModelThought{InterceptionID: intc.ID}) + db.EXPECT().InsertAIBridgeModelThought(gomock.Any(), params).Return(expected, nil).AnyTimes() + check.Args(params).Asserts(intc, policy.ActionUpdate) + })) + s.Run("InsertAIBridgeTokenUsage", s.Mocked(func(db *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { intID := uuid.UUID{2} intc := testutil.Fake(s.T(), faker, database.AIBridgeInterception{ID: intID}) From 3ad80964c80614c2d680cbf98b3ffede445db0bf Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Fri, 6 Mar 2026 16:29:36 +0200 Subject: [PATCH 05/13] chore: fixes Signed-off-by: Danny Kopping --- coderd/database/dump.sql | 5 ++++- .../migrations/000429_aibridge_model_thoughts.up.sql | 2 +- coderd/database/models.go | 2 +- coderd/database/queries.sql.go | 2 +- coderd/database/unique_constraint.go | 1 + enterprise/aibridgedserver/aibridgedserver.go | 8 ++++++-- enterprise/aibridgedserver/aibridgedserver_test.go | 6 +++--- 7 files changed, 17 insertions(+), 9 deletions(-) diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index de94b29773c5b..056a3db86b8e9 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -1086,7 +1086,7 @@ COMMENT ON COLUMN aibridge_interceptions.thread_root_id IS 'The root interceptio COMMENT ON COLUMN aibridge_interceptions.client_session_id IS 'The session ID supplied by the client (optional and not universally supported).'; CREATE TABLE aibridge_model_thoughts ( - id uuid, + id uuid NOT NULL, interception_id uuid NOT NULL, tool_usage_id uuid NOT NULL, content text, @@ -3187,6 +3187,9 @@ ALTER TABLE ONLY ai_seat_state ALTER TABLE ONLY aibridge_interceptions ADD CONSTRAINT aibridge_interceptions_pkey PRIMARY KEY (id); +ALTER TABLE ONLY aibridge_model_thoughts + ADD CONSTRAINT aibridge_model_thoughts_pkey PRIMARY KEY (id); + ALTER TABLE ONLY aibridge_token_usages ADD CONSTRAINT aibridge_token_usages_pkey PRIMARY KEY (id); diff --git a/coderd/database/migrations/000429_aibridge_model_thoughts.up.sql b/coderd/database/migrations/000429_aibridge_model_thoughts.up.sql index fdca71236e5b1..7064f86b51fea 100644 --- a/coderd/database/migrations/000429_aibridge_model_thoughts.up.sql +++ b/coderd/database/migrations/000429_aibridge_model_thoughts.up.sql @@ -1,5 +1,5 @@ CREATE TABLE aibridge_model_thoughts ( - id UUID, + id UUID NOT NULL PRIMARY KEY, interception_id UUID NOT NULL, tool_usage_id UUID NOT NULL, content TEXT, diff --git a/coderd/database/models.go b/coderd/database/models.go index e007498faa045..3dda32a21bef4 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -3976,7 +3976,7 @@ type AIBridgeInterception struct { // Audit log of model thinking in intercepted requests in AI Bridge type AIBridgeModelThought struct { - ID uuid.NullUUID `db:"id" json:"id"` + ID uuid.UUID `db:"id" json:"id"` InterceptionID uuid.UUID `db:"interception_id" json:"interception_id"` ToolUsageID uuid.UUID `db:"tool_usage_id" json:"tool_usage_id"` Content sql.NullString `db:"content" json:"content"` diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 1d8e18817a097..46e096ff67397 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -677,7 +677,7 @@ RETURNING id, interception_id, tool_usage_id, content, metadata, created_at ` type InsertAIBridgeModelThoughtParams struct { - ID uuid.NullUUID `db:"id" json:"id"` + ID uuid.UUID `db:"id" json:"id"` InterceptionID uuid.UUID `db:"interception_id" json:"interception_id"` ToolUsageID uuid.UUID `db:"tool_usage_id" json:"tool_usage_id"` Content sql.NullString `db:"content" json:"content"` diff --git a/coderd/database/unique_constraint.go b/coderd/database/unique_constraint.go index 6066e4ea50eae..132b86777b233 100644 --- a/coderd/database/unique_constraint.go +++ b/coderd/database/unique_constraint.go @@ -9,6 +9,7 @@ const ( UniqueAgentStatsPkey UniqueConstraint = "agent_stats_pkey" // ALTER TABLE ONLY workspace_agent_stats ADD CONSTRAINT agent_stats_pkey PRIMARY KEY (id); UniqueAiSeatStatePkey UniqueConstraint = "ai_seat_state_pkey" // ALTER TABLE ONLY ai_seat_state ADD CONSTRAINT ai_seat_state_pkey PRIMARY KEY (user_id); UniqueAibridgeInterceptionsPkey UniqueConstraint = "aibridge_interceptions_pkey" // ALTER TABLE ONLY aibridge_interceptions ADD CONSTRAINT aibridge_interceptions_pkey PRIMARY KEY (id); + UniqueAibridgeModelThoughtsPkey UniqueConstraint = "aibridge_model_thoughts_pkey" // ALTER TABLE ONLY aibridge_model_thoughts ADD CONSTRAINT aibridge_model_thoughts_pkey PRIMARY KEY (id); UniqueAibridgeTokenUsagesPkey UniqueConstraint = "aibridge_token_usages_pkey" // ALTER TABLE ONLY aibridge_token_usages ADD CONSTRAINT aibridge_token_usages_pkey PRIMARY KEY (id); UniqueAibridgeToolUsagesPkey UniqueConstraint = "aibridge_tool_usages_pkey" // ALTER TABLE ONLY aibridge_tool_usages ADD CONSTRAINT aibridge_tool_usages_pkey PRIMARY KEY (id); UniqueAibridgeUserPromptsPkey UniqueConstraint = "aibridge_user_prompts_pkey" // ALTER TABLE ONLY aibridge_user_prompts ADD CONSTRAINT aibridge_user_prompts_pkey PRIMARY KEY (id); diff --git a/enterprise/aibridgedserver/aibridgedserver.go b/enterprise/aibridgedserver/aibridgedserver.go index c1df057822ba4..62985a0554ac5 100644 --- a/enterprise/aibridgedserver/aibridgedserver.go +++ b/enterprise/aibridgedserver/aibridgedserver.go @@ -379,7 +379,7 @@ func (s *Server) RecordToolUsage(ctx context.Context, in *proto.RecordToolUsageR } _, err = s.store.InsertAIBridgeModelThought(ctx, database.InsertAIBridgeModelThoughtParams{ - ID: uuid.NullUUID{UUID: uuid.New(), Valid: true}, + ID: uuid.New(), InterceptionID: intcID, ToolUsageID: toolUsageID, Content: sql.NullString{String: thought.GetContent(), Valid: thought.GetContent() != ""}, @@ -387,7 +387,11 @@ func (s *Server) RecordToolUsage(ctx context.Context, in *proto.RecordToolUsageR CreatedAt: thought.GetCreatedAt().AsTime(), }) if err != nil { - s.logger.Warn(ctx, "failed to insert model thought", slog.Error(err)) + s.logger.Warn(ctx, "failed to insert model thought", + slog.Error(err), + slog.F("interception_id", intcID.String()), + slog.F("tool_usage_id", toolUsageID.String()), + ) } } diff --git a/enterprise/aibridgedserver/aibridgedserver_test.go b/enterprise/aibridgedserver/aibridgedserver_test.go index d0262055d0c5e..004fdbc5ed6e6 100644 --- a/enterprise/aibridgedserver/aibridgedserver_test.go +++ b/enterprise/aibridgedserver/aibridgedserver_test.go @@ -1016,7 +1016,7 @@ func TestRecordToolUsage(t *testing.T) { }, nil) db.EXPECT().InsertAIBridgeModelThought(gomock.Any(), gomock.Cond(func(p database.InsertAIBridgeModelThoughtParams) bool { - if !assert.True(t, p.ID.Valid, "ID valid") || + if !assert.NotEqual(t, uuid.Nil, p.ID, "ID not nil") || !assert.Equal(t, interceptionID, p.InterceptionID, "interception ID") || !assert.Equal(t, toolUsageID, p.ToolUsageID, "tool usage ID") || !assert.Equal(t, sql.NullString{String: "I should list the files.", Valid: true}, p.Content, "content") || @@ -1025,7 +1025,7 @@ func TestRecordToolUsage(t *testing.T) { } return true })).Return(database.AIBridgeModelThought{ - ID: uuid.NullUUID{UUID: uuid.New(), Valid: true}, + ID: uuid.New(), InterceptionID: interceptionID, ToolUsageID: toolUsageID, Content: sql.NullString{String: "I should list the files.", Valid: true}, @@ -1358,7 +1358,7 @@ func TestStructuredLogging(t *testing.T) { Tool: "bash", }, nil) db.EXPECT().InsertAIBridgeModelThought(gomock.Any(), gomock.Any()).Return(database.AIBridgeModelThought{ - ID: uuid.NullUUID{UUID: uuid.New(), Valid: true}, + ID: uuid.New(), InterceptionID: intcID, }, nil) }, From df2ae956970157a29b385913960d47679ad50739 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Fri, 6 Mar 2026 16:34:10 +0200 Subject: [PATCH 06/13] chore: make gen Signed-off-by: Danny Kopping --- enterprise/aibridged/aibridgedmock/clientmock.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/enterprise/aibridged/aibridgedmock/clientmock.go b/enterprise/aibridged/aibridgedmock/clientmock.go index b5cf662c2973d..2bb7083e10924 100644 --- a/enterprise/aibridged/aibridgedmock/clientmock.go +++ b/enterprise/aibridged/aibridgedmock/clientmock.go @@ -3,7 +3,7 @@ // // Generated by this command: // -// mockgen -destination ./enterprise/aibridged/aibridgedmock/clientmock.go -package aibridgedmock github.com/coder/coder/v2/enterprise/aibridged DRPCClient +// mockgen -destination ./clientmock.go -package aibridgedmock github.com/coder/coder/v2/enterprise/aibridged DRPCClient // // Package aibridgedmock is a generated GoMock package. From ad95219a8b9b2be9cc83233e1cb7797a200b765a Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Fri, 6 Mar 2026 17:09:24 +0200 Subject: [PATCH 07/13] chore: check log output for specific line Signed-off-by: Danny Kopping --- enterprise/aibridgedserver/aibridgedserver_test.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/enterprise/aibridgedserver/aibridgedserver_test.go b/enterprise/aibridgedserver/aibridgedserver_test.go index 004fdbc5ed6e6..0bc3914a1fc30 100644 --- a/enterprise/aibridgedserver/aibridgedserver_test.go +++ b/enterprise/aibridgedserver/aibridgedserver_test.go @@ -1140,6 +1140,7 @@ func TestStructuredLogging(t *testing.T) { expectedErr error setupMocks func(db *dbmock.MockStore, interceptionID uuid.UUID) recordFn func(srv *aibridgedserver.Server, ctx context.Context, interceptionID uuid.UUID) error + expectedLineIdx int expectedFields map[string]any } @@ -1384,10 +1385,11 @@ func TestStructuredLogging(t *testing.T) { // The structured logging test checks for the first log line. // RecordToolUsage logs both tool_usage and model_thought entries. expectedFields: map[string]any{ - "record_type": "tool_usage", + "record_type": "model_thought", "interception_id": interceptionID.String(), - "tool": "bash", + "content": "I need to list the files.", }, + expectedLineIdx: 1, // "tool_usage" is also logged. }, } @@ -1421,9 +1423,9 @@ func TestStructuredLogging(t *testing.T) { require.Empty(t, lines) } else { matchedLines := getLogLinesWithMessage(lines, aibridgedserver.InterceptionLogMarker) - require.NotEmpty(t, matchedLines, "expected at least one log line with message %q", aibridgedserver.InterceptionLogMarker) + require.GreaterOrEqual(t, tc.expectedLineIdx+1, len(matchedLines), "expected at least %d log line with message %q", tc.expectedLineIdx+1, aibridgedserver.InterceptionLogMarker) - fields := matchedLines[0].Fields + fields := matchedLines[tc.expectedLineIdx].Fields for key, expected := range tc.expectedFields { require.Equal(t, expected, fields[key], "field %q mismatch", key) } From fb58504ba4323686fecde0c0860379df959b0338 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Wed, 11 Mar 2026 13:37:02 +0200 Subject: [PATCH 08/13] chore: fix migration numbering Signed-off-by: Danny Kopping --- ..._thoughts.down.sql => 000434_aibridge_model_thoughts.down.sql} | 0 ...odel_thoughts.up.sql => 000434_aibridge_model_thoughts.up.sql} | 0 ...odel_thoughts.up.sql => 000434_aibridge_model_thoughts.up.sql} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000429_aibridge_model_thoughts.down.sql => 000434_aibridge_model_thoughts.down.sql} (100%) rename coderd/database/migrations/{000429_aibridge_model_thoughts.up.sql => 000434_aibridge_model_thoughts.up.sql} (100%) rename coderd/database/migrations/testdata/fixtures/{000429_aibridge_model_thoughts.up.sql => 000434_aibridge_model_thoughts.up.sql} (100%) diff --git a/coderd/database/migrations/000429_aibridge_model_thoughts.down.sql b/coderd/database/migrations/000434_aibridge_model_thoughts.down.sql similarity index 100% rename from coderd/database/migrations/000429_aibridge_model_thoughts.down.sql rename to coderd/database/migrations/000434_aibridge_model_thoughts.down.sql diff --git a/coderd/database/migrations/000429_aibridge_model_thoughts.up.sql b/coderd/database/migrations/000434_aibridge_model_thoughts.up.sql similarity index 100% rename from coderd/database/migrations/000429_aibridge_model_thoughts.up.sql rename to coderd/database/migrations/000434_aibridge_model_thoughts.up.sql diff --git a/coderd/database/migrations/testdata/fixtures/000429_aibridge_model_thoughts.up.sql b/coderd/database/migrations/testdata/fixtures/000434_aibridge_model_thoughts.up.sql similarity index 100% rename from coderd/database/migrations/testdata/fixtures/000429_aibridge_model_thoughts.up.sql rename to coderd/database/migrations/testdata/fixtures/000434_aibridge_model_thoughts.up.sql From 7ae722e3f9944b542808b0e744ee5d48a1c762dd Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Thu, 12 Mar 2026 14:43:07 +0200 Subject: [PATCH 09/13] chore: break association between thoughts and tools Signed-off-by: Danny Kopping --- coderd/database/dump.sql | 3 +- .../000434_aibridge_model_thoughts.up.sql | 3 +- .../000434_aibridge_model_thoughts.up.sql | 4 +- coderd/database/models.go | 3 +- coderd/database/queries.sql.go | 11 +- coderd/database/queries/aibridge.sql | 4 +- docs/ai-coder/ai-bridge/monitoring.md | 2 +- docs/ai-coder/ai-bridge/setup.md | 2 +- enterprise/aibridged/proto/aibridged.pb.go | 506 ++++++++++-------- enterprise/aibridged/proto/aibridged.proto | 14 +- .../aibridged/proto/aibridged_drpc.pb.go | 42 +- enterprise/aibridged/translator.go | 20 +- enterprise/aibridgedserver/aibridgedserver.go | 72 +-- .../aibridgedserver/aibridgedserver_test.go | 105 ++-- go.mod | 4 +- go.sum | 8 +- 16 files changed, 447 insertions(+), 356 deletions(-) diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 056a3db86b8e9..f919a29cb8fff 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -1088,8 +1088,7 @@ COMMENT ON COLUMN aibridge_interceptions.client_session_id IS 'The session ID su CREATE TABLE aibridge_model_thoughts ( id uuid NOT NULL, interception_id uuid NOT NULL, - tool_usage_id uuid NOT NULL, - content text, + content text NOT NULL, metadata jsonb, created_at timestamp with time zone NOT NULL ); diff --git a/coderd/database/migrations/000434_aibridge_model_thoughts.up.sql b/coderd/database/migrations/000434_aibridge_model_thoughts.up.sql index 7064f86b51fea..f9ed85b992559 100644 --- a/coderd/database/migrations/000434_aibridge_model_thoughts.up.sql +++ b/coderd/database/migrations/000434_aibridge_model_thoughts.up.sql @@ -1,8 +1,7 @@ CREATE TABLE aibridge_model_thoughts ( id UUID NOT NULL PRIMARY KEY, interception_id UUID NOT NULL, - tool_usage_id UUID NOT NULL, - content TEXT, + content TEXT NOT NULL, metadata jsonb, created_at TIMESTAMPTZ NOT NULL ); diff --git a/coderd/database/migrations/testdata/fixtures/000434_aibridge_model_thoughts.up.sql b/coderd/database/migrations/testdata/fixtures/000434_aibridge_model_thoughts.up.sql index 7579b41ea354d..4dac0fcde1270 100644 --- a/coderd/database/migrations/testdata/fixtures/000434_aibridge_model_thoughts.up.sql +++ b/coderd/database/migrations/testdata/fixtures/000434_aibridge_model_thoughts.up.sql @@ -2,7 +2,6 @@ INSERT INTO aibridge_model_thoughts ( id, interception_id, - tool_usage_id, content, metadata, created_at @@ -10,8 +9,7 @@ INSERT INTO VALUES ( 'a1b2c3d4-e5f6-7890-abcd-ef1234567890', 'be003e1e-b38f-43bf-847d-928074dd0aa8', -- from 000370_aibridge.up.sql - '613b4cfa-a257-4e88-99e6-4d2e99ea25f0', -- from 000370_aibridge.up.sql (tool usage) 'The user is asking about their workspaces. I should use the coder_list_workspaces tool to retrieve this information.', - '{"thinking_tokens": 42}', + '{"source": "commentary"}', '2025-09-15 12:45:19.123456+00' ); diff --git a/coderd/database/models.go b/coderd/database/models.go index 3dda32a21bef4..478fdc02d66b3 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -3978,8 +3978,7 @@ type AIBridgeInterception struct { type AIBridgeModelThought struct { ID uuid.UUID `db:"id" json:"id"` InterceptionID uuid.UUID `db:"interception_id" json:"interception_id"` - ToolUsageID uuid.UUID `db:"tool_usage_id" json:"tool_usage_id"` - Content sql.NullString `db:"content" json:"content"` + Content string `db:"content" json:"content"` Metadata pqtype.NullRawMessage `db:"metadata" json:"metadata"` CreatedAt time.Time `db:"created_at" json:"created_at"` } diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 46e096ff67397..f67fae058de76 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -669,18 +669,17 @@ func (q *sqlQuerier) InsertAIBridgeInterception(ctx context.Context, arg InsertA const insertAIBridgeModelThought = `-- name: InsertAIBridgeModelThought :one INSERT INTO aibridge_model_thoughts ( - id, interception_id, tool_usage_id, content, metadata, created_at + id, interception_id, content, metadata, created_at ) VALUES ( - $1, $2, $3, $4, COALESCE($5::jsonb, '{}'::jsonb), $6 + $1, $2, $3, COALESCE($4::jsonb, '{}'::jsonb), $5 ) -RETURNING id, interception_id, tool_usage_id, content, metadata, created_at +RETURNING id, interception_id, content, metadata, created_at ` type InsertAIBridgeModelThoughtParams struct { ID uuid.UUID `db:"id" json:"id"` InterceptionID uuid.UUID `db:"interception_id" json:"interception_id"` - ToolUsageID uuid.UUID `db:"tool_usage_id" json:"tool_usage_id"` - Content sql.NullString `db:"content" json:"content"` + Content string `db:"content" json:"content"` Metadata json.RawMessage `db:"metadata" json:"metadata"` CreatedAt time.Time `db:"created_at" json:"created_at"` } @@ -689,7 +688,6 @@ func (q *sqlQuerier) InsertAIBridgeModelThought(ctx context.Context, arg InsertA row := q.db.QueryRowContext(ctx, insertAIBridgeModelThought, arg.ID, arg.InterceptionID, - arg.ToolUsageID, arg.Content, arg.Metadata, arg.CreatedAt, @@ -698,7 +696,6 @@ func (q *sqlQuerier) InsertAIBridgeModelThought(ctx context.Context, arg InsertA err := row.Scan( &i.ID, &i.InterceptionID, - &i.ToolUsageID, &i.Content, &i.Metadata, &i.CreatedAt, diff --git a/coderd/database/queries/aibridge.sql b/coderd/database/queries/aibridge.sql index 3ea05fc8c6ee2..52204ee8bc0e0 100644 --- a/coderd/database/queries/aibridge.sql +++ b/coderd/database/queries/aibridge.sql @@ -55,9 +55,9 @@ RETURNING *; -- name: InsertAIBridgeModelThought :one INSERT INTO aibridge_model_thoughts ( - id, interception_id, tool_usage_id, content, metadata, created_at + id, interception_id, content, metadata, created_at ) VALUES ( - @id, @interception_id, @tool_usage_id, @content, COALESCE(@metadata::jsonb, '{}'::jsonb), @created_at + @id, @interception_id, @content, COALESCE(@metadata::jsonb, '{}'::jsonb), @created_at ) RETURNING *; diff --git a/docs/ai-coder/ai-bridge/monitoring.md b/docs/ai-coder/ai-bridge/monitoring.md index 7a4ffda22f97f..f214eeb8a0473 100644 --- a/docs/ai-coder/ai-bridge/monitoring.md +++ b/docs/ai-coder/ai-bridge/monitoring.md @@ -1,6 +1,6 @@ # Monitoring -AI Bridge records the last `user` prompt, token usage, and every tool invocation for each intercepted request. Each capture is tied to a single "interception" that maps back to the authenticated Coder identity, making it easy to attribute spend and behaviour. +AI Bridge records the last `user` prompt, token usage, model reasoning, and every tool invocation for each intercepted request. Each capture is tied to a single "interception" that maps back to the authenticated Coder identity, making it easy to attribute spend and behaviour. ![User Prompt logging](../../images/aibridge/grafana_user_prompts_logging.png) diff --git a/docs/ai-coder/ai-bridge/setup.md b/docs/ai-coder/ai-bridge/setup.md index 5232331926328..50b6a4f86c0e8 100644 --- a/docs/ai-coder/ai-bridge/setup.md +++ b/docs/ai-coder/ai-bridge/setup.md @@ -103,7 +103,7 @@ AI Bridge can relay traffic to other OpenAI- or Anthropic-compatible services or ## Data Retention -AI Bridge records prompts, token usage, and tool invocations for auditing and +AI Bridge records prompts, token usage, tool invocations, and model reasoning for auditing and monitoring purposes. By default, this data is retained for **60 days**. Configure retention using `--aibridge-retention` or `CODER_AIBRIDGE_RETENTION`: diff --git a/enterprise/aibridged/proto/aibridged.pb.go b/enterprise/aibridged/proto/aibridged.pb.go index 20fe3e6523806..f75955c3bba26 100644 --- a/enterprise/aibridged/proto/aibridged.pb.go +++ b/enterprise/aibridged/proto/aibridged.pb.go @@ -536,8 +536,7 @@ type RecordToolUsageRequest struct { InvocationError *string `protobuf:"bytes,7,opt,name=invocation_error,json=invocationError,proto3,oneof" json:"invocation_error,omitempty"` // Only injected tools are invoked. Metadata map[string]*anypb.Any `protobuf:"bytes,8,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` CreatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` - ToolCallId string `protobuf:"bytes,10,opt,name=tool_call_id,json=toolCallId,proto3" json:"tool_call_id,omitempty"` // The ID of the tool call provided by the AI provider. - ModelThoughts []*ModelThought `protobuf:"bytes,11,rep,name=model_thoughts,json=modelThoughts,proto3" json:"model_thoughts,omitempty"` // Model thinking associated with this tool call. + ToolCallId string `protobuf:"bytes,10,opt,name=tool_call_id,json=toolCallId,proto3" json:"tool_call_id,omitempty"` // The ID of the tool call provided by the AI provider. } func (x *RecordToolUsageRequest) Reset() { @@ -642,13 +641,6 @@ func (x *RecordToolUsageRequest) GetToolCallId() string { return "" } -func (x *RecordToolUsageRequest) GetModelThoughts() []*ModelThought { - if x != nil { - return x.ModelThoughts - } - return nil -} - type RecordToolUsageResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -687,20 +679,19 @@ func (*RecordToolUsageResponse) Descriptor() ([]byte, []int) { return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{9} } -// ModelThought represents a model's thinking/reasoning associated with -// a tool call. -type ModelThought struct { +type RecordModelThoughtRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Content string `protobuf:"bytes,1,opt,name=content,proto3" json:"content,omitempty"` - Metadata map[string]*anypb.Any `protobuf:"bytes,2,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - CreatedAt *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` + InterceptionId string `protobuf:"bytes,1,opt,name=interception_id,json=interceptionId,proto3" json:"interception_id,omitempty"` // UUID. + Content string `protobuf:"bytes,2,opt,name=content,proto3" json:"content,omitempty"` + Metadata map[string]*anypb.Any `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + CreatedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=created_at,json=createdAt,proto3" json:"created_at,omitempty"` } -func (x *ModelThought) Reset() { - *x = ModelThought{} +func (x *RecordModelThoughtRequest) Reset() { + *x = RecordModelThoughtRequest{} if protoimpl.UnsafeEnabled { mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -708,13 +699,13 @@ func (x *ModelThought) Reset() { } } -func (x *ModelThought) String() string { +func (x *RecordModelThoughtRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ModelThought) ProtoMessage() {} +func (*RecordModelThoughtRequest) ProtoMessage() {} -func (x *ModelThought) ProtoReflect() protoreflect.Message { +func (x *RecordModelThoughtRequest) ProtoReflect() protoreflect.Message { mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -726,32 +717,77 @@ func (x *ModelThought) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ModelThought.ProtoReflect.Descriptor instead. -func (*ModelThought) Descriptor() ([]byte, []int) { +// Deprecated: Use RecordModelThoughtRequest.ProtoReflect.Descriptor instead. +func (*RecordModelThoughtRequest) Descriptor() ([]byte, []int) { return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{10} } -func (x *ModelThought) GetContent() string { +func (x *RecordModelThoughtRequest) GetInterceptionId() string { + if x != nil { + return x.InterceptionId + } + return "" +} + +func (x *RecordModelThoughtRequest) GetContent() string { if x != nil { return x.Content } return "" } -func (x *ModelThought) GetMetadata() map[string]*anypb.Any { +func (x *RecordModelThoughtRequest) GetMetadata() map[string]*anypb.Any { if x != nil { return x.Metadata } return nil } -func (x *ModelThought) GetCreatedAt() *timestamppb.Timestamp { +func (x *RecordModelThoughtRequest) GetCreatedAt() *timestamppb.Timestamp { if x != nil { return x.CreatedAt } return nil } +type RecordModelThoughtResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *RecordModelThoughtResponse) Reset() { + *x = RecordModelThoughtResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RecordModelThoughtResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RecordModelThoughtResponse) ProtoMessage() {} + +func (x *RecordModelThoughtResponse) ProtoReflect() protoreflect.Message { + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RecordModelThoughtResponse.ProtoReflect.Descriptor instead. +func (*RecordModelThoughtResponse) Descriptor() ([]byte, []int) { + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{11} +} + type GetMCPServerConfigsRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -763,7 +799,7 @@ type GetMCPServerConfigsRequest struct { func (x *GetMCPServerConfigsRequest) Reset() { *x = GetMCPServerConfigsRequest{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[11] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -776,7 +812,7 @@ func (x *GetMCPServerConfigsRequest) String() string { func (*GetMCPServerConfigsRequest) ProtoMessage() {} func (x *GetMCPServerConfigsRequest) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[11] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -789,7 +825,7 @@ func (x *GetMCPServerConfigsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMCPServerConfigsRequest.ProtoReflect.Descriptor instead. func (*GetMCPServerConfigsRequest) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{11} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{12} } func (x *GetMCPServerConfigsRequest) GetUserId() string { @@ -811,7 +847,7 @@ type GetMCPServerConfigsResponse struct { func (x *GetMCPServerConfigsResponse) Reset() { *x = GetMCPServerConfigsResponse{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[12] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -824,7 +860,7 @@ func (x *GetMCPServerConfigsResponse) String() string { func (*GetMCPServerConfigsResponse) ProtoMessage() {} func (x *GetMCPServerConfigsResponse) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[12] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -837,7 +873,7 @@ func (x *GetMCPServerConfigsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetMCPServerConfigsResponse.ProtoReflect.Descriptor instead. func (*GetMCPServerConfigsResponse) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{12} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{13} } func (x *GetMCPServerConfigsResponse) GetCoderMcpConfig() *MCPServerConfig { @@ -868,7 +904,7 @@ type MCPServerConfig struct { func (x *MCPServerConfig) Reset() { *x = MCPServerConfig{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[13] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -881,7 +917,7 @@ func (x *MCPServerConfig) String() string { func (*MCPServerConfig) ProtoMessage() {} func (x *MCPServerConfig) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[13] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -894,7 +930,7 @@ func (x *MCPServerConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use MCPServerConfig.ProtoReflect.Descriptor instead. func (*MCPServerConfig) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{13} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{14} } func (x *MCPServerConfig) GetId() string { @@ -937,7 +973,7 @@ type GetMCPServerAccessTokensBatchRequest struct { func (x *GetMCPServerAccessTokensBatchRequest) Reset() { *x = GetMCPServerAccessTokensBatchRequest{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[14] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -950,7 +986,7 @@ func (x *GetMCPServerAccessTokensBatchRequest) String() string { func (*GetMCPServerAccessTokensBatchRequest) ProtoMessage() {} func (x *GetMCPServerAccessTokensBatchRequest) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[14] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -963,7 +999,7 @@ func (x *GetMCPServerAccessTokensBatchRequest) ProtoReflect() protoreflect.Messa // Deprecated: Use GetMCPServerAccessTokensBatchRequest.ProtoReflect.Descriptor instead. func (*GetMCPServerAccessTokensBatchRequest) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{14} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{15} } func (x *GetMCPServerAccessTokensBatchRequest) GetUserId() string { @@ -994,7 +1030,7 @@ type GetMCPServerAccessTokensBatchResponse struct { func (x *GetMCPServerAccessTokensBatchResponse) Reset() { *x = GetMCPServerAccessTokensBatchResponse{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[15] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1007,7 +1043,7 @@ func (x *GetMCPServerAccessTokensBatchResponse) String() string { func (*GetMCPServerAccessTokensBatchResponse) ProtoMessage() {} func (x *GetMCPServerAccessTokensBatchResponse) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[15] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1020,7 +1056,7 @@ func (x *GetMCPServerAccessTokensBatchResponse) ProtoReflect() protoreflect.Mess // Deprecated: Use GetMCPServerAccessTokensBatchResponse.ProtoReflect.Descriptor instead. func (*GetMCPServerAccessTokensBatchResponse) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{15} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{16} } func (x *GetMCPServerAccessTokensBatchResponse) GetAccessTokens() map[string]string { @@ -1048,7 +1084,7 @@ type IsAuthorizedRequest struct { func (x *IsAuthorizedRequest) Reset() { *x = IsAuthorizedRequest{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[16] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1061,7 +1097,7 @@ func (x *IsAuthorizedRequest) String() string { func (*IsAuthorizedRequest) ProtoMessage() {} func (x *IsAuthorizedRequest) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[16] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1074,7 +1110,7 @@ func (x *IsAuthorizedRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use IsAuthorizedRequest.ProtoReflect.Descriptor instead. func (*IsAuthorizedRequest) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{16} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{17} } func (x *IsAuthorizedRequest) GetKey() string { @@ -1097,7 +1133,7 @@ type IsAuthorizedResponse struct { func (x *IsAuthorizedResponse) Reset() { *x = IsAuthorizedResponse{} if protoimpl.UnsafeEnabled { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[17] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1110,7 +1146,7 @@ func (x *IsAuthorizedResponse) String() string { func (*IsAuthorizedResponse) ProtoMessage() {} func (x *IsAuthorizedResponse) ProtoReflect() protoreflect.Message { - mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[17] + mi := &file_enterprise_aibridged_proto_aibridged_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1123,7 +1159,7 @@ func (x *IsAuthorizedResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use IsAuthorizedResponse.ProtoReflect.Descriptor instead. func (*IsAuthorizedResponse) Descriptor() ([]byte, []int) { - return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{17} + return file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP(), []int{18} } func (x *IsAuthorizedResponse) GetOwnerId() string { @@ -1253,7 +1289,7 @@ var file_enterprise_aibridged_proto_aibridged_proto_rawDesc = []byte{ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1b, 0x0a, 0x19, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0xcb, 0x04, 0x0a, 0x16, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, + 0x22, 0x8f, 0x04, 0x0a, 0x16, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, @@ -1278,126 +1314,134 @@ var file_enterprise_aibridged_proto_aibridged_proto_rawDesc = []byte{ 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0a, 0x74, 0x6f, 0x6f, 0x6c, 0x43, 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x12, 0x3a, 0x0a, 0x0e, 0x6d, - 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x74, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x73, 0x18, 0x0b, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x6f, 0x64, 0x65, - 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x54, - 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x73, 0x1a, 0x51, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, - 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, 0x0a, 0x0b, 0x5f, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x13, 0x0a, 0x11, 0x5f, 0x69, 0x6e, - 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x19, - 0x0a, 0x17, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, - 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xf5, 0x01, 0x0a, 0x0c, 0x4d, 0x6f, - 0x64, 0x65, 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x12, 0x3d, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, - 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, - 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0x51, - 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, - 0x01, 0x22, 0x35, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, - 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0xb2, 0x01, 0x0a, 0x1b, 0x47, 0x65, 0x74, - 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x10, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x5f, 0x6d, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, + 0x0a, 0x74, 0x6f, 0x6f, 0x6c, 0x43, 0x61, 0x6c, 0x6c, 0x49, 0x64, 0x1a, 0x51, 0x0a, 0x0d, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x0d, + 0x0a, 0x0b, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x42, 0x13, 0x0a, + 0x11, 0x5f, 0x69, 0x6e, 0x76, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x22, 0x19, 0x0a, 0x17, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, + 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb8, 0x02, + 0x0a, 0x19, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x68, 0x6f, + 0x75, 0x67, 0x68, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x4a, + 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4d, + 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x39, 0x0a, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x41, 0x74, 0x1a, 0x51, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x1c, 0x0a, 0x1a, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x0a, 0x1a, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0xb2, 0x01, + 0x0a, 0x1b, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, + 0x10, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x6d, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, + 0x0e, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x4d, 0x63, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, + 0x51, 0x0a, 0x19, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, + 0x5f, 0x6d, 0x63, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x43, 0x50, 0x53, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x4d, 0x63, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x51, 0x0a, 0x19, 0x65, 0x78, - 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x6d, 0x63, 0x70, 0x5f, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x16, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, - 0x75, 0x74, 0x68, 0x4d, 0x63, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x22, 0x85, 0x01, - 0x0a, 0x0f, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x75, 0x72, 0x6c, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, - 0x77, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x74, - 0x6f, 0x6f, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, 0x65, 0x78, 0x12, 0x26, 0x0a, - 0x0f, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x64, 0x65, 0x6e, 0x79, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x6f, 0x6f, 0x6c, 0x44, 0x65, 0x6e, 0x79, - 0x52, 0x65, 0x67, 0x65, 0x78, 0x22, 0x72, 0x0a, 0x24, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, - 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, - 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x6d, 0x63, 0x70, 0x5f, 0x73, 0x65, - 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x69, 0x64, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x6d, 0x63, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x73, 0x22, 0xda, 0x02, 0x0a, 0x25, 0x47, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x16, 0x65, 0x78, 0x74, 0x65, + 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x4d, 0x63, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x0f, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x6f, 0x6c, + 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0e, 0x74, 0x6f, 0x6f, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x77, 0x52, 0x65, 0x67, + 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0f, 0x74, 0x6f, 0x6f, 0x6c, 0x5f, 0x64, 0x65, 0x6e, 0x79, 0x5f, + 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x74, 0x6f, 0x6f, + 0x6c, 0x44, 0x65, 0x6e, 0x79, 0x52, 0x65, 0x67, 0x65, 0x78, 0x22, 0x72, 0x0a, 0x24, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, + 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x31, 0x0a, 0x15, 0x6d, + 0x63, 0x70, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x6d, 0x63, 0x70, 0x53, + 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x49, 0x64, 0x73, 0x22, 0xda, + 0x02, 0x0a, 0x25, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, - 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x50, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, - 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x1a, 0x3f, 0x0a, 0x11, 0x41, 0x63, - 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x63, 0x0a, 0x0d, 0x61, 0x63, 0x63, 0x65, + 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x3e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, + 0x72, 0x76, 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, + 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x41, 0x63, + 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x0c, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x50, 0x0a, + 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x38, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x1a, + 0x3f, 0x0a, 0x11, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x1a, 0x39, 0x0a, 0x0b, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x39, 0x0a, 0x0b, 0x45, - 0x72, 0x72, 0x6f, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x27, 0x0a, 0x13, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, - 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x22, - 0x6b, 0x0a, 0x14, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x77, 0x6e, 0x65, 0x72, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x77, 0x6e, 0x65, 0x72, - 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x69, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x70, 0x69, 0x4b, 0x65, 0x79, 0x49, 0x64, - 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x32, 0xce, 0x03, 0x0a, - 0x08, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x59, 0x0a, 0x12, 0x52, 0x65, 0x63, - 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, - 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x17, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x12, - 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, - 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x27, 0x0a, 0x13, 0x49, + 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x22, 0x6b, 0x0a, 0x14, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, + 0x69, 0x7a, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1c, 0x0a, 0x0a, 0x61, 0x70, 0x69, 0x5f, 0x6b, + 0x65, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x61, 0x70, 0x69, + 0x4b, 0x65, 0x79, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x32, 0xa9, 0x04, 0x0a, 0x08, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x59, + 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, - 0x0a, 0x10, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, - 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, - 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, - 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x50, 0x0a, 0x0f, 0x52, - 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1d, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, - 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, - 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xeb, 0x01, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x68, 0x0a, 0x17, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, + 0x6e, 0x64, 0x65, 0x64, 0x12, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, + 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, + 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x26, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x63, + 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x53, 0x0a, 0x10, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, + 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x55, 0x73, 0x61, 0x67, 0x65, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x56, 0x0a, 0x11, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, 0x6d, + 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x50, 0x72, 0x6f, + 0x6d, 0x70, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x50, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, + 0x72, 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, + 0x64, 0x54, 0x6f, 0x6f, 0x6c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x59, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4d, 0x6f, 0x64, 0x65, + 0x6c, 0x54, 0x68, 0x6f, 0x75, 0x67, 0x68, 0x74, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x68, 0x6f, 0x75, + 0x67, 0x68, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4d, 0x6f, 0x64, 0x65, 0x6c, 0x54, 0x68, + 0x6f, 0x75, 0x67, 0x68, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0xeb, 0x01, 0x0a, 0x0f, 0x4d, 0x43, 0x50, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x12, 0x5c, 0x0a, 0x13, 0x47, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, @@ -1436,7 +1480,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_rawDescGZIP() []byte { return file_enterprise_aibridged_proto_aibridged_proto_rawDescData } -var file_enterprise_aibridged_proto_aibridged_proto_msgTypes = make([]protoimpl.MessageInfo, 25) +var file_enterprise_aibridged_proto_aibridged_proto_msgTypes = make([]protoimpl.MessageInfo, 26) var file_enterprise_aibridged_proto_aibridged_proto_goTypes = []interface{}{ (*RecordInterceptionRequest)(nil), // 0: proto.RecordInterceptionRequest (*RecordInterceptionResponse)(nil), // 1: proto.RecordInterceptionResponse @@ -1448,67 +1492,69 @@ var file_enterprise_aibridged_proto_aibridged_proto_goTypes = []interface{}{ (*RecordPromptUsageResponse)(nil), // 7: proto.RecordPromptUsageResponse (*RecordToolUsageRequest)(nil), // 8: proto.RecordToolUsageRequest (*RecordToolUsageResponse)(nil), // 9: proto.RecordToolUsageResponse - (*ModelThought)(nil), // 10: proto.ModelThought - (*GetMCPServerConfigsRequest)(nil), // 11: proto.GetMCPServerConfigsRequest - (*GetMCPServerConfigsResponse)(nil), // 12: proto.GetMCPServerConfigsResponse - (*MCPServerConfig)(nil), // 13: proto.MCPServerConfig - (*GetMCPServerAccessTokensBatchRequest)(nil), // 14: proto.GetMCPServerAccessTokensBatchRequest - (*GetMCPServerAccessTokensBatchResponse)(nil), // 15: proto.GetMCPServerAccessTokensBatchResponse - (*IsAuthorizedRequest)(nil), // 16: proto.IsAuthorizedRequest - (*IsAuthorizedResponse)(nil), // 17: proto.IsAuthorizedResponse - nil, // 18: proto.RecordInterceptionRequest.MetadataEntry - nil, // 19: proto.RecordTokenUsageRequest.MetadataEntry - nil, // 20: proto.RecordPromptUsageRequest.MetadataEntry - nil, // 21: proto.RecordToolUsageRequest.MetadataEntry - nil, // 22: proto.ModelThought.MetadataEntry - nil, // 23: proto.GetMCPServerAccessTokensBatchResponse.AccessTokensEntry - nil, // 24: proto.GetMCPServerAccessTokensBatchResponse.ErrorsEntry - (*timestamppb.Timestamp)(nil), // 25: google.protobuf.Timestamp - (*anypb.Any)(nil), // 26: google.protobuf.Any + (*RecordModelThoughtRequest)(nil), // 10: proto.RecordModelThoughtRequest + (*RecordModelThoughtResponse)(nil), // 11: proto.RecordModelThoughtResponse + (*GetMCPServerConfigsRequest)(nil), // 12: proto.GetMCPServerConfigsRequest + (*GetMCPServerConfigsResponse)(nil), // 13: proto.GetMCPServerConfigsResponse + (*MCPServerConfig)(nil), // 14: proto.MCPServerConfig + (*GetMCPServerAccessTokensBatchRequest)(nil), // 15: proto.GetMCPServerAccessTokensBatchRequest + (*GetMCPServerAccessTokensBatchResponse)(nil), // 16: proto.GetMCPServerAccessTokensBatchResponse + (*IsAuthorizedRequest)(nil), // 17: proto.IsAuthorizedRequest + (*IsAuthorizedResponse)(nil), // 18: proto.IsAuthorizedResponse + nil, // 19: proto.RecordInterceptionRequest.MetadataEntry + nil, // 20: proto.RecordTokenUsageRequest.MetadataEntry + nil, // 21: proto.RecordPromptUsageRequest.MetadataEntry + nil, // 22: proto.RecordToolUsageRequest.MetadataEntry + nil, // 23: proto.RecordModelThoughtRequest.MetadataEntry + nil, // 24: proto.GetMCPServerAccessTokensBatchResponse.AccessTokensEntry + nil, // 25: proto.GetMCPServerAccessTokensBatchResponse.ErrorsEntry + (*timestamppb.Timestamp)(nil), // 26: google.protobuf.Timestamp + (*anypb.Any)(nil), // 27: google.protobuf.Any } var file_enterprise_aibridged_proto_aibridged_proto_depIdxs = []int32{ - 18, // 0: proto.RecordInterceptionRequest.metadata:type_name -> proto.RecordInterceptionRequest.MetadataEntry - 25, // 1: proto.RecordInterceptionRequest.started_at:type_name -> google.protobuf.Timestamp - 25, // 2: proto.RecordInterceptionEndedRequest.ended_at:type_name -> google.protobuf.Timestamp - 19, // 3: proto.RecordTokenUsageRequest.metadata:type_name -> proto.RecordTokenUsageRequest.MetadataEntry - 25, // 4: proto.RecordTokenUsageRequest.created_at:type_name -> google.protobuf.Timestamp - 20, // 5: proto.RecordPromptUsageRequest.metadata:type_name -> proto.RecordPromptUsageRequest.MetadataEntry - 25, // 6: proto.RecordPromptUsageRequest.created_at:type_name -> google.protobuf.Timestamp - 21, // 7: proto.RecordToolUsageRequest.metadata:type_name -> proto.RecordToolUsageRequest.MetadataEntry - 25, // 8: proto.RecordToolUsageRequest.created_at:type_name -> google.protobuf.Timestamp - 10, // 9: proto.RecordToolUsageRequest.model_thoughts:type_name -> proto.ModelThought - 22, // 10: proto.ModelThought.metadata:type_name -> proto.ModelThought.MetadataEntry - 25, // 11: proto.ModelThought.created_at:type_name -> google.protobuf.Timestamp - 13, // 12: proto.GetMCPServerConfigsResponse.coder_mcp_config:type_name -> proto.MCPServerConfig - 13, // 13: proto.GetMCPServerConfigsResponse.external_auth_mcp_configs:type_name -> proto.MCPServerConfig - 23, // 14: proto.GetMCPServerAccessTokensBatchResponse.access_tokens:type_name -> proto.GetMCPServerAccessTokensBatchResponse.AccessTokensEntry - 24, // 15: proto.GetMCPServerAccessTokensBatchResponse.errors:type_name -> proto.GetMCPServerAccessTokensBatchResponse.ErrorsEntry - 26, // 16: proto.RecordInterceptionRequest.MetadataEntry.value:type_name -> google.protobuf.Any - 26, // 17: proto.RecordTokenUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any - 26, // 18: proto.RecordPromptUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any - 26, // 19: proto.RecordToolUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any - 26, // 20: proto.ModelThought.MetadataEntry.value:type_name -> google.protobuf.Any - 0, // 21: proto.Recorder.RecordInterception:input_type -> proto.RecordInterceptionRequest - 2, // 22: proto.Recorder.RecordInterceptionEnded:input_type -> proto.RecordInterceptionEndedRequest - 4, // 23: proto.Recorder.RecordTokenUsage:input_type -> proto.RecordTokenUsageRequest - 6, // 24: proto.Recorder.RecordPromptUsage:input_type -> proto.RecordPromptUsageRequest - 8, // 25: proto.Recorder.RecordToolUsage:input_type -> proto.RecordToolUsageRequest - 11, // 26: proto.MCPConfigurator.GetMCPServerConfigs:input_type -> proto.GetMCPServerConfigsRequest - 14, // 27: proto.MCPConfigurator.GetMCPServerAccessTokensBatch:input_type -> proto.GetMCPServerAccessTokensBatchRequest - 16, // 28: proto.Authorizer.IsAuthorized:input_type -> proto.IsAuthorizedRequest + 19, // 0: proto.RecordInterceptionRequest.metadata:type_name -> proto.RecordInterceptionRequest.MetadataEntry + 26, // 1: proto.RecordInterceptionRequest.started_at:type_name -> google.protobuf.Timestamp + 26, // 2: proto.RecordInterceptionEndedRequest.ended_at:type_name -> google.protobuf.Timestamp + 20, // 3: proto.RecordTokenUsageRequest.metadata:type_name -> proto.RecordTokenUsageRequest.MetadataEntry + 26, // 4: proto.RecordTokenUsageRequest.created_at:type_name -> google.protobuf.Timestamp + 21, // 5: proto.RecordPromptUsageRequest.metadata:type_name -> proto.RecordPromptUsageRequest.MetadataEntry + 26, // 6: proto.RecordPromptUsageRequest.created_at:type_name -> google.protobuf.Timestamp + 22, // 7: proto.RecordToolUsageRequest.metadata:type_name -> proto.RecordToolUsageRequest.MetadataEntry + 26, // 8: proto.RecordToolUsageRequest.created_at:type_name -> google.protobuf.Timestamp + 23, // 9: proto.RecordModelThoughtRequest.metadata:type_name -> proto.RecordModelThoughtRequest.MetadataEntry + 26, // 10: proto.RecordModelThoughtRequest.created_at:type_name -> google.protobuf.Timestamp + 14, // 11: proto.GetMCPServerConfigsResponse.coder_mcp_config:type_name -> proto.MCPServerConfig + 14, // 12: proto.GetMCPServerConfigsResponse.external_auth_mcp_configs:type_name -> proto.MCPServerConfig + 24, // 13: proto.GetMCPServerAccessTokensBatchResponse.access_tokens:type_name -> proto.GetMCPServerAccessTokensBatchResponse.AccessTokensEntry + 25, // 14: proto.GetMCPServerAccessTokensBatchResponse.errors:type_name -> proto.GetMCPServerAccessTokensBatchResponse.ErrorsEntry + 27, // 15: proto.RecordInterceptionRequest.MetadataEntry.value:type_name -> google.protobuf.Any + 27, // 16: proto.RecordTokenUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any + 27, // 17: proto.RecordPromptUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any + 27, // 18: proto.RecordToolUsageRequest.MetadataEntry.value:type_name -> google.protobuf.Any + 27, // 19: proto.RecordModelThoughtRequest.MetadataEntry.value:type_name -> google.protobuf.Any + 0, // 20: proto.Recorder.RecordInterception:input_type -> proto.RecordInterceptionRequest + 2, // 21: proto.Recorder.RecordInterceptionEnded:input_type -> proto.RecordInterceptionEndedRequest + 4, // 22: proto.Recorder.RecordTokenUsage:input_type -> proto.RecordTokenUsageRequest + 6, // 23: proto.Recorder.RecordPromptUsage:input_type -> proto.RecordPromptUsageRequest + 8, // 24: proto.Recorder.RecordToolUsage:input_type -> proto.RecordToolUsageRequest + 10, // 25: proto.Recorder.RecordModelThought:input_type -> proto.RecordModelThoughtRequest + 12, // 26: proto.MCPConfigurator.GetMCPServerConfigs:input_type -> proto.GetMCPServerConfigsRequest + 15, // 27: proto.MCPConfigurator.GetMCPServerAccessTokensBatch:input_type -> proto.GetMCPServerAccessTokensBatchRequest + 17, // 28: proto.Authorizer.IsAuthorized:input_type -> proto.IsAuthorizedRequest 1, // 29: proto.Recorder.RecordInterception:output_type -> proto.RecordInterceptionResponse 3, // 30: proto.Recorder.RecordInterceptionEnded:output_type -> proto.RecordInterceptionEndedResponse 5, // 31: proto.Recorder.RecordTokenUsage:output_type -> proto.RecordTokenUsageResponse 7, // 32: proto.Recorder.RecordPromptUsage:output_type -> proto.RecordPromptUsageResponse 9, // 33: proto.Recorder.RecordToolUsage:output_type -> proto.RecordToolUsageResponse - 12, // 34: proto.MCPConfigurator.GetMCPServerConfigs:output_type -> proto.GetMCPServerConfigsResponse - 15, // 35: proto.MCPConfigurator.GetMCPServerAccessTokensBatch:output_type -> proto.GetMCPServerAccessTokensBatchResponse - 17, // 36: proto.Authorizer.IsAuthorized:output_type -> proto.IsAuthorizedResponse - 29, // [29:37] is the sub-list for method output_type - 21, // [21:29] is the sub-list for method input_type - 21, // [21:21] is the sub-list for extension type_name - 21, // [21:21] is the sub-list for extension extendee - 0, // [0:21] is the sub-list for field type_name + 11, // 34: proto.Recorder.RecordModelThought:output_type -> proto.RecordModelThoughtResponse + 13, // 35: proto.MCPConfigurator.GetMCPServerConfigs:output_type -> proto.GetMCPServerConfigsResponse + 16, // 36: proto.MCPConfigurator.GetMCPServerAccessTokensBatch:output_type -> proto.GetMCPServerAccessTokensBatchResponse + 18, // 37: proto.Authorizer.IsAuthorized:output_type -> proto.IsAuthorizedResponse + 29, // [29:38] is the sub-list for method output_type + 20, // [20:29] is the sub-list for method input_type + 20, // [20:20] is the sub-list for extension type_name + 20, // [20:20] is the sub-list for extension extendee + 0, // [0:20] is the sub-list for field type_name } func init() { file_enterprise_aibridged_proto_aibridged_proto_init() } @@ -1638,7 +1684,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ModelThought); i { + switch v := v.(*RecordModelThoughtRequest); i { case 0: return &v.state case 1: @@ -1650,7 +1696,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMCPServerConfigsRequest); i { + switch v := v.(*RecordModelThoughtResponse); i { case 0: return &v.state case 1: @@ -1662,7 +1708,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMCPServerConfigsResponse); i { + switch v := v.(*GetMCPServerConfigsRequest); i { case 0: return &v.state case 1: @@ -1674,7 +1720,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MCPServerConfig); i { + switch v := v.(*GetMCPServerConfigsResponse); i { case 0: return &v.state case 1: @@ -1686,7 +1732,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMCPServerAccessTokensBatchRequest); i { + switch v := v.(*MCPServerConfig); i { case 0: return &v.state case 1: @@ -1698,7 +1744,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetMCPServerAccessTokensBatchResponse); i { + switch v := v.(*GetMCPServerAccessTokensBatchRequest); i { case 0: return &v.state case 1: @@ -1710,7 +1756,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*IsAuthorizedRequest); i { + switch v := v.(*GetMCPServerAccessTokensBatchResponse); i { case 0: return &v.state case 1: @@ -1722,6 +1768,18 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { } } file_enterprise_aibridged_proto_aibridged_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*IsAuthorizedRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_enterprise_aibridged_proto_aibridged_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*IsAuthorizedResponse); i { case 0: return &v.state @@ -1742,7 +1800,7 @@ func file_enterprise_aibridged_proto_aibridged_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_enterprise_aibridged_proto_aibridged_proto_rawDesc, NumEnums: 0, - NumMessages: 25, + NumMessages: 26, NumExtensions: 0, NumServices: 3, }, diff --git a/enterprise/aibridged/proto/aibridged.proto b/enterprise/aibridged/proto/aibridged.proto index cf2457e43ce3a..e0aa34346a7dd 100644 --- a/enterprise/aibridged/proto/aibridged.proto +++ b/enterprise/aibridged/proto/aibridged.proto @@ -15,6 +15,7 @@ service Recorder { rpc RecordTokenUsage(RecordTokenUsageRequest) returns (RecordTokenUsageResponse); rpc RecordPromptUsage(RecordPromptUsageRequest) returns (RecordPromptUsageResponse); rpc RecordToolUsage(RecordToolUsageRequest) returns (RecordToolUsageResponse); + rpc RecordModelThought(RecordModelThoughtRequest) returns (RecordModelThoughtResponse); } // MCPConfigurator is responsible for retrieving any relevant data required for configuring MCP clients @@ -88,17 +89,16 @@ message RecordToolUsageRequest { map metadata = 8; google.protobuf.Timestamp created_at = 9; string tool_call_id = 10; // The ID of the tool call provided by the AI provider. - repeated ModelThought model_thoughts = 11; // Model thinking associated with this tool call. } message RecordToolUsageResponse {} -// ModelThought represents a model's thinking/reasoning associated with -// a tool call. -message ModelThought { - string content = 1; - map metadata = 2; - google.protobuf.Timestamp created_at = 3; +message RecordModelThoughtRequest { + string interception_id = 1; // UUID. + string content = 2; + map metadata = 3; + google.protobuf.Timestamp created_at = 4; } +message RecordModelThoughtResponse {} message GetMCPServerConfigsRequest { string user_id = 1; // UUID. // Not used yet, will be necessary for later RBAC purposes. diff --git a/enterprise/aibridged/proto/aibridged_drpc.pb.go b/enterprise/aibridged/proto/aibridged_drpc.pb.go index 1309957d153d5..95b46701471f1 100644 --- a/enterprise/aibridged/proto/aibridged_drpc.pb.go +++ b/enterprise/aibridged/proto/aibridged_drpc.pb.go @@ -43,6 +43,7 @@ type DRPCRecorderClient interface { RecordTokenUsage(ctx context.Context, in *RecordTokenUsageRequest) (*RecordTokenUsageResponse, error) RecordPromptUsage(ctx context.Context, in *RecordPromptUsageRequest) (*RecordPromptUsageResponse, error) RecordToolUsage(ctx context.Context, in *RecordToolUsageRequest) (*RecordToolUsageResponse, error) + RecordModelThought(ctx context.Context, in *RecordModelThoughtRequest) (*RecordModelThoughtResponse, error) } type drpcRecorderClient struct { @@ -100,12 +101,22 @@ func (c *drpcRecorderClient) RecordToolUsage(ctx context.Context, in *RecordTool return out, nil } +func (c *drpcRecorderClient) RecordModelThought(ctx context.Context, in *RecordModelThoughtRequest) (*RecordModelThoughtResponse, error) { + out := new(RecordModelThoughtResponse) + err := c.cc.Invoke(ctx, "/proto.Recorder/RecordModelThought", drpcEncoding_File_enterprise_aibridged_proto_aibridged_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + type DRPCRecorderServer interface { RecordInterception(context.Context, *RecordInterceptionRequest) (*RecordInterceptionResponse, error) RecordInterceptionEnded(context.Context, *RecordInterceptionEndedRequest) (*RecordInterceptionEndedResponse, error) RecordTokenUsage(context.Context, *RecordTokenUsageRequest) (*RecordTokenUsageResponse, error) RecordPromptUsage(context.Context, *RecordPromptUsageRequest) (*RecordPromptUsageResponse, error) RecordToolUsage(context.Context, *RecordToolUsageRequest) (*RecordToolUsageResponse, error) + RecordModelThought(context.Context, *RecordModelThoughtRequest) (*RecordModelThoughtResponse, error) } type DRPCRecorderUnimplementedServer struct{} @@ -130,9 +141,13 @@ func (s *DRPCRecorderUnimplementedServer) RecordToolUsage(context.Context, *Reco return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } +func (s *DRPCRecorderUnimplementedServer) RecordModelThought(context.Context, *RecordModelThoughtRequest) (*RecordModelThoughtResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + type DRPCRecorderDescription struct{} -func (DRPCRecorderDescription) NumMethods() int { return 5 } +func (DRPCRecorderDescription) NumMethods() int { return 6 } func (DRPCRecorderDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { switch n { @@ -181,6 +196,15 @@ func (DRPCRecorderDescription) Method(n int) (string, drpc.Encoding, drpc.Receiv in1.(*RecordToolUsageRequest), ) }, DRPCRecorderServer.RecordToolUsage, true + case 5: + return "/proto.Recorder/RecordModelThought", drpcEncoding_File_enterprise_aibridged_proto_aibridged_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCRecorderServer). + RecordModelThought( + ctx, + in1.(*RecordModelThoughtRequest), + ) + }, DRPCRecorderServer.RecordModelThought, true default: return "", nil, nil, nil, false } @@ -270,6 +294,22 @@ func (x *drpcRecorder_RecordToolUsageStream) SendAndClose(m *RecordToolUsageResp return x.CloseSend() } +type DRPCRecorder_RecordModelThoughtStream interface { + drpc.Stream + SendAndClose(*RecordModelThoughtResponse) error +} + +type drpcRecorder_RecordModelThoughtStream struct { + drpc.Stream +} + +func (x *drpcRecorder_RecordModelThoughtStream) SendAndClose(m *RecordModelThoughtResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_enterprise_aibridged_proto_aibridged_proto{}); err != nil { + return err + } + return x.CloseSend() +} + type DRPCMCPConfiguratorClient interface { DRPCConn() drpc.Conn diff --git a/enterprise/aibridged/translator.go b/enterprise/aibridged/translator.go index 122a2135413f0..66cb010671293 100644 --- a/enterprise/aibridged/translator.go +++ b/enterprise/aibridged/translator.go @@ -92,15 +92,6 @@ func (t *recorderTranslation) RecordToolUsage(ctx context.Context, req *aibridge invErr = ptr.Ref(req.InvocationError.Error()) } - var thoughts []*proto.ModelThought - for _, thought := range req.ModelThoughts { - thoughts = append(thoughts, &proto.ModelThought{ - Content: thought.Content, - Metadata: marshalForProto(thought.Metadata), - CreatedAt: timestamppb.New(thought.CreatedAt), - }) - } - _, err = t.client.RecordToolUsage(ctx, &proto.RecordToolUsageRequest{ InterceptionId: req.InterceptionID, MsgId: req.MsgID, @@ -112,7 +103,16 @@ func (t *recorderTranslation) RecordToolUsage(ctx context.Context, req *aibridge InvocationError: invErr, Metadata: marshalForProto(req.Metadata), CreatedAt: timestamppb.New(req.CreatedAt), - ModelThoughts: thoughts, + }) + return err +} + +func (t *recorderTranslation) RecordModelThought(ctx context.Context, req *aibridge.ModelThoughtRecord) error { + _, err := t.client.RecordModelThought(ctx, &proto.RecordModelThoughtRequest{ + InterceptionId: req.InterceptionID, + Content: req.Content, + Metadata: marshalForProto(req.Metadata), + CreatedAt: timestamppb.New(req.CreatedAt), }) return err } diff --git a/enterprise/aibridgedserver/aibridgedserver.go b/enterprise/aibridgedserver/aibridgedserver.go index 62985a0554ac5..cfb59730c22d0 100644 --- a/enterprise/aibridgedserver/aibridgedserver.go +++ b/enterprise/aibridgedserver/aibridgedserver.go @@ -340,9 +340,8 @@ func (s *Server) RecordToolUsage(ctx context.Context, in *proto.RecordToolUsageR s.logger.Warn(ctx, "failed to marshal aibridge metadata from proto to JSON", slog.F("metadata", in), slog.Error(err)) } - toolUsageID := uuid.New() _, err = s.store.InsertAIBridgeToolUsage(ctx, database.InsertAIBridgeToolUsageParams{ - ID: toolUsageID, + ID: uuid.New(), InterceptionID: intcID, ProviderResponseID: in.GetMsgId(), ProviderToolCallID: sql.NullString{String: in.GetToolCallId(), Valid: in.GetToolCallId() != ""}, @@ -358,44 +357,47 @@ func (s *Server) RecordToolUsage(ctx context.Context, in *proto.RecordToolUsageR return nil, xerrors.Errorf("insert tool usage: %w", err) } - // Insert any model thoughts associated with this tool call. - for _, thought := range in.GetModelThoughts() { - thoughtMetadata := metadataToMap(thought.GetMetadata()) + return &proto.RecordToolUsageResponse{}, nil +} - if s.structuredLogging { - s.logger.Info(ctx, InterceptionLogMarker, - slog.F("record_type", "model_thought"), - slog.F("interception_id", intcID.String()), - slog.F("tool_usage_id", toolUsageID.String()), - slog.F("content", thought.GetContent()), - slog.F("created_at", thought.GetCreatedAt().AsTime()), - slog.F("metadata", thoughtMetadata), - ) - } +func (s *Server) RecordModelThought(ctx context.Context, in *proto.RecordModelThoughtRequest) (*proto.RecordModelThoughtResponse, error) { + //nolint:gocritic // AIBridged has specific authz rules. + ctx = dbauthz.AsAIBridged(ctx) - thoughtMetadataJSON, err := json.Marshal(thoughtMetadata) - if err != nil { - s.logger.Warn(ctx, "failed to marshal aibridge model thought metadata from proto to JSON", slog.F("metadata", thought), slog.Error(err)) - } + intcID, err := uuid.Parse(in.GetInterceptionId()) + if err != nil { + return nil, xerrors.Errorf("failed to parse interception_id %q: %w", in.GetInterceptionId(), err) + } - _, err = s.store.InsertAIBridgeModelThought(ctx, database.InsertAIBridgeModelThoughtParams{ - ID: uuid.New(), - InterceptionID: intcID, - ToolUsageID: toolUsageID, - Content: sql.NullString{String: thought.GetContent(), Valid: thought.GetContent() != ""}, - Metadata: thoughtMetadataJSON, - CreatedAt: thought.GetCreatedAt().AsTime(), - }) - if err != nil { - s.logger.Warn(ctx, "failed to insert model thought", - slog.Error(err), - slog.F("interception_id", intcID.String()), - slog.F("tool_usage_id", toolUsageID.String()), - ) - } + metadata := metadataToMap(in.GetMetadata()) + + if s.structuredLogging { + s.logger.Info(ctx, InterceptionLogMarker, + slog.F("record_type", "model_thought"), + slog.F("interception_id", intcID.String()), + slog.F("content", in.GetContent()), + slog.F("created_at", in.GetCreatedAt().AsTime()), + slog.F("metadata", metadata), + ) } - return &proto.RecordToolUsageResponse{}, nil + out, err := json.Marshal(metadata) + if err != nil { + s.logger.Warn(ctx, "failed to marshal aibridge metadata from proto to JSON", slog.F("metadata", in), slog.Error(err)) + } + + _, err = s.store.InsertAIBridgeModelThought(ctx, database.InsertAIBridgeModelThoughtParams{ + ID: uuid.New(), + InterceptionID: intcID, + Content: in.GetContent(), + Metadata: out, + CreatedAt: in.GetCreatedAt().AsTime(), + }) + if err != nil { + return nil, xerrors.Errorf("insert model thought: %w", err) + } + + return &proto.RecordModelThoughtResponse{}, nil } // findInterceptionLineage looks up the parent interception and the root diff --git a/enterprise/aibridgedserver/aibridgedserver_test.go b/enterprise/aibridgedserver/aibridgedserver_test.go index 0bc3914a1fc30..10785c73a8378 100644 --- a/enterprise/aibridgedserver/aibridgedserver_test.go +++ b/enterprise/aibridgedserver/aibridgedserver_test.go @@ -982,44 +982,41 @@ func TestRecordToolUsage(t *testing.T) { }, expectedErr: "insert tool usage", }, + }, + ) +} + +func TestRecordModelThought(t *testing.T) { + t.Parallel() + + var ( + metadataProto = map[string]*anypb.Any{ + "key": mustMarshalAny(t, &structpb.Value{Kind: &structpb.Value_StringValue{StringValue: "value"}}), + } + metadataJSON = `{"key":"value"}` + ) + + testRecordMethod(t, + func(srv *aibridgedserver.Server, ctx context.Context, req *proto.RecordModelThoughtRequest) (*proto.RecordModelThoughtResponse, error) { + return srv.RecordModelThought(ctx, req) + }, + []testRecordMethodCase[*proto.RecordModelThoughtRequest]{ { - name: "tool usage with model thoughts", - request: &proto.RecordToolUsageRequest{ + name: "valid model thought", + request: &proto.RecordModelThoughtRequest{ InterceptionId: uuid.NewString(), - MsgId: "msg_456", - ToolCallId: "call_abc", - Tool: "bash", - Input: `{"command": "ls"}`, - Injected: true, + Content: "I should list the files.", + Metadata: metadataProto, CreatedAt: timestamppb.Now(), - ModelThoughts: []*proto.ModelThought{ - { - Content: "I should list the files.", - Metadata: metadataProto, - CreatedAt: timestamppb.Now(), - }, - }, }, - setupMocks: func(t *testing.T, db *dbmock.MockStore, req *proto.RecordToolUsageRequest) { + setupMocks: func(t *testing.T, db *dbmock.MockStore, req *proto.RecordModelThoughtRequest) { interceptionID, err := uuid.Parse(req.GetInterceptionId()) assert.NoError(t, err, "parse interception UUID") - var toolUsageID uuid.UUID - db.EXPECT().InsertAIBridgeToolUsage(gomock.Any(), gomock.Cond(func(p database.InsertAIBridgeToolUsageParams) bool { - toolUsageID = p.ID - return assert.Equal(t, interceptionID, p.InterceptionID, "interception ID") - })).Return(database.AIBridgeToolUsage{ - ID: uuid.New(), - InterceptionID: interceptionID, - Tool: req.GetTool(), - CreatedAt: req.GetCreatedAt().AsTime(), - }, nil) - db.EXPECT().InsertAIBridgeModelThought(gomock.Any(), gomock.Cond(func(p database.InsertAIBridgeModelThoughtParams) bool { if !assert.NotEqual(t, uuid.Nil, p.ID, "ID not nil") || !assert.Equal(t, interceptionID, p.InterceptionID, "interception ID") || - !assert.Equal(t, toolUsageID, p.ToolUsageID, "tool usage ID") || - !assert.Equal(t, sql.NullString{String: "I should list the files.", Valid: true}, p.Content, "content") || + !assert.Equal(t, "I should list the files.", p.Content, "content") || !assert.JSONEq(t, metadataJSON, string(p.Metadata), "metadata") { return false } @@ -1027,8 +1024,7 @@ func TestRecordToolUsage(t *testing.T) { })).Return(database.AIBridgeModelThought{ ID: uuid.New(), InterceptionID: interceptionID, - ToolUsageID: toolUsageID, - Content: sql.NullString{String: "I should list the files.", Valid: true}, + Content: "I should list the files.", Metadata: pqtype.NullRawMessage{ RawMessage: json.RawMessage(metadataJSON), Valid: true, @@ -1036,6 +1032,27 @@ func TestRecordToolUsage(t *testing.T) { }, nil) }, }, + { + name: "invalid interception ID", + request: &proto.RecordModelThoughtRequest{ + InterceptionId: "not-a-uuid", + Content: "thinking...", + CreatedAt: timestamppb.Now(), + }, + expectedErr: "failed to parse interception_id", + }, + { + name: "database error", + request: &proto.RecordModelThoughtRequest{ + InterceptionId: uuid.NewString(), + Content: "thinking...", + CreatedAt: timestamppb.Now(), + }, + setupMocks: func(t *testing.T, db *dbmock.MockStore, req *proto.RecordModelThoughtRequest) { + db.EXPECT().InsertAIBridgeModelThought(gomock.Any(), gomock.Any()).Return(database.AIBridgeModelThought{}, sql.ErrConnDone) + }, + expectedErr: "insert model thought", + }, }, ) } @@ -1350,46 +1367,28 @@ func TestStructuredLogging(t *testing.T) { }, }, { - name: "RecordToolUsage_with_model_thought_logs_when_enabled", + name: "RecordModelThought_logs_when_enabled", structuredLogging: true, setupMocks: func(db *dbmock.MockStore, intcID uuid.UUID) { - db.EXPECT().InsertAIBridgeToolUsage(gomock.Any(), gomock.Any()).Return(database.AIBridgeToolUsage{ - ID: uuid.New(), - InterceptionID: intcID, - Tool: "bash", - }, nil) db.EXPECT().InsertAIBridgeModelThought(gomock.Any(), gomock.Any()).Return(database.AIBridgeModelThought{ ID: uuid.New(), InterceptionID: intcID, }, nil) }, recordFn: func(srv *aibridgedserver.Server, ctx context.Context, intcID uuid.UUID) error { - _, err := srv.RecordToolUsage(ctx, &proto.RecordToolUsageRequest{ + _, err := srv.RecordModelThought(ctx, &proto.RecordModelThoughtRequest{ InterceptionId: intcID.String(), - MsgId: "msg_789", - ToolCallId: "call_xyz", - Tool: "bash", - Input: `{"command": "ls"}`, - Injected: true, + Content: "I need to list the files.", + Metadata: metadataProto, CreatedAt: timestamppb.Now(), - ModelThoughts: []*proto.ModelThought{ - { - Content: "I need to list the files.", - Metadata: metadataProto, - CreatedAt: timestamppb.Now(), - }, - }, }) return err }, - // The structured logging test checks for the first log line. - // RecordToolUsage logs both tool_usage and model_thought entries. expectedFields: map[string]any{ "record_type": "model_thought", "interception_id": interceptionID.String(), "content": "I need to list the files.", }, - expectedLineIdx: 1, // "tool_usage" is also logged. }, } @@ -1423,7 +1422,7 @@ func TestStructuredLogging(t *testing.T) { require.Empty(t, lines) } else { matchedLines := getLogLinesWithMessage(lines, aibridgedserver.InterceptionLogMarker) - require.GreaterOrEqual(t, tc.expectedLineIdx+1, len(matchedLines), "expected at least %d log line with message %q", tc.expectedLineIdx+1, aibridgedserver.InterceptionLogMarker) + require.GreaterOrEqual(t, len(matchedLines), tc.expectedLineIdx+1, "expected at least %d log line(s) with message %q", tc.expectedLineIdx+1, aibridgedserver.InterceptionLogMarker) fields := matchedLines[tc.expectedLineIdx].Fields for key, expected := range tc.expectedFields { diff --git a/go.mod b/go.mod index 713162c025cfd..423b35d81f3ea 100644 --- a/go.mod +++ b/go.mod @@ -85,7 +85,7 @@ replace charm.land/fantasy => github.com/kylecarbs/fantasy v0.0.0-20260313123746 replace github.com/charmbracelet/anthropic-sdk-go => github.com/kylecarbs/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab require ( - cdr.dev/slog/v3 v3.0.0-rc1 + cdr.dev/slog/v3 v3.0.0 cloud.google.com/go/compute/metadata v0.9.0 github.com/Microsoft/go-winio v0.6.2 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d @@ -485,7 +485,7 @@ require ( github.com/anthropics/anthropic-sdk-go v1.19.0 github.com/brianvoe/gofakeit/v7 v7.14.0 github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225 - github.com/coder/aibridge v1.0.8-0.20260306145130-a0ad39219bad // TODO: update with merge commit. + github.com/coder/aibridge v1.0.8-0.20260313153751-0c56c3327014 // TODO: update with merge commit. github.com/coder/aisdk-go v0.0.9 github.com/coder/boundary v0.8.4-0.20260304164748-566aeea939ab github.com/coder/preview v1.0.8 diff --git a/go.sum b/go.sum index c8b264dd6cec2..3e720d6617006 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -cdr.dev/slog/v3 v3.0.0-rc1 h1:EN7Zim6GvTpAeHQjI0ERDEfqKbTyXRvgH4UhlzLpvWM= -cdr.dev/slog/v3 v3.0.0-rc1/go.mod h1:iO/OALX1VxlI03mkodCGdVP7pXzd2bRMvu3ePvlJ9ak= +cdr.dev/slog/v3 v3.0.0 h1:kXFUqAqK7ogRKcvo4BnduQVp+Jh0uV1AUKf3NW5FU74= +cdr.dev/slog/v3 v3.0.0/go.mod h1:iO/OALX1VxlI03mkodCGdVP7pXzd2bRMvu3ePvlJ9ak= cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= @@ -313,8 +313,8 @@ github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225 h1:tRIViZ5JRmzdOEo5wUWngaGEFBG8OaE1o2GIHN5ujJ8= github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225/go.mod h1:rNLVpYgEVeu1Zk29K64z6Od8RBP9DwqCu9OfCzh8MR4= -github.com/coder/aibridge v1.0.8-0.20260306145130-a0ad39219bad h1:juS2+u/GmcPa1We/hcKLluMIEXS+zx8hO2ptEpFl5O4= -github.com/coder/aibridge v1.0.8-0.20260306145130-a0ad39219bad/go.mod h1:3BTl243k7OhpqtaITARAw647uC2V0YrxGOTQrkscnkk= +github.com/coder/aibridge v1.0.8-0.20260313153751-0c56c3327014 h1:Oks48RqNFcXGelQ38pyrF5V45OVu7muBOEHw1cUeGxg= +github.com/coder/aibridge v1.0.8-0.20260313153751-0c56c3327014/go.mod h1:u6WvGLMQQbk3ByeOw+LBdVgDNc/v/ujAtUc6MfvzQb4= github.com/coder/aisdk-go v0.0.9 h1:Vzo/k2qwVGLTR10ESDeP2Ecek1SdPfZlEjtTfMveiVo= github.com/coder/aisdk-go v0.0.9/go.mod h1:KF6/Vkono0FJJOtWtveh5j7yfNrSctVTpwgweYWSp5M= github.com/coder/boundary v0.8.4-0.20260304164748-566aeea939ab h1:HrlxyTmMQpOHfSKzRU1vf5TxrmV6vL5OiWq+Dvn5qh0= From b9132e4243b1e01d14c33b1249b7fab9796b0217 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 16 Mar 2026 10:58:00 +0200 Subject: [PATCH 10/13] chore: fix mock Signed-off-by: Danny Kopping --- enterprise/aibridged/aibridgedmock/clientmock.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/enterprise/aibridged/aibridgedmock/clientmock.go b/enterprise/aibridged/aibridgedmock/clientmock.go index 2bb7083e10924..cbd00c41fd435 100644 --- a/enterprise/aibridged/aibridgedmock/clientmock.go +++ b/enterprise/aibridged/aibridgedmock/clientmock.go @@ -131,6 +131,21 @@ func (mr *MockDRPCClientMockRecorder) RecordInterceptionEnded(ctx, in any) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordInterceptionEnded", reflect.TypeOf((*MockDRPCClient)(nil).RecordInterceptionEnded), ctx, in) } +// RecordModelThought mocks base method. +func (m *MockDRPCClient) RecordModelThought(ctx context.Context, in *proto.RecordModelThoughtRequest) (*proto.RecordModelThoughtResponse, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RecordModelThought", ctx, in) + ret0, _ := ret[0].(*proto.RecordModelThoughtResponse) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// RecordModelThought indicates an expected call of RecordModelThought. +func (mr *MockDRPCClientMockRecorder) RecordModelThought(ctx, in any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecordModelThought", reflect.TypeOf((*MockDRPCClient)(nil).RecordModelThought), ctx, in) +} + // RecordPromptUsage mocks base method. func (m *MockDRPCClient) RecordPromptUsage(ctx context.Context, in *proto.RecordPromptUsageRequest) (*proto.RecordPromptUsageResponse, error) { m.ctrl.T.Helper() From 44a393ee31af3a154b2dfc1600c968ed289825f7 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 16 Mar 2026 10:58:31 +0200 Subject: [PATCH 11/13] chore: fix migrations Signed-off-by: Danny Kopping --- ..._thoughts.down.sql => 000439_aibridge_model_thoughts.down.sql} | 0 ...odel_thoughts.up.sql => 000439_aibridge_model_thoughts.up.sql} | 0 ...odel_thoughts.up.sql => 000439_aibridge_model_thoughts.up.sql} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000434_aibridge_model_thoughts.down.sql => 000439_aibridge_model_thoughts.down.sql} (100%) rename coderd/database/migrations/{000434_aibridge_model_thoughts.up.sql => 000439_aibridge_model_thoughts.up.sql} (100%) rename coderd/database/migrations/testdata/fixtures/{000434_aibridge_model_thoughts.up.sql => 000439_aibridge_model_thoughts.up.sql} (100%) diff --git a/coderd/database/migrations/000434_aibridge_model_thoughts.down.sql b/coderd/database/migrations/000439_aibridge_model_thoughts.down.sql similarity index 100% rename from coderd/database/migrations/000434_aibridge_model_thoughts.down.sql rename to coderd/database/migrations/000439_aibridge_model_thoughts.down.sql diff --git a/coderd/database/migrations/000434_aibridge_model_thoughts.up.sql b/coderd/database/migrations/000439_aibridge_model_thoughts.up.sql similarity index 100% rename from coderd/database/migrations/000434_aibridge_model_thoughts.up.sql rename to coderd/database/migrations/000439_aibridge_model_thoughts.up.sql diff --git a/coderd/database/migrations/testdata/fixtures/000434_aibridge_model_thoughts.up.sql b/coderd/database/migrations/testdata/fixtures/000439_aibridge_model_thoughts.up.sql similarity index 100% rename from coderd/database/migrations/testdata/fixtures/000434_aibridge_model_thoughts.up.sql rename to coderd/database/migrations/testdata/fixtures/000439_aibridge_model_thoughts.up.sql From d10ac12dd19b27d0aa5e7261dafbee4cc3872771 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 16 Mar 2026 21:22:31 +0200 Subject: [PATCH 12/13] chore: update go.mod Signed-off-by: Danny Kopping --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 423b35d81f3ea..1dcbe2f71a28d 100644 --- a/go.mod +++ b/go.mod @@ -485,7 +485,7 @@ require ( github.com/anthropics/anthropic-sdk-go v1.19.0 github.com/brianvoe/gofakeit/v7 v7.14.0 github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225 - github.com/coder/aibridge v1.0.8-0.20260313153751-0c56c3327014 // TODO: update with merge commit. + github.com/coder/aibridge v1.0.8-0.20260316151612-5c071a7db41b github.com/coder/aisdk-go v0.0.9 github.com/coder/boundary v0.8.4-0.20260304164748-566aeea939ab github.com/coder/preview v1.0.8 diff --git a/go.sum b/go.sum index 3e720d6617006..7893f6a42ccdc 100644 --- a/go.sum +++ b/go.sum @@ -313,8 +313,8 @@ github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225 h1:tRIViZ5JRmzdOEo5wUWngaGEFBG8OaE1o2GIHN5ujJ8= github.com/coder/agentapi-sdk-go v0.0.0-20250505131810-560d1d88d225/go.mod h1:rNLVpYgEVeu1Zk29K64z6Od8RBP9DwqCu9OfCzh8MR4= -github.com/coder/aibridge v1.0.8-0.20260313153751-0c56c3327014 h1:Oks48RqNFcXGelQ38pyrF5V45OVu7muBOEHw1cUeGxg= -github.com/coder/aibridge v1.0.8-0.20260313153751-0c56c3327014/go.mod h1:u6WvGLMQQbk3ByeOw+LBdVgDNc/v/ujAtUc6MfvzQb4= +github.com/coder/aibridge v1.0.8-0.20260316151612-5c071a7db41b h1:O470JUI+D8cuCSsPVSI6JMUq1JlKDdsPtk7feDCaLqQ= +github.com/coder/aibridge v1.0.8-0.20260316151612-5c071a7db41b/go.mod h1:u6WvGLMQQbk3ByeOw+LBdVgDNc/v/ujAtUc6MfvzQb4= github.com/coder/aisdk-go v0.0.9 h1:Vzo/k2qwVGLTR10ESDeP2Ecek1SdPfZlEjtTfMveiVo= github.com/coder/aisdk-go v0.0.9/go.mod h1:KF6/Vkono0FJJOtWtveh5j7yfNrSctVTpwgweYWSp5M= github.com/coder/boundary v0.8.4-0.20260304164748-566aeea939ab h1:HrlxyTmMQpOHfSKzRU1vf5TxrmV6vL5OiWq+Dvn5qh0= From 056cff9c81770c26dc38ed56c67956f43e18ef49 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 16 Mar 2026 22:12:14 +0200 Subject: [PATCH 13/13] chore: fix migrations Signed-off-by: Danny Kopping --- ..._thoughts.down.sql => 000440_aibridge_model_thoughts.down.sql} | 0 ...odel_thoughts.up.sql => 000440_aibridge_model_thoughts.up.sql} | 0 ...odel_thoughts.up.sql => 000440_aibridge_model_thoughts.up.sql} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000439_aibridge_model_thoughts.down.sql => 000440_aibridge_model_thoughts.down.sql} (100%) rename coderd/database/migrations/{000439_aibridge_model_thoughts.up.sql => 000440_aibridge_model_thoughts.up.sql} (100%) rename coderd/database/migrations/testdata/fixtures/{000439_aibridge_model_thoughts.up.sql => 000440_aibridge_model_thoughts.up.sql} (100%) diff --git a/coderd/database/migrations/000439_aibridge_model_thoughts.down.sql b/coderd/database/migrations/000440_aibridge_model_thoughts.down.sql similarity index 100% rename from coderd/database/migrations/000439_aibridge_model_thoughts.down.sql rename to coderd/database/migrations/000440_aibridge_model_thoughts.down.sql diff --git a/coderd/database/migrations/000439_aibridge_model_thoughts.up.sql b/coderd/database/migrations/000440_aibridge_model_thoughts.up.sql similarity index 100% rename from coderd/database/migrations/000439_aibridge_model_thoughts.up.sql rename to coderd/database/migrations/000440_aibridge_model_thoughts.up.sql diff --git a/coderd/database/migrations/testdata/fixtures/000439_aibridge_model_thoughts.up.sql b/coderd/database/migrations/testdata/fixtures/000440_aibridge_model_thoughts.up.sql similarity index 100% rename from coderd/database/migrations/testdata/fixtures/000439_aibridge_model_thoughts.up.sql rename to coderd/database/migrations/testdata/fixtures/000440_aibridge_model_thoughts.up.sql