Skip to content

Fix/reasoning close only#10

Open
chay2199 wants to merge 3 commits into
masterfrom
fix/reasoning-close-only
Open

Fix/reasoning close only#10
chay2199 wants to merge 3 commits into
masterfrom
fix/reasoning-close-only

Conversation

@chay2199
Copy link
Copy Markdown

@chay2199 chay2199 commented Jun 6, 2026

Description

This PR fixes #

Notes for Reviewers

Signed commits

  • Yes, I signed my commits.

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
@codity-chait
Copy link
Copy Markdown

codity-chait Bot commented Jun 6, 2026

PR Summary

What Changed

  • Moved reasoning extraction from pkg/functions into a new pkg/reasoning module to separate parsing logic and make chat integration cleaner.
  • Added model-aware reasoning parsing for multiple tag formats, including closing-only and unclosed tag cases, to handle more real model outputs.
  • Added forced-open reasoning mode via config and prompt-suffix detection so outputs without opening tags are still parsed correctly in streaming and non-streaming paths.

Key Changes by Area

  • Configuration: Added ReasoningConfig with ThinkingForcedOpen so behavior can be controlled per model.
  • Chat API: Wired chat endpoint reasoning handling to the new reasoning module and config.
  • Reasoning Parsing: Added Extract(...), model-specific tag support, forced-open options, and improved splitting when output starts with reasoning before a closing tag.
  • Tests: Expanded coverage for nested, unclosed, empty, mismatched, special-character, and closing-only reasoning outputs.

Files Changed

File Changes Summary
core/config/model_config.go Added per-model reasoning config, including forced-open setting.
core/http/endpoints/openai/chat.go Switched chat reasoning flow to use new reasoning module and config.
pkg/functions/reasoning.go Removed or reduced old reasoning extraction logic after module move.
pkg/functions/reasoning_test.go Updated legacy tests to reflect reasoning logic relocation.
pkg/reasoning/config.go Added reasoning config types for module behavior control.
pkg/reasoning/options.go Added functional options, including forced-open handling.
pkg/reasoning/reasoning.go Implemented core extraction logic with model-specific tags and closing-only handling.
pkg/reasoning/reasoning_suite_test.go Added test suite setup for new reasoning package.
pkg/reasoning/reasoning_test.go Added broad coverage for tag variants, forced-open mode, and streaming-related cases.

Review Focus Areas

  • Confirm behavior when content starts with reasoning and only includes a closing tag, especially split boundaries.
  • Check forced-open detection and ThinkingForcedOpen precedence across prompt detection vs config.
  • Verify chat endpoint behavior parity after moving logic from pkg/functions to pkg/reasoning.

Architecture

  • Design Decisions: The PR isolates reasoning parsing into pkg/reasoning and makes behavior configurable per model, which reduces coupling with chat handlers and supports model-specific output formats.
  • Scalability & Extensibility: Adding model-specific tags and options in one module improves reuse when new model formats are added.
  • Risks: There is behavior risk around parsing edge cases in mixed content streams, especially where forced-open mode and closing-only tags interact. This looks intentional to support known model outputs but needs close verification.

Comment on lines +102 to +110
additionalReasoning, finalContent := extractFromTags(cleanedContent)
if additionalReasoning != "" {
if reasoning != "" {
reasoning = reasoning + "\n\n" + additionalReasoning
} else {
reasoning = additionalReasoning
}
}
cleanedContent = finalContent
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Functional Medium

With WithThinkingForcedOpen(), the post-close remainder is reparsed by extractFromTags, which treats closing-only tags as reasoning blocks. This incorrectly reclassifies normal response content as reasoning when the remainder contains a stray closing tag, and removes that content from cleanedContent. Concrete failing case: "Reasoning</think>content</thinking>more" currently returns reasoning "Reasoning\n\ncontent" instead of "Reasoning", matching the failing test in pkg/reasoning/reasoning_test.go (should find earliest closing tag).

