Skip to content

FIX: Preserve Responses API reasoning state - #162

Merged
merefield merged 19 commits into
mainfrom
chain_of_thought_improvements
Aug 1, 2026
Merged

FIX: Preserve Responses API reasoning state#162
merefield merged 19 commits into
mainfrom
chain_of_thought_improvements

Conversation

@merefield

@merefield merefield commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Previously, Responses API tool loops discarded ordered provider state and could treat incomplete or refused responses as successful blank replies.

This change preserves native response items for model continuation while exposing only readable reasoning summaries in the inner-thoughts trace. Reasoning-only turns are treated as intermediate state and continued until the model returns a message or tool call. It also validates Responses statuses across every call site, retains rejected URL responses during repair attempts, and replaces the transcript-length heuristic with bounded model, tool, and URL-repair iterations.

Compatible endpoints can disable reasoning summaries with the new chatbot_open_ai_include_reasoning_summaries setting. Chat Completions retain their existing output budget, Responses use a dedicated 25,000-token reasoning/output budget, and RAG loops have a 100,000-token aggregate threshold. Setting any per-call budget to 0 uses the provider default, while setting the aggregate threshold to 0 disables it. Usable partial text is returned, but truncated tool calls and reasoning runs with no visible output raise a specific token-budget error.

Token-budget and deterministic chain-limit failures are terminal job outcomes instead of retryable provider failures. Iteration, tool-count, URL-repair, and disabled-tool limits use typed non-retryable errors, while provider and malformed-response failures remain retryable. Reported usage is charged even when response validation fails, and users receive a localized explanation when a configured limit is reached.

Administrators can configure iteration, tool-call, and URL-repair limits through consistently named chatbot_chain_of_thought_max_* settings. Their defaults preserve the previous fixed limits, and URL repairs can be disabled by setting their limit to 0.

Reasoning summaries returned with an incomplete Responses result are preserved before terminal token-limit handling and carried into the job's inner-thought trace.

URL integrity validation now starts when a trusted tool establishes URL provenance, rather than after any second model iteration. Declared provenance and URLs present in any tool result are collected through one contract, while unrelated tools and reasoning-only continuations do not activate validation. Forum links must use the local hostname and a recognized topic/post path; external links are normalized before comparison so host casing, fragments, root paths, trailing slashes, and Markdown punctuation do not cause false mismatches. Length-limited partial responses are validated before being returned.

Malformed tool arguments are returned to the model as tool errors instead of escaping the chain and restarting the job. A successful image upload is returned directly only for a single paint/edit call, while mixed tool batches always continue with every result regardless of call order. Completed Responses messages with no visible text or refusal are rejected instead of creating blank replies.

Tests:

  • bin/rspec plugins/discourse-chatbot/spec — 148 examples, 0 failures
  • Current Discourse Syntax Tree formatter and RuboCop — clean
  • git diff --check and YAML parsing — clean

The plugin's standalone bin/lint --fix wrapper remains blocked by its existing lint bundle: syntax_tree is absent and its RuboCop Discourse version does not recognize the current core cops.

@merefield
merefield marked this pull request as ready for review August 1, 2026 21:38
@merefield
merefield requested a review from Copilot August 1, 2026 21:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the OpenAI “Responses API” integration for the chatbot by preserving provider-native response state across tool loops, validating response statuses, and introducing clearer/typed termination paths for token budgets and chain limits. It also refines URL integrity validation so it only activates once trusted provenance is established, and adds new admin settings for reasoning summaries and loop/token constraints.

Changes:

  • Preserve Responses API output items for continuation while exposing only reasoning summaries in the inner-thoughts trace, and treat reasoning-only turns as intermediate continuation state.
  • Replace heuristic loop termination with bounded iteration/tool/URL-repair limits plus aggregate token-budget enforcement, using typed non-retryable errors for deterministic stop conditions.
  • Improve URL integrity checking by collecting/normalizing trusted URL provenance from tool outputs, and validating/repairing URLs under controlled limits.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
spec/lib/bot/open_ai_bot_basic_spec.rb Adds coverage for Responses status handling, refusals, incomplete outputs, and provider-default token budgets.
spec/lib/bot/open_ai_agent_spec.rb Expands RAG coverage for reasoning summaries, continuation behavior, tool error handling, URL provenance/validation, and loop limits.
spec/lib/bot/bot_spec.rb Ensures quota consumption includes accumulated tokens even when responses fail.
spec/jobs/regular/chatbot_reply_spec.rb Verifies non-retryable failures return immediate localized replies (and include inner thoughts when enabled).
plugin.rb Bumps plugin version to 1.8.0.
lib/discourse_chatbot/post/post_reply_creator.rb Uses responses_text for reasoning-model title extraction with validation.
lib/discourse_chatbot/functions/escalate_to_staff_function.rb Uses responses_text for reasoning-model escalation title extraction with validation.
lib/discourse_chatbot/bots/open_ai_bot_rag.rb Implements preserved Responses context, reasoning-summary extraction, bounded loops/limits, improved URL provenance + validation, and tool error continuation.
lib/discourse_chatbot/bots/open_ai_bot_basic.rb Switches to shared completion-token limit helper and validated responses_text; normalizes token accounting.
lib/discourse_chatbot/bots/open_ai_bot_base.rb Adds typed non-retryable errors, Responses parameter/budget handling, Responses validation, and a shared completion-token limit helper.
lib/discourse_chatbot/bot.rb Moves quota consumption to an ensure block to charge usage even on failures.
config/settings.yml Adds new settings for reasoning summaries and chain/token/tool/url-repair limits; allows provider defaults via 0.
config/locales/server.en.yml Adds admin-facing descriptions for new settings and new localized terminal error messages.
app/jobs/regular/chatbot_reply.rb Treats token-budget/chain-limit errors as terminal (non-retryable) and posts localized replies.
app/controllers/discourse_chatbot/chatbot_controller.rb Uses validated responses_text and shared completion-token limit helper.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread spec/lib/bot/open_ai_agent_spec.rb
Comment thread lib/discourse_chatbot/bot.rb
@merefield
merefield merged commit d1fa2dc into main Aug 1, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants