|
@@ -1203,7 +1203,8 @@ final class DashboardView: NSView, NSTextFieldDelegate {
|
|
|
isAwaitingResponse = true
|
|
isAwaitingResponse = true
|
|
|
chatStatusLabel.stringValue = "Thinking..."
|
|
chatStatusLabel.stringValue = "Thinking..."
|
|
|
setInputEnabled(false)
|
|
setInputEnabled(false)
|
|
|
- jobSearchService.searchJobs(query: prompt) { [weak self] result in
|
|
|
|
|
|
|
+ let contextMessages = chatMessages
|
|
|
|
|
+ jobSearchService.searchJobs(query: prompt, conversation: contextMessages) { [weak self] result in
|
|
|
DispatchQueue.main.async {
|
|
DispatchQueue.main.async {
|
|
|
guard let self else { return }
|
|
guard let self else { return }
|
|
|
self.isAwaitingResponse = false
|
|
self.isAwaitingResponse = false
|
|
@@ -1556,7 +1557,7 @@ private final class OpenAIJobSearchService {
|
|
|
private let endpoint = URL(string: "https://api.openai.com/v1/responses")!
|
|
private let endpoint = URL(string: "https://api.openai.com/v1/responses")!
|
|
|
private let session = URLSession(configuration: .ephemeral)
|
|
private let session = URLSession(configuration: .ephemeral)
|
|
|
|
|
|
|
|
- func searchJobs(query: String, completion: @escaping (Result<JobSearchOutput, Error>) -> Void) {
|
|
|
|
|
|
|
+ func searchJobs(query: String, conversation: [ChatMessage], completion: @escaping (Result<JobSearchOutput, Error>) -> Void) {
|
|
|
let apiKey = OpenAIConfiguration.apiKey
|
|
let apiKey = OpenAIConfiguration.apiKey
|
|
|
guard OpenAIConfiguration.hasAPIKey else {
|
|
guard OpenAIConfiguration.hasAPIKey else {
|
|
|
completion(.failure(NSError(
|
|
completion(.failure(NSError(
|
|
@@ -1573,8 +1574,25 @@ private final class OpenAIJobSearchService {
|
|
|
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
|
|
request.setValue("Bearer \(apiKey)", forHTTPHeaderField: "Authorization")
|
|
|
request.timeoutInterval = 45
|
|
request.timeoutInterval = 45
|
|
|
|
|
|
|
|
|
|
+ let recentContext = conversation.suffix(8)
|
|
|
|
|
+ .map { "\($0.role.uppercased()): \($0.content)" }
|
|
|
|
|
+ .joined(separator: "\n")
|
|
|
|
|
+ let contextBlock: String
|
|
|
|
|
+ if recentContext.isEmpty {
|
|
|
|
|
+ contextBlock = "No prior conversation context."
|
|
|
|
|
+ } else {
|
|
|
|
|
+ contextBlock = recentContext
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
let instructions = """
|
|
let instructions = """
|
|
|
- Search the web for currently available jobs related to this role query: "\(query)".
|
|
|
|
|
|
|
+ Continue this same job-search conversation. Use prior context when useful, and prioritize the latest user query.
|
|
|
|
|
+
|
|
|
|
|
+ Conversation context:
|
|
|
|
|
+ \(contextBlock)
|
|
|
|
|
+
|
|
|
|
|
+ Latest user query: "\(query)"
|
|
|
|
|
+
|
|
|
|
|
+ Search the web for currently available jobs related to the latest query (and relevant context above).
|
|
|
Return ONLY strict JSON that matches this schema:
|
|
Return ONLY strict JSON that matches this schema:
|
|
|
{
|
|
{
|
|
|
"jobs": [
|
|
"jobs": [
|