Sfoglia il codice sorgente

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 2 settimane fa
parent
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],