Files
veridian/app/composables/useModels.ts
T
zoeissleeping 9914c043cb feat: add web search tool with reranking support
Integrates SearXNG web search as a tool available during chat when the
agent has search enabled. Supports optional reranking of results via a
configurable reranking model. Replaces Python subprocess evaluation with
@pydantic/monty WASM runtime. Introduces stable tool call ID mapping to
avoid exposing provider-native IDs to the database.
2026-04-27 12:05:47 -05:00

178 lines
5.4 KiB
TypeScript

import { nanoid } from 'nanoid';
import * as schema from '~~/drizzle/schema';
export type Model = typeof schema.models.$inferSelect;
export type Provider = typeof schema.providers.$inferSelect;
export type ProviderWithModels = Provider & {
models: Model[];
defaultBaseUrl?: string;
};
export type ModelWithProvider = Model & {
provider: Provider;
};
export const useModels = async () => {
const providers = useState<ProviderWithModels[]>('models_state', () => []);
const loaded = useState('models_loaded', () => false);
const { refresh } = await useFetch<ProviderWithModels[]>('/api/providers', {
key: 'models_request',
immediate: !loaded.value,
onRequest() {
loaded.value = true;
},
onResponse({ response }) {
if (response.ok) {
providers.value = response._data ?? [];
}
}
});
const allModels = computed<ModelWithProvider[]>(() => {
const result: ModelWithProvider[] = [];
for (const provider of providers.value) {
if (!provider.enabled) continue;
for (const model of provider.models || []) {
if (!model.enabled) continue;
result.push({ ...model, provider });
}
}
return result;
});
const getModel = (id: string): ModelWithProvider | undefined => {
return allModels.value.find((model) => model.id === id);
};
const getProvider = (id: string): ProviderWithModels | undefined => {
return providers.value.find((provider) => provider.id === id);
};
const getFirstAvailableModel = () => {
return allModels.value[0] ?? null;
};
const createModel = async (model: Model) => {
model.id = nanoid();
await $fetch(`/api/model`, {
method: 'POST',
body: model,
onRequest() {
providers.value = providers.value.map(p => ({
...p,
models: p.id === model.providerId ? [...p.models, model] : p.models
}));
},
onResponseError() {
providers.value = providers.value.map(p => ({
...p,
models: p.id === model.providerId ? p.models.filter(m => m.id !== model.id) : p.models
}));
},
});
}
const updateModel = async (id: string, updates: Partial<Model>) => {
const model = providers.value.find(p => p.models.find(m => m.id === id));
if (!model) return;
const original = model;
await $fetch(`/api/model/${id}`, {
method: 'PATCH',
body: updates,
onRequest() {
providers.value = providers.value.map(p => ({
...p,
models: p.models.map(m =>
m.id === id ? { ...m, ...updates } : m
)
}));
},
onRequestError() {
providers.value = providers.value.map(p => ({
...p,
models: p.models.map(m =>
m.id === id ? original : m
)
}) as ProviderWithModels);
},
onResponseError() {
providers.value = providers.value.map(p => ({
...p,
models: p.models.map(m =>
m.id === id ? original : m
)
}) as ProviderWithModels);
},
// async onResponse() {
// await refresh();
// }
});
};
const deleteModel = async (id: string) => {
const model = providers.value.find(p => p.models.find(m => m.id === id));
if (!model) return;
await $fetch(`/api/model/${id}`, {
method: 'DELETE',
onRequest() {
providers.value = providers.value.map(p => ({
...p,
models: p.models.filter(m => m.id !== id)
}));
},
onResponseError() {
providers.value.push(model);
},
async onResponse() {
await refresh();
}
});
}
const updateProvider = async (id: string, updates: Partial<Provider>) => {
const provider = providers.value.find(p => p.id === id);
if (!provider) return;
const original = provider;
await $fetch(`/api/provider/${id}`, {
method: 'PATCH',
body: updates,
onRequest() {
providers.value = providers.value.map(p =>
p.id === id ? { ...p, ...updates } : p
);
},
onRequestError() {
providers.value = providers.value.map(p =>
p.id === id ? original : p
);
},
onResponseError() {
providers.value = providers.value.map(p =>
p.id === id ? original : p
);
},
async onResponse() {
await refresh();
}
});
};
return {
providers,
allModels,
getModel,
getProvider,
getFirstAvailableModel,
createModel,
updateModel,
updateProvider,
deleteModel
};
}