Quellcode durchsuchen

Hide backend API errors from job search chat.

Show generic connection and search failure messages so OpenAI responses never expose keys or internal details to users.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 vor 2 Wochen
Ursprung
Commit
a596b41e00

+ 23 - 0
App for Indeed/Services/UserFacingErrorMessage.swift

@@ -0,0 +1,23 @@
1
+import Foundation
2
+
3
+/// Maps backend and network errors to short, safe copy for the UI.
4
+enum UserFacingErrorMessage {
5
+    static func jobSearchFailure(_ error: Error) -> String {
6
+        if let urlError = error as? URLError {
7
+            switch urlError.code {
8
+            case .notConnectedToInternet,
9
+                 .networkConnectionLost,
10
+                 .timedOut,
11
+                 .cannotFindHost,
12
+                 .cannotConnectToHost,
13
+                 .dnsLookupFailed:
14
+                return "We couldn't reach the server. Check your internet connection and try again."
15
+            case .cancelled:
16
+                return "The search was cancelled. Try again when you're ready."
17
+            default:
18
+                break
19
+            }
20
+        }
21
+        return "Something went wrong while searching. Please try again in a moment."
22
+    }
23
+}

+ 13 - 17
App for Indeed/Views/DashboardView.swift

@@ -2163,7 +2163,7 @@ final class DashboardView: NSView, NSTextFieldDelegate, NSSharingServicePickerDe
2163 2163
                     self.chatMessages.append(ChatMessage(role: "assistant", content: reply, attachedJobs: freshJobs.isEmpty ? nil : freshJobs))
2164 2164
                     self.appendChatBubble(text: reply, isUser: false, jobs: freshJobs)
2165 2165
                 case .failure(let error):
2166
-                    self.appendChatBubble(text: error.localizedDescription, isUser: false)
2166
+                    self.appendChatBubble(text: UserFacingErrorMessage.jobSearchFailure(error), isUser: false)
2167 2167
                 }
2168 2168
             }
2169 2169
         }
@@ -2920,7 +2920,7 @@ private final class OpenAIJobSearchService {
2920 2920
             completion(.failure(NSError(
2921 2921
                 domain: "OpenAIJobSearchService",
2922 2922
                 code: 1,
2923
-                userInfo: [NSLocalizedDescriptionKey: "Missing API key. Set OPENAI_API_KEY in Xcode Build Settings."]
2923
+                userInfo: [NSLocalizedDescriptionKey: "Job search is unavailable."]
2924 2924
             )))
2925 2925
             return
2926 2926
         }
@@ -2995,19 +2995,12 @@ private final class OpenAIJobSearchService {
2995 2995
                 return
2996 2996
             }
2997 2997
             if let http = response as? HTTPURLResponse, !(200...299).contains(http.statusCode) {
2998
-                if let apiError = try? JSONDecoder().decode(OpenAIAPIErrorResponse.self, from: data) {
2999
-                    completion(.failure(NSError(
3000
-                        domain: "OpenAIJobSearchService",
3001
-                        code: http.statusCode,
3002
-                        userInfo: [NSLocalizedDescriptionKey: apiError.error.message]
3003
-                    )))
3004
-                } else {
3005
-                    completion(.failure(NSError(
3006
-                        domain: "OpenAIJobSearchService",
3007
-                        code: http.statusCode,
3008
-                        userInfo: [NSLocalizedDescriptionKey: "Job search request failed with status \(http.statusCode)."]
3009
-                    )))
3010
-                }
2998
+                _ = try? JSONDecoder().decode(OpenAIAPIErrorResponse.self, from: data)
2999
+                completion(.failure(NSError(
3000
+                    domain: "OpenAIJobSearchService",
3001
+                    code: http.statusCode,
3002
+                    userInfo: [NSLocalizedDescriptionKey: "Job search request failed."]
3003
+                )))
3011 3004
                 return
3012 3005
             }
3013 3006
             do {
@@ -3051,8 +3044,11 @@ private final class OpenAIJobSearchService {
3051 3044
         }
3052 3045
         if let status = root["status"] as? String {
3053 3046
             if status == "failed" {
3054
-                let message = (root["error"] as? [String: Any])?["message"] as? String ?? "The search request failed."
3055
-                throw NSError(domain: "OpenAIJobSearchService", code: 7, userInfo: [NSLocalizedDescriptionKey: message])
3047
+                throw NSError(
3048
+                    domain: "OpenAIJobSearchService",
3049
+                    code: 7,
3050
+                    userInfo: [NSLocalizedDescriptionKey: "The search request failed."]
3051
+                )
3056 3052
             }
3057 3053
             if status == "incomplete",
3058 3054
                let details = root["incomplete_details"] as? [String: Any],