Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.

Commit e450111

Browse files
committed
correct subtle multi threading issues
1 parent f683d69 commit e450111

File tree

4 files changed

+32
-14
lines changed

4 files changed

+32
-14
lines changed

app/controllers/discourse_ai/admin/ai_personas_controller.rb

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,11 @@ def queue_reply(&block)
9090

9191
db = RailsMultisite::ConnectionManagement.current_db
9292
thread_pool.post do
93-
RailsMultisite::ConnectionManagement.with_connection(db) { block.call }
93+
begin
94+
RailsMultisite::ConnectionManagement.with_connection(db) { block.call }
95+
rescue StandardError => e
96+
Discourse.warn_exception(e, message: "Discourse AI: Unable to stream reply")
97+
end
9498
end
9599
end
96100
end
@@ -157,7 +161,7 @@ def stream_reply
157161
PostCreator.create!(
158162
user,
159163
title: I18n.t("discourse_ai.ai_bot.default_pm_prefix"),
160-
raw: params[:question],
164+
raw: params[:query],
161165
archetype: Archetype.private_message,
162166
target_usernames: "#{user.username},#{persona.user.username}",
163167
skip_validations: true,
@@ -175,16 +179,18 @@ def stream_reply
175179
begin
176180
io.write "HTTP/1.1 200 OK"
177181
io.write CRLF
178-
io.write "Content-Type: application/json"
182+
io.write "Content-Type: text/plain; charset=utf-8"
179183
io.write CRLF
180184
io.write "Transfer-Encoding: chunked"
181185
io.write CRLF
182186
io.write "Cache-Control: no-cache, no-store, must-revalidate"
183187
io.write CRLF
184-
io.write "Connection: keep-alive"
188+
io.write "Connection: close"
185189
io.write CRLF
186190
io.write "X-Accel-Buffering: no"
187191
io.write CRLF
192+
io.write "X-Content-Type-Options: nosniff"
193+
io.write CRLF
188194
io.write CRLF
189195
io.flush
190196

@@ -202,31 +208,33 @@ def stream_reply
202208
io.write data
203209
io.write CRLF
204210

205-
io.flush
206-
207211
DiscourseAi::AiBot::Playground
208212
.new(bot)
209213
.reply_to(post) do |partial|
214+
next if partial.length == 0
215+
210216
data = { partial: partial }.to_json + "\n\n"
211217

218+
data.force_encoding("UTF-8")
219+
212220
io.write data.bytesize.to_s(16)
213221
io.write CRLF
214222
io.write data
215223
io.write CRLF
216-
217224
io.flush
218225
end
219226

220-
# End the response with zero-length chunk
221227
io.write "0"
222228
io.write CRLF
223229
io.write CRLF
230+
224231
io.flush
232+
io.done
225233
rescue StandardError => e
226-
p e
227-
puts e.backtrace
228-
rescue IOError => e
229-
Rails.logger.error "Streaming error: #{e.message}"
234+
# make it a tiny bit easier to debug in dev, this is tricky
235+
# multi-threaded code that exhibits various limitations in rails
236+
p e if Rails.env.development?
237+
Discourse.warn_exception(e, message: "Discourse AI: Unable to stream reply")
230238
ensure
231239
io.close
232240
end

config/locales/server.en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ en:
169169
failed_to_share: "Failed to share the conversation"
170170
conversation_deleted: "Conversation share deleted successfully"
171171
ai_bot:
172+
default_pm_prefix: "[Untitled AI bot PM]"
172173
personas:
173174
default_llm_required: "Default LLM model is required prior to enabling Chat"
174175
cannot_delete_system_persona: "System personas cannot be deleted, please disable it instead"

lib/ai_bot/playground.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,11 @@ def get_context(participants:, conversation_context:, user:, skip_tool_details:
391391
end
392392

393393
def reply_to(post, &blk)
394+
# this is a multithreading issue
395+
# post custom prompt is needed and it may not
396+
# be properly loaded, ensure it is loaded
397+
PostCustomPrompt.none
398+
394399
reply = +""
395400
start = Time.now
396401

spec/requests/admin/ai_personas_controller_spec.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,11 +456,12 @@ def validate_streamed_response(raw_http, expected)
456456

457457
preamble = (<<~PREAMBLE).strip
458458
HTTP/1.1 200 OK
459-
Content-Type: application/json
459+
Content-Type: text/plain; charset=utf-8
460460
Transfer-Encoding: chunked
461461
Cache-Control: no-cache, no-store, must-revalidate
462-
Connection: keep-alive
462+
Connection: close
463463
X-Accel-Buffering: no
464+
X-Content-Type-Options: nosniff
464465
PREAMBLE
465466

466467
expect(header_lines.join("\n")).to eq(preamble)
@@ -522,6 +523,9 @@ def validate_streamed_response(raw_http, expected)
522523
last_post = topic.posts.order(:created_at).last
523524
expect(last_post.raw).to eq("This is a test! Testing!")
524525

526+
user_post = topic.posts.find_by(post_number: 1)
527+
expect(user_post.raw).to eq("how are you today?")
528+
525529
# need ai persona and user
526530
expect(topic.topic_allowed_users.count).to eq(2)
527531
expect(topic.archetype).to eq(Archetype.private_message)

0 commit comments

Comments
 (0)