mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-18 22:35:51 +00:00
feat: 重构供应商层次 (#286)
* refactor: 创建 @anthropic-ai/model-provider 包骨架与类型定义
- 新建 workspace 包 packages/@anthropic-ai/model-provider
- 定义 ModelProviderHooks 接口(依赖注入:分析、成本、日志等)
- 定义 ClientFactories 接口(Anthropic/OpenAI/Gemini/Grok 客户端工厂)
- 搬入核心类型:Message 体系、NonNullableUsage、EMPTY_USAGE、SystemPrompt、错误常量
- 主项目 src/types/message.ts 等改为 re-export,保持向后兼容
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: 提升 OpenAI 转换器和模型映射到 model-provider 包
- 搬入 OpenAI 消息转换(convertMessages)、工具转换(convertTools)、流适配(streamAdapter)
- 搬入 OpenAI 和 Grok 模型映射(resolveOpenAIModel、resolveGrokModel)
- 主项目文件改为 thin re-export proxy
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: 搬入 Gemini 兼容层到 model-provider 包
- 搬入 Gemini 类型定义、消息转换、工具转换、流适配、模型映射
- 主项目 gemini/ 目录下文件改为 thin re-export proxy
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: 搬入 errorUtils 并迁移消费者导入到 model-provider
- 搬入 formatAPIError、extractConnectionErrorDetails 等 errorUtils
- 迁移 10 个消费者文件直接从 @anthropic-ai/model-provider 导入
- 更新 emptyUsage、sdkUtilityTypes、systemPromptType 为 re-export proxy
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: compact 模型降级为 -1 模式(Opus→Sonnet, Sonnet→Haiku)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* docs: 添加 agent-loop 绘图
* Revert "feat: compact 模型降级为 -1 模式(Opus→Sonnet, Sonnet→Haiku)"
This reverts commit e458d6391d.
* docs: 添加简化版 agent loop
* fix: 修复 n 快捷键导致关闭的问题
* fix: 修复 node 下 ws 没打包问题
* docs: 修复链接
* test: 添加测试支持
* fix: 修复类型问题(#267) (#271)
* fix: 修复 Bun 的 polyfill 问题
* fix: 类型修复完成
* feat: 统一所有包的类型文件
* fix: 修复构建问题
* test: 修复类型校验 (#279)
* fix: 修复 Bun 的 polyfill 问题
* fix: 类型修复完成
* feat: 统一所有包的类型文件
* fix: 修复构建问题
* fix(remote-control): harden self-hosted session flows (#278)
Co-authored-by: chengzifeng <chengzifeng@meituan.com>
* docs: update contributors
* build: 新增 vite 构建流程
* feat: 添加环境变量支持以覆盖 max_tokens 设置
* feat(langfuse): LLM generation 记录工具定义
将 Anthropic 格式的工具定义转换为 Langfuse 兼容的 OpenAI 格式,
并在 generation 的 input 中以 { messages, tools } 结构传入,
以便在 Langfuse UI 中查看完整的工具定义信息。
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: 添加对 ACP 协议的支持 (#284)
* feat: 适配 zed acp 协议
* docs: 完善 acp 文档
* chore: 1.4.0
* conflict: 解决冲突
* feat: 添加测试覆盖率上报
* style: 改名加移动文件夹位置
* refactor: 移动测试用例及实现
* test: 修复测试用例完成
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Cheng Zi Feng <1154238323@qq.com>
Co-authored-by: chengzifeng <chengzifeng@meituan.com>
Co-authored-by: claude-code-best <272536312+claude-code-best@users.noreply.github.com>
This commit is contained in:
74
src/utils/__tests__/bunHashPolyfill.test.ts
Normal file
74
src/utils/__tests__/bunHashPolyfill.test.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Tests for fix: 修复 Bun.hash 不存在的问题 (ecbd5a9)
|
||||
*
|
||||
* The Node.js polyfill in build.ts injects a FNV-1a hash implementation as
|
||||
* globalThis.Bun.hash so bundled output doesn't crash under plain Node.js.
|
||||
* We test the algorithm directly here to guard against regressions.
|
||||
*/
|
||||
import { describe, expect, test } from 'bun:test'
|
||||
|
||||
/**
|
||||
* Inline copy of the polyfill from build.ts — keep in sync if the
|
||||
* implementation changes.
|
||||
*/
|
||||
function bunHashPolyfill(data: string, seed?: number): number {
|
||||
let h = ((seed || 0) ^ 0x811c9dc5) >>> 0
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
h ^= data.charCodeAt(i)
|
||||
h = Math.imul(h, 0x01000193) >>> 0
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
describe('Bun.hash Node.js polyfill (FNV-1a)', () => {
|
||||
test('returns a number', () => {
|
||||
expect(typeof bunHashPolyfill('hello')).toBe('number')
|
||||
})
|
||||
|
||||
test('returns a 32-bit unsigned integer', () => {
|
||||
const h = bunHashPolyfill('test')
|
||||
expect(h).toBeGreaterThanOrEqual(0)
|
||||
expect(h).toBeLessThanOrEqual(0xffffffff)
|
||||
})
|
||||
|
||||
test('is deterministic', () => {
|
||||
expect(bunHashPolyfill('hello')).toBe(bunHashPolyfill('hello'))
|
||||
})
|
||||
|
||||
test('different inputs produce different hashes', () => {
|
||||
expect(bunHashPolyfill('abc')).not.toBe(bunHashPolyfill('def'))
|
||||
})
|
||||
|
||||
test('empty string returns seed-derived value (no crash)', () => {
|
||||
const h = bunHashPolyfill('')
|
||||
expect(typeof h).toBe('number')
|
||||
expect(h).toBeGreaterThanOrEqual(0)
|
||||
})
|
||||
|
||||
test('seed=0 and no seed produce the same result', () => {
|
||||
expect(bunHashPolyfill('hello', 0)).toBe(bunHashPolyfill('hello'))
|
||||
})
|
||||
|
||||
test('different seeds produce different hashes for same input', () => {
|
||||
expect(bunHashPolyfill('hello', 1)).not.toBe(bunHashPolyfill('hello', 2))
|
||||
})
|
||||
|
||||
test('result is always an unsigned 32-bit integer (no negative values)', () => {
|
||||
const inputs = ['', 'a', 'hello world', '\x00\xff', 'unicode: 你好']
|
||||
for (const input of inputs) {
|
||||
const h = bunHashPolyfill(input)
|
||||
expect(h).toBeGreaterThanOrEqual(0)
|
||||
expect(Number.isInteger(h)).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
test('Bun.hash native returns a numeric type (bigint or number)', () => {
|
||||
// Bun.hash returns a bigint (64-bit), while the polyfill returns a 32-bit
|
||||
// unsigned int. They use different widths so direct equality is not expected.
|
||||
// This test just verifies the native API exists and returns a numeric type.
|
||||
if (typeof globalThis.Bun?.hash === 'function') {
|
||||
const result = (globalThis.Bun.hash as (s: string) => bigint | number)('hello')
|
||||
expect(['number', 'bigint']).toContain(typeof result)
|
||||
}
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user