Suggested fix
		if strings.Contains(cleanedContent, "<thinking>") ||
			strings.Contains(cleanedContent, "<think>") ||
			strings.Contains(cleanedContent, "<|START_THINKING|>") ||
			strings.Contains(cleanedContent, "<|inner_prefix|>") ||
			strings.Contains(cleanedContent, "<seed:think>") ||
			strings.Contains(cleanedContent, "[THINK]") {
			additionalReasoning, finalContent := extractFromTags(cleanedContent)
			if additionalReasoning != "" {
				if reasoning != "" {
					reasoning = reasoning + "\n\n" + additionalReasoning
				} else {
					reasoning = additionalReasoning
				}
			}
			cleanedContent = finalContent
		}
Prompt for AI assistance

Copy the prompt below and paste it into ChatGPT, Claude, or any LLM:

You are an expert bash developer with deep knowledge of security, performance, and best practices.

### Context

File: pkg/reasoning/reasoning.go
Lines: 102-110
Issue Type: functional-medium
Severity: medium

Issue Description:
With `WithThinkingForcedOpen()`, the post-close remainder is reparsed by `extractFromTags`, which treats closing-only tags as reasoning blocks. This incorrectly reclassifies normal response content as reasoning when the remainder contains a stray closing tag, and removes that content from `cleanedContent`. Concrete failing case: `"Reasoning</think>content</thinking>more"` currently returns reasoning `"Reasoning\n\ncontent"` instead of `"Reasoning"`, matching the failing test in `pkg/reasoning/reasoning_test.go` (`should find earliest closing tag`).

Current Code:
		additionalReasoning, finalContent := extractFromTags(cleanedContent)
		if additionalReasoning != "" {
			if reasoning != "" {
				reasoning = reasoning + "\n\n" + additionalReasoning
			} else {
				reasoning = additionalReasoning
			}
		}
		cleanedContent = finalContent

---

### Instructions

1. Fix the issue described above
2. Maintain the exact indentation and code style from the original
3. Follow bash best practices and language-specific idioms
4. Ensure the fix addresses the root cause, not just the symptoms
5. Add brief inline comments explaining the fix if needed

### Constraints

- Do not change functionality beyond fixing the identified issue
- Preserve existing variable names and function signatures unless they are part of the problem
- Ensure the fix is production-ready

---


Like Dislike Create Issue

@codity-chait
Copy link
Copy Markdown

codity-chait Bot commented Jun 6, 2026

License Compliance Scan

Metric Value
Packages Scanned 334
High Risk (Strong Copyleft) 0
Medium Risk (Weak Copyleft) 4
Low Risk (Permissive) 263
Unknown License 67

Weak copyleft licenses found - verify compatibility

Some packages have unknown licenses - manual review required

Medium Risk Licenses - 4 packages

MPL-2.0 (4 packages):

  • github.com/libp2p/go-yamux/v5 5.0.1
  • github.com/hashicorp/golang-lru 1.0.2
  • github.com/hashicorp/golang-lru/v2 2.0.7
  • github.com/shoenig/go-m1cpu 0.1.6
Unknown Licenses - 67 packages
  • github.com/prometheus/otlptranslator 1.0.0
  • github.com/rymdport/portal 0.4.2
  • github.com/srwiley/oksvg 0.0.0-20221011165216-be6e8873101c
  • github.com/wlynxg/anet 0.0.5
  • github.com/srwiley/rasterx 0.0.0-20220730225603-2ab79fcdd4ef
  • github.com/yosida95/uritemplate/v3 3.0.2
  • github.com/Masterminds/goutils 1.1.1
  • github.com/Masterminds/semver/v3 3.4.0
  • github.com/containerd/errdefs 1.0.0
  • github.com/andybalholm/brotli 1.2.0
  • github.com/alecthomas/chroma/v2 2.14.0
  • github.com/beorn7/perks 1.0.1
  • github.com/containerd/cgroups 1.1.0
  • github.com/containerd/continuity 0.4.4
  • github.com/containerd/log 0.1.0
  • github.com/containerd/stargz-snapshotter/estargz 0.18.1
  • github.com/creachadair/otp 0.5.0
  • github.com/davidlazar/go-crypto 0.0.0-20200604182044-b73af7476f6c
  • github.com/docker/cli 29.0.3+incompatible
  • github.com/docker/docker 28.5.2+incompatible

...and 47 more

Powered by Codity.ai · Docs

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