Skip to content

Commit 26f595d

Browse files
Refactor OpenAI-compatible provider execution into shared core
Consolidate OpenAI-compatible API request handling into a single shared module and route background dispatch through provider registry lookup. This removes duplicated streaming/parsing logic from openai-api and custom-api while keeping existing behavior. Add config migration to preserve existing API keys and custom mode entries by mapping them into providerSecrets and custom provider records. Keep legacy fallbacks for apiMode customUrl/custom apiKey to avoid user-visible regressions during rollout. Normalize apiMode objects at runtime and compare selection using stable identity fields so migrated and legacy session data continue to match correctly.
1 parent c236a4b commit 26f595d

25 files changed

+7797
-565
lines changed

src/background/index.mjs

Lines changed: 19 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,10 @@ import {
55
sendMessageFeedback,
66
} from '../services/apis/chatgpt-web'
77
import { generateAnswersWithBingWebApi } from '../services/apis/bing-web.mjs'
8-
import {
9-
generateAnswersWithOpenAiApi,
10-
generateAnswersWithGptCompletionApi,
11-
} from '../services/apis/openai-api'
12-
import { generateAnswersWithCustomApi } from '../services/apis/custom-api.mjs'
13-
import { generateAnswersWithOllamaApi } from '../services/apis/ollama-api.mjs'
8+
import { generateAnswersWithOpenAICompatibleApi } from '../services/apis/openai-api'
149
import { generateAnswersWithAzureOpenaiApi } from '../services/apis/azure-openai-api.mjs'
1510
import { generateAnswersWithClaudeApi } from '../services/apis/claude-api.mjs'
16-
import { generateAnswersWithChatGLMApi } from '../services/apis/chatglm-api.mjs'
1711
import { generateAnswersWithWaylaidwandererApi } from '../services/apis/waylaidwanderer-api.mjs'
18-
import { generateAnswersWithOpenRouterApi } from '../services/apis/openrouter-api.mjs'
19-
import { generateAnswersWithAimlApi } from '../services/apis/aiml-api.mjs'
2012
import {
2113
defaultConfig,
2214
getUserConfig,
@@ -52,10 +44,8 @@ import { refreshMenu } from './menus.mjs'
5244
import { registerCommands } from './commands.mjs'
5345
import { generateAnswersWithBardWebApi } from '../services/apis/bard-web.mjs'
5446
import { generateAnswersWithClaudeWebApi } from '../services/apis/claude-web.mjs'
55-
import { generateAnswersWithMoonshotCompletionApi } from '../services/apis/moonshot-api.mjs'
5647
import { generateAnswersWithMoonshotWebApi } from '../services/apis/moonshot-web.mjs'
5748
import { isUsingModelName } from '../utils/model-name-convert.mjs'
58-
import { generateAnswersWithDeepSeekApi } from '../services/apis/deepseek-api.mjs'
5949
import { redactSensitiveFields } from './redact.mjs'
6050

6151
const RECONNECT_CONFIG = {
@@ -345,6 +335,20 @@ function setPortProxy(port, proxyTabId) {
345335
}
346336
}
347337

338+
function isUsingOpenAICompatibleApiSession(session) {
339+
return (
340+
isUsingCustomModel(session) ||
341+
isUsingChatgptApiModel(session) ||
342+
isUsingMoonshotApiModel(session) ||
343+
isUsingChatGLMApiModel(session) ||
344+
isUsingDeepSeekApiModel(session) ||
345+
isUsingOllamaApiModel(session) ||
346+
isUsingOpenRouterApiModel(session) ||
347+
isUsingAimlApiModel(session) ||
348+
isUsingGptCompletionApiModel(session)
349+
)
350+
}
351+
348352
async function executeApi(session, port, config) {
349353
console.log(
350354
`[background] executeApi called for model: ${session.modelName}, apiMode: ${session.apiMode}`,
@@ -360,29 +364,7 @@ async function executeApi(session, port, config) {
360364
)
361365
}
362366
try {
363-
if (isUsingCustomModel(session)) {
364-
console.debug('[background] Using Custom Model API')
365-
if (!session.apiMode)
366-
await generateAnswersWithCustomApi(
367-
port,
368-
session.question,
369-
session,
370-
config.customModelApiUrl.trim() || 'http://localhost:8000/v1/chat/completions',
371-
config.customApiKey,
372-
config.customModelName,
373-
)
374-
else
375-
await generateAnswersWithCustomApi(
376-
port,
377-
session.question,
378-
session,
379-
session.apiMode.customUrl?.trim() ||
380-
config.customModelApiUrl.trim() ||
381-
'http://localhost:8000/v1/chat/completions',
382-
session.apiMode.apiKey?.trim() || config.customApiKey,
383-
session.apiMode.customName,
384-
)
385-
} else if (isUsingChatgptWebModel(session)) {
367+
if (isUsingChatgptWebModel(session)) {
386368
console.debug('[background] Using ChatGPT Web Model')
387369
let tabId
388370
if (
@@ -507,46 +489,15 @@ async function executeApi(session, port, config) {
507489
console.debug('[background] Using Gemini Web Model')
508490
const cookies = await getBardCookies()
509491
await generateAnswersWithBardWebApi(port, session.question, session, cookies)
510-
} else if (isUsingChatgptApiModel(session)) {
511-
console.debug('[background] Using OpenAI API Model')
512-
await generateAnswersWithOpenAiApi(port, session.question, session, config.apiKey)
492+
} else if (isUsingOpenAICompatibleApiSession(session)) {
493+
console.debug('[background] Using OpenAI-compatible API provider')
494+
await generateAnswersWithOpenAICompatibleApi(port, session.question, session, config)
513495
} else if (isUsingClaudeApiModel(session)) {
514496
console.debug('[background] Using Anthropic API Model')
515497
await generateAnswersWithClaudeApi(port, session.question, session)
516-
} else if (isUsingMoonshotApiModel(session)) {
517-
console.debug('[background] Using Moonshot API Model')
518-
await generateAnswersWithMoonshotCompletionApi(
519-
port,
520-
session.question,
521-
session,
522-
config.moonshotApiKey,
523-
)
524-
} else if (isUsingChatGLMApiModel(session)) {
525-
console.debug('[background] Using ChatGLM API Model')
526-
await generateAnswersWithChatGLMApi(port, session.question, session)
527-
} else if (isUsingDeepSeekApiModel(session)) {
528-
console.debug('[background] Using DeepSeek API Model')
529-
await generateAnswersWithDeepSeekApi(port, session.question, session, config.deepSeekApiKey)
530-
} else if (isUsingOllamaApiModel(session)) {
531-
console.debug('[background] Using Ollama API Model')
532-
await generateAnswersWithOllamaApi(port, session.question, session)
533-
} else if (isUsingOpenRouterApiModel(session)) {
534-
console.debug('[background] Using OpenRouter API Model')
535-
await generateAnswersWithOpenRouterApi(
536-
port,
537-
session.question,
538-
session,
539-
config.openRouterApiKey,
540-
)
541-
} else if (isUsingAimlApiModel(session)) {
542-
console.debug('[background] Using AIML API Model')
543-
await generateAnswersWithAimlApi(port, session.question, session, config.aimlApiKey)
544498
} else if (isUsingAzureOpenAiApiModel(session)) {
545499
console.debug('[background] Using Azure OpenAI API Model')
546500
await generateAnswersWithAzureOpenaiApi(port, session.question, session)
547-
} else if (isUsingGptCompletionApiModel(session)) {
548-
console.debug('[background] Using GPT Completion API Model')
549-
await generateAnswersWithGptCompletionApi(port, session.question, session, config.apiKey)
550501
} else if (isUsingGithubThirdPartyApiModel(session)) {
551502
console.debug('[background] Using Github Third Party API Model')
552503
await generateAnswersWithWaylaidwandererApi(port, session.question, session)

src/components/ConversationCard/index.jsx

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
apiModeToModelName,
88
createElementAtPosition,
99
getApiModesFromConfig,
10-
isApiModeSelected,
10+
getUniquelySelectedApiModeIndex,
1111
isFirefox,
1212
isMobile,
1313
isSafari,
@@ -38,6 +38,7 @@ import { generateAnswersWithBingWebApi } from '../../services/apis/bing-web.mjs'
3838
import { handlePortError } from '../../services/wrappers.mjs'
3939

4040
const logo = Browser.runtime.getURL('logo.png')
41+
const UNMATCHED_API_MODE_VALUE = '__current-session-api-mode__'
4142

4243
class ConversationItemData extends Object {
4344
/**
@@ -67,9 +68,36 @@ function ConversationCard(props) {
6768

6869
/**
6970
* @type {[ConversationItemData[], (conversationItemData: ConversationItemData[]) => void]}
70-
*/
71+
*/
7172
const [conversationItemData, setConversationItemData] = useState([])
7273
const config = useConfig()
74+
const currentAiName =
75+
session.aiName ||
76+
modelNameToDesc(
77+
session.apiMode && typeof session.apiMode === 'object'
78+
? apiModeToModelName(session.apiMode)
79+
: session.modelName,
80+
t,
81+
config.customModelName,
82+
) ||
83+
t(Models.customModel.desc)
84+
const selectedApiModeIndex = useMemo(
85+
() => getUniquelySelectedApiModeIndex(apiModes, session, { sessionCompat: true }),
86+
[apiModes, session],
87+
)
88+
const selectedApiModeDesc =
89+
selectedApiModeIndex !== -1
90+
? modelNameToDesc(
91+
apiModeToModelName(apiModes[selectedApiModeIndex]),
92+
t,
93+
config.customModelName,
94+
)
95+
: ''
96+
const selectedApiModeValue = selectedApiModeDesc
97+
? String(selectedApiModeIndex)
98+
: !session.apiMode && session.modelName === 'customModel'
99+
? '-1'
100+
: UNMATCHED_API_MODE_VALUE
73101

74102
useLayoutEffect(() => {
75103
if (session.conversationRecords.length === 0) {
@@ -379,11 +407,16 @@ function ConversationCard(props) {
379407
style={props.notClampSize ? {} : { width: 0, flexGrow: 1 }}
380408
className="normal-button"
381409
required
410+
value={selectedApiModeValue}
382411
onChange={(e) => {
412+
if (e.target.value === UNMATCHED_API_MODE_VALUE) return
413+
383414
let apiMode = null
384415
let modelName = 'customModel'
385416
if (e.target.value !== '-1') {
386-
apiMode = apiModes[e.target.value]
417+
const selectedApiMode = apiModes[Number(e.target.value)]
418+
if (!selectedApiMode) return
419+
apiMode = selectedApiMode
387420
modelName = apiModeToModelName(apiMode)
388421
}
389422
const newSession = {
@@ -401,20 +434,23 @@ function ConversationCard(props) {
401434
else setSession(newSession)
402435
}}
403436
>
437+
{selectedApiModeValue === UNMATCHED_API_MODE_VALUE && (
438+
<option value={UNMATCHED_API_MODE_VALUE} disabled>
439+
{currentAiName}
440+
</option>
441+
)}
404442
{apiModes.map((apiMode, index) => {
405443
const modelName = apiModeToModelName(apiMode)
406444
const desc = modelNameToDesc(modelName, t, config.customModelName)
407445
if (desc) {
408446
return (
409-
<option value={index} key={index} selected={isApiModeSelected(apiMode, session)}>
447+
<option value={index} key={index}>
410448
{desc}
411449
</option>
412450
)
413451
}
414452
})}
415-
<option value={-1} selected={!session.apiMode && session.modelName === 'customModel'}>
416-
{t(Models.customModel.desc)}
417-
</option>
453+
<option value={-1}>{t(Models.customModel.desc)}</option>
418454
</select>
419455
</span>
420456
{props.draggable && !completeDraggable && (

0 commit comments

Comments
 (0)