blob: 06d5e895873c7a65f796d47498208e93242e66d5 [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import assert from 'node:assert/strict';
import { test } from 'node:test';
import { createDefaultRuntimePolicy } from '@maka/core/runtime-policy';
import { installRefreshedModelMetadata, lookupModelMetadata } from '@maka/core/model-metadata';
import { MODELS_DEV_PROVIDERS } from '@maka/core/models-dev-projection';
import type { ProxiedFetchProxy } from '@maka/runtime/network/scoped-fetch-transport';
import type {
ResolveHostOutboundExecutionResult,
RuntimePolicyOperationCoordinator,
} from '@maka/storage/runtime-policy-stores';
import { startHostModelMetadataRefresh } from '../server/model-metadata-refresh.js';
/** Read before any install, so a snapshot refresh cannot make it a stale literal. */
const BUNDLED_OPUS_NAME = lookupModelMetadata('anthropic', 'claude-opus-4-5').displayName;
test('a refreshed catalog replaces the bundled metadata before clients are told', async (t) => {
t.after(() => installRefreshedModelMetadata(undefined));
const announced: string[] = [];
const refresh = startHostModelMetadataRefresh({
policy: resolver(ready()),
publish: () => {
announced.push(lookupModelMetadata('anthropic', 'refreshed-model').displayName ?? '');
},
createFetchTransport: () => respondWith(JSON.stringify(catalogFixture())),
});
await refresh.settled;
assert.deepEqual(announced, ['Refreshed Model']);
assert.equal(
lookupModelMetadata('anthropic', 'refreshed-model').displayName,
'Refreshed Model',
'the refreshed table answers lookups',
);
});
test('a refresh drops every model the bundled snapshot described on its own', async (t) => {
t.after(() => installRefreshedModelMetadata(undefined));
const refresh = startHostModelMetadataRefresh({
policy: resolver(ready()),
publish: () => {},
createFetchTransport: () => respondWith(JSON.stringify(catalogFixture())),
});
await refresh.settled;
assert.equal(typeof BUNDLED_OPUS_NAME, 'string');
assert.equal(
lookupModelMetadata('anthropic', 'claude-opus-4-5').displayName,
undefined,
'a model upstream no longer lists stops being described by models.dev',
);
});
test('an upstream shape the projection refuses keeps the bundled snapshot', async (t) => {
t.after(() => installRefreshedModelMetadata(undefined));
const catalog = catalogFixture();
catalog.anthropic.models['refreshed-model'].modalities = {
input: ['hologram'],
output: ['text'],
};
let announced = 0;
const refresh = startHostModelMetadataRefresh({
policy: resolver(ready()),
publish: () => {
announced += 1;
},
createFetchTransport: () => respondWith(JSON.stringify(catalog)),
});
await refresh.settled;
assert.equal(announced, 0);
assert.equal(lookupModelMetadata('anthropic', 'refreshed-model').displayName, undefined);
assert.equal(lookupModelMetadata('anthropic', 'claude-opus-4-5').displayName, BUNDLED_OPUS_NAME);
});
test('a failed fetch keeps the bundled snapshot and announces nothing', async (t) => {
t.after(() => installRefreshedModelMetadata(undefined));
let announced = 0;
let closed = 0;
const refresh = startHostModelMetadataRefresh({
policy: resolver(ready()),
publish: () => {
announced += 1;
},
createFetchTransport: () => ({
fetch: async () => {
throw new Error('offline');
},
close: async () => {
closed += 1;
},
}),
});
await refresh.settled;
assert.equal(announced, 0);
assert.equal(closed, 1, 'the transport is closed even when the fetch throws');
assert.equal(lookupModelMetadata('anthropic', 'claude-opus-4-5').displayName, BUNDLED_OPUS_NAME);
});
test('privacy mode refuses the refresh before any transport exists', async () => {
let transportCreated = false;
const refresh = startHostModelMetadataRefresh({
policy: resolver({ kind: 'privacy_mode' }),
publish: () => assert.fail('privacy mode must not announce a refresh'),
createFetchTransport: () => {
transportCreated = true;
throw new Error('transport must not be created');
},
});
await refresh.settled;
assert.equal(transportCreated, false);
});
test('the refresh goes out over the resolved proxy snapshot', async (t) => {
t.after(() => installRefreshedModelMetadata(undefined));
const networkProxy = {
...createDefaultRuntimePolicy().networkProxy,
enabled: true,
protocol: 'http' as const,
host: 'proxy.example',
port: 8080,
authEnabled: true,
username: 'proxy-user',
bypassList: ['direct.example'],
};
let proxy: ProxiedFetchProxy | null | undefined;
const refresh = startHostModelMetadataRefresh({
policy: resolver({
kind: 'ready',
networkProxy,
secretMaterial: {
networkProxy: {
locator: { scope: 'network_proxy', kind: 'password' },
credentialId: 'proxy-credential',
revision: 1,
secret: 'proxy-secret',
},
},
}),
publish: () => {},
createFetchTransport: (candidate) => {
proxy = candidate;
return respondWith(JSON.stringify(catalogFixture()));
},
});
await refresh.settled;
assert.deepEqual(proxy, {
enabled: true,
type: 'http',
host: 'proxy.example',
port: 8080,
username: 'proxy-user',
password: 'proxy-secret',
bypassList: [...networkProxy.bypassList, ...networkProxy.autoBypassDomains],
});
});
function ready(): ResolveHostOutboundExecutionResult {
return {
kind: 'ready',
networkProxy: createDefaultRuntimePolicy().networkProxy,
secretMaterial: {},
};
}
function resolver(
result: ResolveHostOutboundExecutionResult,
): Pick<RuntimePolicyOperationCoordinator, 'resolveHostOutboundExecution'> {
return { resolveHostOutboundExecution: async () => result };
}
function respondWith(body: string) {
return {
fetch: async () => new Response(body, { headers: { 'content-type': 'application/json' } }),
close: async () => {},
};
}
interface FixtureModel {
name: string;
reasoning: boolean;
tool_call: boolean;
limit: { context: number; output: number };
modalities: { input: string[]; output: string[] };
}
/**
* A whole models.dev response: the projection refuses a partial one, so every
* provider Maka reads has to be present with at least one model.
*/
function catalogFixture(): Record<
string,
{ id: string; name: string; doc: string; models: Record<string, FixtureModel> }
> {
const catalog: Record<
string,
{ id: string; name: string; doc: string; models: Record<string, FixtureModel> }
> = {};
for (const sourceId of new Set(Object.values(MODELS_DEV_PROVIDERS))) {
catalog[sourceId] = {
id: sourceId,
name: sourceId,
doc: `https://models.dev/${sourceId}`,
models: { 'refreshed-model': model() },
};
}
return catalog;
}
function model(): FixtureModel {
return {
name: 'Refreshed Model',
reasoning: false,
tool_call: true,
limit: { context: 200_000, output: 64_000 },
modalities: { input: ['text', 'image'], output: ['text'] },
};
}