| 377 | } |
| 378 | |
| 379 | func (s *Server) RecordModelThought(ctx context.Context, in *proto.RecordModelThoughtRequest) (*proto.RecordModelThoughtResponse, error) { |
| 380 | //nolint:gocritic // AIBridged has specific authz rules. |
| 381 | ctx = dbauthz.AsAIBridged(ctx) |
| 382 | |
| 383 | intcID, err := uuid.Parse(in.GetInterceptionId()) |
| 384 | if err != nil { |
| 385 | return nil, xerrors.Errorf("failed to parse interception_id %q: %w", in.GetInterceptionId(), err) |
| 386 | } |
| 387 | |
| 388 | metadata := metadataToMap(in.GetMetadata()) |
| 389 | |
| 390 | if s.structuredLogging { |
| 391 | s.logger.Info(ctx, InterceptionLogMarker, |
| 392 | slog.F("record_type", "model_thought"), |
| 393 | slog.F("interception_id", intcID.String()), |
| 394 | slog.F("content", in.GetContent()), |
| 395 | slog.F("created_at", in.GetCreatedAt().AsTime()), |
| 396 | slog.F("metadata", metadata), |
| 397 | ) |
| 398 | } |
| 399 | |
| 400 | out, err := json.Marshal(metadata) |
| 401 | if err != nil { |
| 402 | s.logger.Warn(ctx, "failed to marshal aibridge metadata from proto to JSON", slog.F("metadata", in), slog.Error(err)) |
| 403 | } |
| 404 | |
| 405 | _, err = s.store.InsertAIBridgeModelThought(ctx, database.InsertAIBridgeModelThoughtParams{ |
| 406 | InterceptionID: intcID, |
| 407 | Content: in.GetContent(), |
| 408 | Metadata: out, |
| 409 | CreatedAt: in.GetCreatedAt().AsTime(), |
| 410 | }) |
| 411 | if err != nil { |
| 412 | return nil, xerrors.Errorf("insert model thought: %w", err) |
| 413 | } |
| 414 | |
| 415 | return &proto.RecordModelThoughtResponse{}, nil |
| 416 | } |
| 417 | |
| 418 | // findInterceptionLineage looks up the parent interception and the root |
| 419 | // of the thread by finding which interception recorded a tool usage with |