mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-30 19:49:14 +00:00
feat(ai): add Alibaba DashScope recipe (#59 split, part 1/2)
12th recipe. text-embedding-v3 (current) + text-embedding-v2; 1024 default dims with Matryoshka options [64, 128, 256, 512, 768, 1024]. OpenAI-compatible at dashscope-intl.aliyuncs.com. China-region users override via cfg.base_urls['dashscope']; v0.32 ships with the international default. Conservative max_batch_tokens=8192 + chars_per_token=2 declared because Alibaba doesn't publish a hard batch limit and text-embedding-v3 mixes English + CJK heavily (CJK density closer to Voyage than OpenAI tiktoken). Tests: bun test test/ai/ — 106/106 (5 new + 101 prior). Plan: ~/.claude/plans/ok-lets-turn-this-enumerated-sonnet.md (commit 6 of 11). Reworked from #59 (DashScope+Zhipu split into 2 commits per the plan; Zhipu lands next). Co-Authored-By: Magicray1217 <267836857+Magicray1217@users.noreply.github.com> Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Magicray1217
Claude Opus 4.7
parent
1abbe8d5a0
commit
ce05aef3de
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* DashScope (Alibaba) recipe smoke (Commit 6 of the v0.32 wave).
|
||||
*/
|
||||
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { getRecipe } from '../../src/core/ai/recipes/index.ts';
|
||||
import { defaultResolveAuth } from '../../src/core/ai/gateway.ts';
|
||||
import { AIConfigError } from '../../src/core/ai/errors.ts';
|
||||
|
||||
describe('recipe: dashscope', () => {
|
||||
test('registered with expected shape', () => {
|
||||
const r = getRecipe('dashscope');
|
||||
expect(r).toBeDefined();
|
||||
expect(r!.id).toBe('dashscope');
|
||||
expect(r!.tier).toBe('openai-compat');
|
||||
expect(r!.implementation).toBe('openai-compatible');
|
||||
expect(r!.base_url_default).toBe(
|
||||
'https://dashscope-intl.aliyuncs.com/compatible-mode/v1',
|
||||
);
|
||||
expect(r!.auth_env?.required).toEqual(['DASHSCOPE_API_KEY']);
|
||||
});
|
||||
|
||||
test('embedding touchpoint declares text-embedding-v3 first + 1024 dims', () => {
|
||||
const r = getRecipe('dashscope')!;
|
||||
expect(r.touchpoints.embedding).toBeDefined();
|
||||
expect(r.touchpoints.embedding!.models[0]).toBe('text-embedding-v3');
|
||||
expect(r.touchpoints.embedding!.models).toContain('text-embedding-v2');
|
||||
expect(r.touchpoints.embedding!.default_dims).toBe(1024);
|
||||
expect(r.touchpoints.embedding!.dims_options).toEqual([64, 128, 256, 512, 768, 1024]);
|
||||
// Matryoshka: every dims option ≤ 2000 (HNSW-compatible).
|
||||
for (const d of r.touchpoints.embedding!.dims_options ?? []) {
|
||||
expect(d).toBeLessThanOrEqual(2000);
|
||||
}
|
||||
});
|
||||
|
||||
test('default auth: DASHSCOPE_API_KEY set → "Bearer <key>"', () => {
|
||||
const r = getRecipe('dashscope')!;
|
||||
const auth = defaultResolveAuth(
|
||||
r,
|
||||
{ DASHSCOPE_API_KEY: 'sk-dashscope-fake' },
|
||||
'embedding',
|
||||
);
|
||||
expect(auth.headerName).toBe('Authorization');
|
||||
expect(auth.token).toBe('Bearer sk-dashscope-fake');
|
||||
});
|
||||
|
||||
test('default auth: missing DASHSCOPE_API_KEY → AIConfigError', () => {
|
||||
const r = getRecipe('dashscope')!;
|
||||
expect(() => defaultResolveAuth(r, {}, 'embedding')).toThrow(AIConfigError);
|
||||
});
|
||||
|
||||
test('declares chars_per_token + max_batch_tokens for safer batching', () => {
|
||||
const r = getRecipe('dashscope')!;
|
||||
expect(r.touchpoints.embedding!.max_batch_tokens).toBeGreaterThan(0);
|
||||
expect(r.touchpoints.embedding!.chars_per_token).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user