Merge pull request #144 from CJackHwang/codex/refactor-codebase-to-remove-redundancy

Refactor tool-sieve and response streaming, remove unused helpers and UI wrappers
This commit is contained in:
CJACK.
2026-03-22 10:39:36 +08:00
committed by GitHub
17 changed files with 14 additions and 493 deletions

View File

@@ -24,7 +24,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
node-version: "24"
cache: "npm"
cache-dependency-path: webui/package-lock.json

View File

@@ -32,7 +32,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"
node-version: "24"
cache: "npm"
cache-dependency-path: webui/package-lock.json

View File

@@ -2,12 +2,6 @@ package openai
import "strings"
func applyOpenAIChatPassThrough(req map[string]any, payload map[string]any) {
for k, v := range collectOpenAIChatPassThrough(req) {
payload[k] = v
}
}
func (h *Handler) toolcallFeatureMatchEnabled() bool {
if h == nil || h.Store == nil {
return true

View File

@@ -32,7 +32,6 @@ type responsesStreamRuntime struct {
toolCallsDoneEmitted bool
sieve toolStreamSieveState
thinkingSieve toolStreamSieveState
thinking strings.Builder
text strings.Builder
visibleText strings.Builder
@@ -169,15 +168,6 @@ func (s *responsesStreamRuntime) logToolPolicyRejections(textParsed util.ToolCal
logRejected(textParsed, "text")
}
func (s *responsesStreamRuntime) hasFunctionCallDone() bool {
for _, done := range s.functionDone {
if done {
return true
}
}
return false
}
func (s *responsesStreamRuntime) onParsed(parsed sse.LineResult) streamengine.ParsedDecision {
if !parsed.Parsed {
return streamengine.ParsedDecision{}

View File

@@ -675,18 +675,3 @@ func extractAllSSEEventPayloads(body, targetEvent string) []map[string]any {
}
return out
}
func asFloat(v any) float64 {
switch x := v.(type) {
case float64:
return x
case float32:
return float64(x)
case int:
return float64(x)
case int64:
return float64(x)
default:
return 0
}
}

View File

@@ -1,288 +0,0 @@
package openai
import "strings"
func buildIncrementalToolDeltas(state *toolStreamSieveState) []toolCallDelta {
if state.disableDeltas {
return nil
}
captured := state.capture.String()
if captured == "" {
return nil
}
lower := strings.ToLower(captured)
keyIdx := strings.Index(lower, "tool_calls")
if keyIdx < 0 {
return nil
}
start := strings.LastIndex(captured[:keyIdx], "{")
if start < 0 {
return nil
}
certainSingle, hasMultiple := classifyToolCallsIncrementalSafety(captured, keyIdx)
if hasMultiple {
state.disableDeltas = true
return nil
}
if !certainSingle {
// In uncertain phases (e.g. first call arrived but array not closed yet),
// avoid speculative deltas and wait for final parsed tool_calls payload.
return nil
}
callStart, ok := findFirstToolCallObjectStart(captured, keyIdx)
if !ok {
return nil
}
deltas := make([]toolCallDelta, 0, 2)
if state.toolName == "" {
name, ok := extractToolCallName(captured, callStart)
if !ok || name == "" {
return nil
}
state.toolName = name
}
if state.toolArgsStart < 0 {
argsStart, stringMode, ok := findToolCallArgsStart(captured, callStart)
if ok {
state.toolArgsString = stringMode
if stringMode {
state.toolArgsStart = argsStart + 1
} else {
state.toolArgsStart = argsStart
}
state.toolArgsSent = state.toolArgsStart
}
}
if !state.toolNameSent {
if state.toolArgsStart < 0 {
return nil
}
state.toolNameSent = true
deltas = append(deltas, toolCallDelta{Index: 0, Name: state.toolName})
}
if state.toolArgsStart < 0 || state.toolArgsDone {
return deltas
}
end, complete, ok := scanToolCallArgsProgress(captured, state.toolArgsStart, state.toolArgsString)
if !ok {
return deltas
}
if end > state.toolArgsSent {
deltas = append(deltas, toolCallDelta{
Index: 0,
Arguments: captured[state.toolArgsSent:end],
})
state.toolArgsSent = end
}
if complete {
state.toolArgsDone = true
}
return deltas
}
func classifyToolCallsIncrementalSafety(text string, keyIdx int) (certainSingle bool, hasMultiple bool) {
arrStart, ok := findToolCallsArrayStart(text, keyIdx)
if !ok {
return false, false
}
i := skipSpaces(text, arrStart+1)
if i >= len(text) || text[i] != '{' {
return false, false
}
count := 0
depth := 0
quote := byte(0)
escaped := false
for ; i < len(text); i++ {
ch := text[i]
if quote != 0 {
if escaped {
escaped = false
continue
}
if ch == '\\' {
escaped = true
continue
}
if ch == quote {
quote = 0
}
continue
}
if ch == '"' || ch == '\'' {
quote = ch
continue
}
if ch == '{' {
if depth == 0 {
count++
if count > 1 {
return false, true
}
}
depth++
continue
}
if ch == '}' {
if depth > 0 {
depth--
}
continue
}
if ch == ',' && depth == 0 {
// top-level separator means at least one more tool call exists
// (or is expected). Treat as multi-call and stop incremental deltas.
return false, true
}
if ch == ']' && depth == 0 {
return count == 1, false
}
}
// array not closed yet: still uncertain whether more calls will appear
return false, false
}
func findFirstToolCallObjectStart(text string, keyIdx int) (int, bool) {
arrStart, ok := findToolCallsArrayStart(text, keyIdx)
if !ok {
return -1, false
}
i := skipSpaces(text, arrStart+1)
if i >= len(text) || text[i] != '{' {
return -1, false
}
return i, true
}
func findToolCallsArrayStart(text string, keyIdx int) (int, bool) {
i := keyIdx + len("tool_calls")
for i < len(text) && text[i] != ':' {
i++
}
if i >= len(text) {
return -1, false
}
i = skipSpaces(text, i+1)
if i >= len(text) || text[i] != '[' {
return -1, false
}
return i, true
}
func extractToolCallName(text string, callStart int) (string, bool) {
valueStart, ok := findObjectFieldValueStart(text, callStart, []string{"name"})
if !ok || valueStart >= len(text) || text[valueStart] != '"' {
fnStart, fnOK := findFunctionObjectStart(text, callStart)
if !fnOK {
return "", false
}
valueStart, ok = findObjectFieldValueStart(text, fnStart, []string{"name"})
if !ok || valueStart >= len(text) || text[valueStart] != '"' {
return "", false
}
}
name, _, ok := parseJSONStringLiteral(text, valueStart)
if !ok {
return "", false
}
return name, true
}
func findToolCallArgsStart(text string, callStart int) (int, bool, bool) {
keys := []string{"input", "arguments", "args", "parameters", "params"}
valueStart, ok := findObjectFieldValueStart(text, callStart, keys)
if !ok {
fnStart, fnOK := findFunctionObjectStart(text, callStart)
if !fnOK {
return -1, false, false
}
valueStart, ok = findObjectFieldValueStart(text, fnStart, keys)
if !ok {
return -1, false, false
}
}
if valueStart >= len(text) {
return -1, false, false
}
ch := text[valueStart]
if ch == '{' || ch == '[' {
return valueStart, false, true
}
if ch == '"' {
return valueStart, true, true
}
return -1, false, false
}
func scanToolCallArgsProgress(text string, start int, stringMode bool) (int, bool, bool) {
if start < 0 || start > len(text) {
return 0, false, false
}
if stringMode {
escaped := false
for i := start; i < len(text); i++ {
ch := text[i]
if escaped {
escaped = false
continue
}
if ch == '\\' {
escaped = true
continue
}
if ch == '"' {
return i, true, true
}
}
return len(text), false, true
}
if start >= len(text) {
return start, false, false
}
if text[start] != '{' && text[start] != '[' {
return 0, false, false
}
depth := 0
quote := byte(0)
escaped := false
for i := start; i < len(text); i++ {
ch := text[i]
if quote != 0 {
if escaped {
escaped = false
continue
}
if ch == '\\' {
escaped = true
continue
}
if ch == quote {
quote = 0
}
continue
}
if ch == '"' || ch == '\'' {
quote = ch
continue
}
if ch == '{' || ch == '[' {
depth++
continue
}
if ch == '}' || ch == ']' {
depth--
if depth == 0 {
return i + 1, true, true
}
}
}
return len(text), false, true
}
func findFunctionObjectStart(text string, callStart int) (int, bool) {
valueStart, ok := findObjectFieldValueStart(text, callStart, []string{"function"})
if !ok || valueStart >= len(text) || text[valueStart] != '{' {
return -1, false
}
return valueStart, true
}

View File

@@ -1,7 +1,5 @@
package openai
import "strings"
func extractJSONObjectFrom(text string, start int) (string, int, bool) {
if start < 0 || start >= len(text) || text[start] != '{' {
return "", 0, false
@@ -43,110 +41,3 @@ func extractJSONObjectFrom(text string, start int) (string, int, bool) {
}
return "", 0, false
}
func findObjectFieldValueStart(text string, objStart int, keys []string) (int, bool) {
if objStart < 0 || objStart >= len(text) || text[objStart] != '{' {
return 0, false
}
depth := 0
quote := byte(0)
escaped := false
for i := objStart; i < len(text); i++ {
ch := text[i]
if quote != 0 {
if escaped {
escaped = false
continue
}
if ch == '\\' {
escaped = true
continue
}
if ch == quote {
quote = 0
}
continue
}
if ch == '"' || ch == '\'' {
if depth == 1 {
key, end, ok := parseJSONStringLiteral(text, i)
if !ok {
return 0, false
}
j := skipSpaces(text, end)
if j >= len(text) || text[j] != ':' {
i = end - 1
continue
}
j = skipSpaces(text, j+1)
if j >= len(text) {
return 0, false
}
if containsKey(keys, key) {
return j, true
}
i = j - 1
continue
}
quote = ch
continue
}
if ch == '{' {
depth++
continue
}
if ch == '}' {
depth--
if depth == 0 {
break
}
}
}
return 0, false
}
func parseJSONStringLiteral(text string, start int) (string, int, bool) {
if start < 0 || start >= len(text) || text[start] != '"' {
return "", 0, false
}
var b strings.Builder
escaped := false
for i := start + 1; i < len(text); i++ {
ch := text[i]
if escaped {
b.WriteByte(ch)
escaped = false
continue
}
if ch == '\\' {
escaped = true
continue
}
if ch == '"' {
return b.String(), i + 1, true
}
b.WriteByte(ch)
}
return "", 0, false
}
func containsKey(keys []string, value string) bool {
for _, k := range keys {
if k == value {
return true
}
}
return false
}
func skipSpaces(text string, i int) int {
for i < len(text) {
switch text[i] {
case ' ', '\t', '\n', '\r':
i++
default:
return i
}
}
return i
}

View File

@@ -63,14 +63,3 @@ func appendTail(prev, next string, max int) string {
}
return combined[len(combined)-max:]
}
func looksLikeToolExampleContext(text string) bool {
return insideCodeFence(text)
}
func insideCodeFence(text string) bool {
if text == "" {
return false
}
return strings.Count(text, "```")%2 == 1
}

View File

@@ -63,17 +63,6 @@ func (c *Client) postJSONWithStatus(ctx context.Context, doer trans.Doer, url st
return out, resp.StatusCode, nil
}
func (c *Client) getJSON(ctx context.Context, doer trans.Doer, url string, headers map[string]string) (map[string]any, error) {
body, status, err := c.getJSONWithStatus(ctx, doer, url, headers)
if err != nil {
return nil, err
}
if status == 0 {
return nil, errors.New("request failed")
}
return body, nil
}
func (c *Client) getJSONWithStatus(ctx context.Context, doer trans.Doer, url string, headers map[string]string) (map[string]any, int, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {

View File

@@ -7,7 +7,6 @@ import (
var toolCallPattern = regexp.MustCompile(`\{\s*["']tool_calls["']\s*:\s*\[(.*?)\]\s*\}`)
var fencedJSONPattern = regexp.MustCompile("(?s)```(?:json)?\\s*(.*?)\\s*```")
var fencedBlockPattern = regexp.MustCompile("(?s)```.*?```")
func buildToolCallCandidates(text string) []string {
trimmed := strings.TrimSpace(text)
@@ -82,12 +81,12 @@ func extractToolCallObjects(text string) []string {
if searchLimit < offset {
searchLimit = offset
}
start := strings.LastIndex(text[searchLimit:idx], "{")
if start >= 0 {
start += searchLimit
}
if start < 0 {
offset = idx + len(matchedKeyword)
continue
@@ -113,7 +112,7 @@ func extractToolCallObjects(text string) []string {
}
break
}
if !foundObj {
offset = idx + len(matchedKeyword)
}
@@ -174,10 +173,3 @@ func looksLikeToolExampleContext(text string) bool {
}
return strings.Contains(t, "```")
}
func stripFencedCodeBlocks(text string) string {
if strings.TrimSpace(text) == "" {
return ""
}
return fencedBlockPattern.ReplaceAllString(text, " ")
}

View File

@@ -53,7 +53,6 @@ internal/adapter/openai/responses_stream_runtime_events.go
internal/adapter/openai/responses_stream_runtime_toolcalls.go
internal/adapter/openai/tool_sieve_state.go
internal/adapter/openai/tool_sieve_core.go
internal/adapter/openai/tool_sieve_incremental.go
internal/adapter/openai/tool_sieve_jsonscan.go
internal/util/toolcalls_parse.go
@@ -117,7 +116,6 @@ webui/src/app/useAdminAuth.js
webui/src/app/useAdminConfig.js
webui/src/layout/DashboardShell.jsx
webui/src/components/AccountManager.jsx
webui/src/features/account/AccountManagerContainer.jsx
webui/src/features/account/useAccountsData.js
webui/src/features/account/useAccountActions.js
@@ -127,14 +125,12 @@ webui/src/features/account/AccountsTable.jsx
webui/src/features/account/AddKeyModal.jsx
webui/src/features/account/AddAccountModal.jsx
webui/src/components/ApiTester.jsx
webui/src/features/apiTester/ApiTesterContainer.jsx
webui/src/features/apiTester/useApiTesterState.js
webui/src/features/apiTester/useChatStreamClient.js
webui/src/features/apiTester/ConfigPanel.jsx
webui/src/features/apiTester/ChatPanel.jsx
webui/src/components/Settings.jsx
webui/src/features/settings/SettingsContainer.jsx
webui/src/features/settings/useSettingsForm.js
webui/src/features/settings/settingsApi.js
@@ -144,7 +140,6 @@ webui/src/features/settings/BehaviorSection.jsx
webui/src/features/settings/ModelSection.jsx
webui/src/features/settings/BackupSection.jsx
webui/src/components/VercelSync.jsx
webui/src/features/vercel/VercelSyncContainer.jsx
webui/src/features/vercel/useVercelSyncState.js
webui/src/features/vercel/VercelSyncForm.jsx

View File

@@ -12,11 +12,7 @@ is_entry_file() {
case "$1" in
api/chat-stream.js|\
internal/js/helpers/stream-tool-sieve.js|\
webui/src/App.jsx|\
webui/src/components/AccountManager.jsx|\
webui/src/components/ApiTester.jsx|\
webui/src/components/Settings.jsx|\
webui/src/components/VercelSync.jsx)
webui/src/App.jsx)
return 0
;;
esac

View File

@@ -1,3 +0,0 @@
import AccountManagerContainer from '../features/account/AccountManagerContainer'
export default AccountManagerContainer

View File

@@ -1,3 +0,0 @@
import ApiTesterContainer from '../features/apiTester/ApiTesterContainer'
export default ApiTesterContainer

View File

@@ -1,3 +0,0 @@
import SettingsContainer from '../features/settings/SettingsContainer'
export default SettingsContainer

View File

@@ -1,3 +0,0 @@
import VercelSyncContainer from '../features/vercel/VercelSyncContainer'
export default VercelSyncContainer

View File

@@ -12,11 +12,11 @@ import {
} from 'lucide-react'
import clsx from 'clsx'
import AccountManager from '../components/AccountManager'
import ApiTester from '../components/ApiTester'
import AccountManagerContainer from '../features/account/AccountManagerContainer'
import ApiTesterContainer from '../features/apiTester/ApiTesterContainer'
import BatchImport from '../components/BatchImport'
import VercelSync from '../components/VercelSync'
import Settings from '../components/Settings'
import VercelSyncContainer from '../features/vercel/VercelSyncContainer'
import SettingsContainer from '../features/settings/SettingsContainer'
import LanguageToggle from '../components/LanguageToggle'
import { useI18n } from '../i18n'
@@ -73,15 +73,15 @@ export default function DashboardShell({ token, onLogout, config, fetchConfig, s
const renderTab = () => {
switch (activeTab) {
case 'accounts':
return <AccountManager config={config} onRefresh={fetchConfig} onMessage={showMessage} authFetch={authFetch} />
return <AccountManagerContainer config={config} onRefresh={fetchConfig} onMessage={showMessage} authFetch={authFetch} />
case 'test':
return <ApiTester config={config} onMessage={showMessage} authFetch={authFetch} />
return <ApiTesterContainer config={config} onMessage={showMessage} authFetch={authFetch} />
case 'import':
return <BatchImport onRefresh={fetchConfig} onMessage={showMessage} authFetch={authFetch} />
case 'vercel':
return <VercelSync onMessage={showMessage} authFetch={authFetch} isVercel={isVercel} config={config} />
return <VercelSyncContainer onMessage={showMessage} authFetch={authFetch} isVercel={isVercel} config={config} />
case 'settings':
return <Settings onRefresh={fetchConfig} onMessage={showMessage} authFetch={authFetch} onForceLogout={onForceLogout} isVercel={isVercel} />
return <SettingsContainer onRefresh={fetchConfig} onMessage={showMessage} authFetch={authFetch} onForceLogout={onForceLogout} isVercel={isVercel} />
default:
return null
}