improved provider picker ui on resource

This commit is contained in:
miloschwartz
2026-08-07 16:13:51 -04:00
parent 5e5e172d39
commit 9eafa067b9
17 changed files with 874 additions and 149 deletions
+4 -2
View File
@@ -234,7 +234,8 @@ export const resourceAiProviders = pgTable(
accessMode: varchar("accessMode")
.$type<"inherit" | "select">()
.notNull()
.default("inherit")
.default("inherit"),
enabled: boolean("enabled").notNull().default(true)
},
(t) => [primaryKey({ columns: [t.resourceId, t.providerId] })]
);
@@ -529,7 +530,8 @@ export const siteResourceAiProviders = pgTable(
accessMode: varchar("accessMode")
.$type<"inherit" | "select">()
.notNull()
.default("inherit")
.default("inherit"),
enabled: boolean("enabled").notNull().default(true)
},
(t) => [primaryKey({ columns: [t.siteResourceId, t.providerId] })]
);
+4 -2
View File
@@ -231,7 +231,8 @@ export const resourceAiProviders = sqliteTable(
accessMode: text("accessMode")
.$type<"inherit" | "select">()
.notNull()
.default("inherit")
.default("inherit"),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true)
},
(t) => [primaryKey({ columns: [t.resourceId, t.providerId] })]
);
@@ -514,7 +515,8 @@ export const siteResourceAiProviders = sqliteTable(
accessMode: text("accessMode")
.$type<"inherit" | "select">()
.notNull()
.default("inherit")
.default("inherit"),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true)
},
(t) => [primaryKey({ columns: [t.siteResourceId, t.providerId] })]
);
+35 -16
View File
@@ -24,7 +24,8 @@ export type AccessMode = z.infer<typeof accessModeSchema>;
export const resourceAiProviderAttachmentSchema = z.strictObject({
providerId: z.number().int().positive(),
accessMode: accessModeSchema.optional().default("inherit")
accessMode: accessModeSchema.optional().default("inherit"),
enabled: z.boolean().optional().default(true)
});
export type ResourceAiProviderInput = z.infer<
@@ -34,6 +35,7 @@ export type ResourceAiProviderInput = z.infer<
export type ResourceAiProviderAttachment = {
providerId: number;
accessMode: AccessMode;
enabled: boolean;
};
export const resourceAiModelEntrySchema = z.strictObject({
@@ -79,14 +81,23 @@ export function resolveEffectiveLists(input: {
function normalizeAttachments(
inputs: ResourceAiProviderInput[]
): ResourceAiProviderAttachment[] {
const byProviderId = new Map<number, AccessMode>();
const byProviderId = new Map<
number,
{ accessMode: AccessMode; enabled: boolean }
>();
for (const input of inputs) {
byProviderId.set(input.providerId, input.accessMode ?? "inherit");
byProviderId.set(input.providerId, {
accessMode: input.accessMode ?? "inherit",
enabled: input.enabled ?? true
});
}
return [...byProviderId.entries()].map(([providerId, accessMode]) => ({
providerId,
accessMode
}));
return [...byProviderId.entries()].map(
([providerId, { accessMode, enabled }]) => ({
providerId,
accessMode,
enabled
})
);
}
type EffectiveAllowRow = {
@@ -110,14 +121,16 @@ export async function assertNoOverlappingModelKeys(
): Promise<InferenceFieldsError | null> {
const trx = options.trx ?? db;
if (attachments.length < 2) {
const activeAttachments = attachments.filter((a) => a.enabled);
if (activeAttachments.length < 2) {
return null;
}
const inheritProviderIds = attachments
const inheritProviderIds = activeAttachments
.filter((a) => a.accessMode === "inherit")
.map((a) => a.providerId);
const selectProviderIds = attachments
const selectProviderIds = activeAttachments
.filter((a) => a.accessMode === "select")
.map((a) => a.providerId);
@@ -318,7 +331,8 @@ export async function setPublicResourceAiProviders(
attachments.map((a) => ({
resourceId,
providerId: a.providerId,
accessMode: a.accessMode
accessMode: a.accessMode,
enabled: a.enabled
}))
);
}
@@ -344,7 +358,8 @@ export async function setSiteResourceAiProviders(
attachments.map((a) => ({
siteResourceId,
providerId: a.providerId,
accessMode: a.accessMode
accessMode: a.accessMode,
enabled: a.enabled
}))
);
}
@@ -473,7 +488,8 @@ export async function listPublicResourceAiProviders(resourceId: number) {
providerId: resourceAiProviders.providerId,
name: aiProviders.name,
type: aiProviders.type,
enabled: aiProviders.enabled,
enabled: resourceAiProviders.enabled,
providerEnabled: aiProviders.enabled,
accessMode: resourceAiProviders.accessMode
})
.from(resourceAiProviders)
@@ -490,7 +506,8 @@ export async function listSiteResourceAiProviders(siteResourceId: number) {
providerId: siteResourceAiProviders.providerId,
name: aiProviders.name,
type: aiProviders.type,
enabled: aiProviders.enabled,
enabled: siteResourceAiProviders.enabled,
providerEnabled: aiProviders.enabled,
accessMode: siteResourceAiProviders.accessMode
})
.from(siteResourceAiProviders)
@@ -575,7 +592,8 @@ export async function assertPublicResourceModelEntriesValid(input: {
const attachments = await db
.select({
providerId: resourceAiProviders.providerId,
accessMode: resourceAiProviders.accessMode
accessMode: resourceAiProviders.accessMode,
enabled: resourceAiProviders.enabled
})
.from(resourceAiProviders)
.innerJoin(
@@ -610,7 +628,8 @@ export async function assertSiteResourceModelEntriesValid(input: {
const attachments = await db
.select({
providerId: siteResourceAiProviders.providerId,
accessMode: siteResourceAiProviders.accessMode
accessMode: siteResourceAiProviders.accessMode,
enabled: siteResourceAiProviders.enabled
})
.from(siteResourceAiProviders)
.innerJoin(
+13 -4
View File
@@ -287,7 +287,8 @@ async function resolveTarget(host: string): Promise<ResolvedTarget | null> {
resourceAiProviders.resourceId,
resourceRow.resourceId
),
eq(aiProviders.enabled, true)
eq(aiProviders.enabled, true),
eq(resourceAiProviders.enabled, true)
)
),
db
@@ -342,7 +343,8 @@ async function resolveTarget(host: string): Promise<ResolvedTarget | null> {
siteResourceAiProviders.siteResourceId,
siteResourceRow.siteResourceId
),
eq(aiProviders.enabled, true)
eq(aiProviders.enabled, true),
eq(siteResourceAiProviders.enabled, true)
)
),
db
@@ -525,8 +527,15 @@ function logAiUsageAndCost(args: {
isStream: boolean;
headers: Headers;
}): void {
const { capability, provider, requestedModel, requestBody, responseText, isStream, headers } =
args;
const {
capability,
provider,
requestedModel,
requestBody,
responseText,
isStream,
headers
} = args;
let usage: AiUsage | null = extractUsage(
capability,
@@ -118,9 +118,14 @@ export async function addAiProviderToResource(
.filter((a) => a.providerId !== providerId)
.map((a) => ({
providerId: a.providerId,
accessMode: a.accessMode
accessMode: a.accessMode,
enabled: a.enabled
})),
{ providerId, accessMode: "inherit" as const }
{
providerId,
accessMode: "inherit" as const,
enabled: true as const
}
];
const attachments = await resolveProviderAttachments({
+2 -1
View File
@@ -397,7 +397,8 @@ async function createHttpResource(
orgId,
attachments: (aiProviderInputs ?? []).map((p) => ({
providerId: p.providerId,
accessMode: "inherit" as const
accessMode: "inherit" as const,
enabled: true as const
})),
requireAtLeastOne: false
});
@@ -127,7 +127,8 @@ export async function removeAiProviderFromResource(
.filter((a) => a.providerId !== providerId)
.map((a) => ({
providerId: a.providerId,
accessMode: a.accessMode
accessMode: a.accessMode,
enabled: a.enabled
}));
const attachments = await resolveProviderAttachments({
@@ -118,9 +118,14 @@ export async function addAiProviderToSiteResource(
.filter((a) => a.providerId !== providerId)
.map((a) => ({
providerId: a.providerId,
accessMode: a.accessMode
accessMode: a.accessMode,
enabled: a.enabled
})),
{ providerId, accessMode: "inherit" as const }
{
providerId,
accessMode: "inherit" as const,
enabled: true as const
}
];
const attachments = await resolveProviderAttachments({
@@ -356,7 +356,8 @@ export async function createSiteResource(
orgId,
attachments: (aiProviderInputs ?? []).map((p) => ({
providerId: p.providerId,
accessMode: "inherit" as const
accessMode: "inherit" as const,
enabled: true as const
})),
requireAtLeastOne: false
});
@@ -126,7 +126,8 @@ export async function removeAiProviderFromSiteResource(
.filter((a) => a.providerId !== providerId)
.map((a) => ({
providerId: a.providerId,
accessMode: a.accessMode
accessMode: a.accessMode,
enabled: a.enabled
}));
const attachments = await resolveProviderAttachments({