mirror of
https://github.com/HeyPuter/puter.git
synced 2026-11-08 06:54:18 +00:00
fix(ai-chat): give uncurated Alibaba catalog models a puterId
Uncurated entries admitted from the DashScope catalog feed previously surfaced with their raw feed id. They now get an alibaba:<vendor>/<model> puterId, vendor-prefixed ids keep their org, and others infer the org from the curated family sibling. Entries whose synthesized puterId collides with a curated entry are skipped so the model is not listed twice.
This commit is contained in:
1 parent
24aac2f6d2
commit
f0f97a08cf
2 files changed
+63
-1
No files matched your search
@@ -809,6 +809,11 @@ describe('Alibaba official catalog', () => {
|
||||
expect(models.some((model) => model.id === 'qwen-image-fixture')).toBe(
|
||||
false,
|
||||
);
|
||||
const fixture = models.find(
|
||||
(model) => model.id === 'qwen-catalog-fixture',
|
||||
)!;
|
||||
expect(fixture.puterId).toBe('alibaba:qwen/qwen-catalog-fixture');
|
||||
expect(modelLookupNames(models)).toContain('qwen-catalog-fixture');
|
||||
const plus = models.find((model) => model.id === 'qwen-plus')!;
|
||||
const original = ALIBABA_MODELS.find(
|
||||
(model) => model.id === 'qwen-plus',
|
||||
@@ -909,6 +914,38 @@ describe('Alibaba official catalog', () => {
|
||||
expect(model.costs).toEqual({ tokens: 1_000_000 });
|
||||
});
|
||||
|
||||
it.each([
|
||||
['qwen3.9-plus-2027-01-01', 'alibaba:qwen/qwen3.9-plus-2027-01-01'],
|
||||
['kimi/kimi-k3', 'alibaba:kimi/kimi-k3'],
|
||||
[
|
||||
'deepseek-v4.1-flash-1017',
|
||||
'alibaba:deepseek/deepseek-v4.1-flash-1017',
|
||||
],
|
||||
['glm-5.3-prime', 'alibaba:zhipu/glm-5.3-prime'],
|
||||
['decision-model-preview', 'alibaba:qwen/decision-model-preview'],
|
||||
])(
|
||||
'gives uncurated model %s a puterId in the alibaba:<vendor>/<id> form',
|
||||
(id, puterId) => {
|
||||
const model = mapAlibabaCatalogModel({
|
||||
model: id,
|
||||
capabilities: ['TG'],
|
||||
})!;
|
||||
expect(model.puterId).toBe(puterId);
|
||||
},
|
||||
);
|
||||
|
||||
it('skips a vendor-prefixed spelling of a curated model', () => {
|
||||
const model = mapAlibabaCatalogModel({
|
||||
model: 'zhipu/glm-5.2',
|
||||
capabilities: ['TG', 'Reasoning'],
|
||||
inference_metadata: {
|
||||
request_modality: ['Text'],
|
||||
response_modality: ['Text'],
|
||||
},
|
||||
});
|
||||
expect(model).toBeNull();
|
||||
});
|
||||
|
||||
it('refuses inference with unverified catalog prices', async () => {
|
||||
seedPages();
|
||||
const { provider } = makeProvider();
|
||||
|
||||
@@ -82,6 +82,23 @@ const positiveLimit = (value: unknown): number | undefined =>
|
||||
? value
|
||||
: undefined;
|
||||
|
||||
const chatCapabilities = ['TG', 'Reasoning', 'VU'];
|
||||
|
||||
const curatedPuterIds = new Set(ALIBABA_MODELS.map((model) => model.puterId));
|
||||
|
||||
const inferPuterId = (id: string): string => {
|
||||
if (id.includes('/')) return `alibaba:${id}`;
|
||||
const family = id.split('-')[0];
|
||||
const sibling = ALIBABA_MODELS.find(
|
||||
(model) => model.puterId && model.id.split('-')[0] === family,
|
||||
);
|
||||
// Unprefixed feed ids are Model Studio's own family unless a curated
|
||||
// sibling points at a third-party org.
|
||||
const org =
|
||||
sibling?.puterId?.slice('alibaba:'.length).split('/')[0] ?? 'qwen';
|
||||
return `alibaba:${org}/${id}`;
|
||||
};
|
||||
|
||||
export const mapAlibabaCatalogModel = (
|
||||
raw: AlibabaApiModel,
|
||||
previous?: IChatModel,
|
||||
@@ -96,10 +113,17 @@ export const mapAlibabaCatalogModel = (
|
||||
!output &&
|
||||
!existing &&
|
||||
!raw.capabilities?.some((capability) =>
|
||||
['TG', 'Reasoning', 'VU'].includes(capability),
|
||||
chatCapabilities.includes(capability),
|
||||
)
|
||||
)
|
||||
return null;
|
||||
let puterId = existing?.puterId;
|
||||
if (!puterId) {
|
||||
puterId = inferPuterId(id);
|
||||
// A feed entry spelling a curated model differently would duplicate
|
||||
// the curated entry's puterId and list the model twice.
|
||||
if (curatedPuterIds.has(puterId)) return null;
|
||||
}
|
||||
const catalogPricing: AlibabaCatalogTier[] = (raw.prices ?? []).map(
|
||||
(tier) => {
|
||||
// Abbreviated ranges do not specify whether k means 1000 or 1024 tokens.
|
||||
@@ -149,6 +173,7 @@ export const mapAlibabaCatalogModel = (
|
||||
return {
|
||||
...existing,
|
||||
id,
|
||||
puterId,
|
||||
name: raw.name ?? existing?.name ?? id,
|
||||
description: raw.description ?? existing?.description,
|
||||
aliases: existing?.aliases,
|
||||
|
||||
Reference in new issue
Block a user