mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-23 16:55:51 +00:00
refactor: 将 codex provider 转换工具迁移至 @ant/model-provider 包
将纯转换工具(callIds、modelMapping、convertMessages、convertTools) 从 src/services/api/codex/ 迁移到 packages/@ant/model-provider/src/providers/codex/, 与 OpenAI/Gemini/Grok provider 保持一致的代码组织模式。同时修复了 streaming.test.ts 中缺失的 mock 导出(logAntError、context 常量、langfuse 导出)。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -61,3 +61,10 @@ export { anthropicMessagesToOpenAI } from './shared/openaiConvertMessages.js'
|
|||||||
export type { ConvertMessagesOptions } from './shared/openaiConvertMessages.js'
|
export type { ConvertMessagesOptions } from './shared/openaiConvertMessages.js'
|
||||||
export { anthropicToolsToOpenAI, anthropicToolChoiceToOpenAI } from './shared/openaiConvertTools.js'
|
export { anthropicToolsToOpenAI, anthropicToolChoiceToOpenAI } from './shared/openaiConvertTools.js'
|
||||||
export { adaptOpenAIStreamToAnthropic } from './shared/openaiStreamAdapter.js'
|
export { adaptOpenAIStreamToAnthropic } from './shared/openaiStreamAdapter.js'
|
||||||
|
|
||||||
|
// Codex provider utilities
|
||||||
|
export { normalizeCodexCallId, resolveCodexCallId, createCodexFallbackCallId } from './providers/codex/callIds.js'
|
||||||
|
export { resolveCodexModel, resolveCodexMaxTokens } from './providers/codex/modelMapping.js'
|
||||||
|
export { anthropicMessagesToCodexInput } from './providers/codex/convertMessages.js'
|
||||||
|
export type { CodexImageConversionOptions } from './providers/codex/convertMessages.js'
|
||||||
|
export { anthropicToolsToCodex } from './providers/codex/convertTools.js'
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type {
|
|||||||
ResponseInputItem,
|
ResponseInputItem,
|
||||||
ResponseInputText,
|
ResponseInputText,
|
||||||
} from 'openai/resources/responses/responses.mjs'
|
} from 'openai/resources/responses/responses.mjs'
|
||||||
import type { Message } from '../../../types/message.js'
|
import type { Message } from '../../types/index.js'
|
||||||
import {
|
import {
|
||||||
normalizeCodexCallId,
|
normalizeCodexCallId,
|
||||||
resolveCodexCallId,
|
resolveCodexCallId,
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import { describe, expect, test } from 'bun:test'
|
import { describe, expect, test } from 'bun:test'
|
||||||
import { createAssistantMessage, createUserMessage } from '../../../../utils/messages.js'
|
import { createAssistantMessage, createUserMessage } from '../../../../utils/messages.js'
|
||||||
import { anthropicMessagesToCodexInput } from '../convertMessages.js'
|
import { anthropicMessagesToCodexInput, anthropicToolsToCodex } from '@ant/model-provider'
|
||||||
import { anthropicToolsToCodex } from '../convertTools.js'
|
|
||||||
|
|
||||||
describe('anthropicMessagesToCodexInput', () => {
|
describe('anthropicMessagesToCodexInput', () => {
|
||||||
test('replays assistant tool calls and user tool results in order', async () => {
|
test('replays assistant tool calls and user tool results in order', async () => {
|
||||||
|
|||||||
@@ -97,33 +97,68 @@ mock.module('../client.js', () => ({
|
|||||||
}),
|
}),
|
||||||
}))
|
}))
|
||||||
|
|
||||||
mock.module('../convertMessages.js', () => ({
|
// Mock only model resolution — conversion functions can use real implementations
|
||||||
anthropicMessagesToCodexInput: () => [],
|
// since the client mock controls API responses.
|
||||||
}))
|
mock.module('@ant/model-provider', () => {
|
||||||
|
// Import the real module to preserve conversion functions
|
||||||
mock.module('../convertTools.js', () => ({
|
const real = require('@ant/model-provider')
|
||||||
anthropicToolsToCodex: () => [],
|
return {
|
||||||
}))
|
...real,
|
||||||
|
|
||||||
mock.module('../model.js', () => ({
|
|
||||||
resolveCodexModel: () => 'gpt-5.4',
|
resolveCodexModel: () => 'gpt-5.4',
|
||||||
resolveCodexMaxTokens: () => 4096,
|
resolveCodexMaxTokens: () => 4096,
|
||||||
}))
|
}
|
||||||
|
})
|
||||||
|
|
||||||
mock.module('../../../../utils/context.js', () => ({
|
mock.module('../../../../utils/context.js', () => ({
|
||||||
|
MODEL_CONTEXT_WINDOW_DEFAULT: 200_000,
|
||||||
|
COMPACT_MAX_OUTPUT_TOKENS: 20_000,
|
||||||
|
CAPPED_DEFAULT_MAX_TOKENS: 8_000,
|
||||||
|
ESCALATED_MAX_TOKENS: 64_000,
|
||||||
|
is1mContextDisabled: () => false,
|
||||||
|
has1mContext: () => false,
|
||||||
|
modelSupports1M: () => false,
|
||||||
|
getContextWindowForModel: () => 200_000,
|
||||||
|
getSonnet1mExpTreatmentEnabled: () => false,
|
||||||
|
calculateContextPercentages: () => ({}),
|
||||||
getModelMaxOutputTokens: () => ({ upperLimit: 4096 }),
|
getModelMaxOutputTokens: () => ({ upperLimit: 4096 }),
|
||||||
|
getMaxThinkingTokensForModel: () => 0,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
mock.module('../../../../utils/api.js', () => ({
|
mock.module('../../../../utils/api.js', () => ({
|
||||||
toolToAPISchema: async () => ({}),
|
toolToAPISchema: async () => ({}),
|
||||||
|
appendSystemContext: () => {},
|
||||||
|
prependUserContext: () => {},
|
||||||
|
logAPIPrefix: () => {},
|
||||||
|
splitSysPromptPrefix: () => ({ prefix: '', rest: [] }),
|
||||||
|
logContextMetrics: async () => {},
|
||||||
|
normalizeToolInput: (input: any) => input,
|
||||||
|
normalizeToolInputForAPI: (input: any) => input,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
mock.module('../../../../utils/debug.js', () => ({
|
mock.module('src/utils/debug.ts', () => ({
|
||||||
|
getMinDebugLogLevel: () => 'debug' as const,
|
||||||
|
isDebugMode: () => false,
|
||||||
|
enableDebugLogging: () => false,
|
||||||
|
getDebugFilter: () => null,
|
||||||
|
isDebugToStdErr: () => false,
|
||||||
|
getDebugFilePath: () => null as string | null,
|
||||||
|
setHasFormattedOutput: () => {},
|
||||||
|
getHasFormattedOutput: () => false,
|
||||||
|
flushDebugLogs: async () => {},
|
||||||
logForDebugging: () => {},
|
logForDebugging: () => {},
|
||||||
|
getDebugLogPath: () => '/tmp/mock-debug.log',
|
||||||
|
logAntError: () => {},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
mock.module('../../../../services/langfuse/tracing.js', () => ({
|
mock.module('../../../../services/langfuse/tracing.js', () => ({
|
||||||
|
createTrace: () => null,
|
||||||
recordLLMObservation: () => {},
|
recordLLMObservation: () => {},
|
||||||
|
recordToolObservation: () => {},
|
||||||
|
createToolBatchSpan: () => null,
|
||||||
|
endToolBatchSpan: () => {},
|
||||||
|
createSubagentTrace: () => null,
|
||||||
|
createChildSpan: () => null,
|
||||||
|
endTrace: () => {},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
mock.module('../../../../services/langfuse/convert.js', () => ({
|
mock.module('../../../../services/langfuse/convert.js', () => ({
|
||||||
|
|||||||
@@ -27,15 +27,18 @@ import {
|
|||||||
convertOutputToLangfuse,
|
convertOutputToLangfuse,
|
||||||
convertToolsToLangfuse,
|
convertToolsToLangfuse,
|
||||||
} from '../../../services/langfuse/convert.js'
|
} from '../../../services/langfuse/convert.js'
|
||||||
import { anthropicMessagesToCodexInput } from './convertMessages.js'
|
import {
|
||||||
import { anthropicToolsToCodex } from './convertTools.js'
|
anthropicMessagesToCodexInput,
|
||||||
|
anthropicToolsToCodex,
|
||||||
|
resolveCodexMaxTokens,
|
||||||
|
resolveCodexModel,
|
||||||
|
} from '@ant/model-provider'
|
||||||
import { getCodexClient } from './client.js'
|
import { getCodexClient } from './client.js'
|
||||||
import { uploadCodexBase64Image } from './imageUpload.js'
|
import { uploadCodexBase64Image } from './imageUpload.js'
|
||||||
import {
|
import {
|
||||||
getCodexConfigurationError,
|
getCodexConfigurationError,
|
||||||
normalizeCodexError,
|
normalizeCodexError,
|
||||||
} from './errors.js'
|
} from './errors.js'
|
||||||
import { resolveCodexMaxTokens, resolveCodexModel } from './model.js'
|
|
||||||
import { sanitizeCodexRequest } from './preflight.js'
|
import { sanitizeCodexRequest } from './preflight.js'
|
||||||
import {
|
import {
|
||||||
addCodexUsage,
|
addCodexUsage,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import type {
|
|||||||
ResponseInputItem,
|
ResponseInputItem,
|
||||||
Tool,
|
Tool,
|
||||||
} from 'openai/resources/responses/responses.mjs'
|
} from 'openai/resources/responses/responses.mjs'
|
||||||
import { normalizeCodexCallId } from './callIds.js'
|
import { normalizeCodexCallId } from '@ant/model-provider'
|
||||||
|
|
||||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
normalizeContentFromAPI,
|
normalizeContentFromAPI,
|
||||||
} from '../../../utils/messages.js'
|
} from '../../../utils/messages.js'
|
||||||
import { getCodexClient } from './client.js'
|
import { getCodexClient } from './client.js'
|
||||||
import { resolveCodexCallId } from './callIds.js'
|
import { resolveCodexCallId } from '@ant/model-provider'
|
||||||
import { toStreamingCodexRequest } from './preflight.js'
|
import { toStreamingCodexRequest } from './preflight.js'
|
||||||
|
|
||||||
export type RawAssistantBlock =
|
export type RawAssistantBlock =
|
||||||
|
|||||||
Reference in New Issue
Block a user