Skip to content

Commit

Permalink
Merge branch 'enricoros:v2-dev' into v2-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
darthalex2014 authored Dec 25, 2024
2 parents 92badf0 + 1bd327e commit 7053ac3
Show file tree
Hide file tree
Showing 13 changed files with 162 additions and 40 deletions.
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
FROM node:22-alpine AS base
ENV NEXT_TELEMETRY_DISABLED 1

Check warning on line 3 in Dockerfile

View workflow job for this annotation

GitHub Actions / build-and-push-image

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/


# Dependencies
FROM base AS deps
WORKDIR /app
Expand All @@ -11,6 +10,9 @@ WORKDIR /app
COPY package*.json ./
COPY src/server/prisma ./src/server/prisma

# link ssl3 for latest Alpine
RUN sh -c '[ ! -e /lib/libssl.so.3 ] && ln -s /usr/lib/libssl.so.3 /lib/libssl.so.3 || echo "Link already exists"'

# Install dependencies, including dev (release builds should use npm ci)
ENV NODE_ENV development

Check warning on line 17 in Dockerfile

View workflow job for this annotation

GitHub Actions / build-and-push-image

Legacy key/value format with whitespace separator should not be used

LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format More info: https://docs.docker.com/go/dockerfile/rule/legacy-key-value-format/
RUN npm ci
Expand Down
16 changes: 14 additions & 2 deletions src/apps/chat/components/layout-bar/useLLMDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { GoodTooltip } from '~/common/components/GoodTooltip';
import { KeyStroke } from '~/common/components/KeyStroke';
import { OptimaBarControlMethods, OptimaBarDropdownMemo, OptimaDropdownItems } from '~/common/layout/optima/bar/OptimaBarDropdown';
import { findModelsServiceOrNull, llmsStoreActions, useModelsStore } from '~/common/stores/llms/store-llms';
import { isDeepEqual } from '~/common/util/hooks/useDeep';
import { optimaActions, optimaOpenModels } from '~/common/layout/optima/useOptima';


Expand Down Expand Up @@ -43,6 +44,9 @@ function LLMDropdown(props: {
}, [chatLlmId]);


// dropdown items - chached
const stabilizeLlmOptions = React.useRef<OptimaDropdownItems>();

const llmDropdownItems: OptimaDropdownItems = React.useMemo(() => {
const llmItems: OptimaDropdownItems = {};
let prevServiceId: DModelsServiceId | null = null;
Expand All @@ -69,7 +73,8 @@ function LLMDropdown(props: {
llmItems[`sep-${llm.sId}`] = {
type: 'separator',
title: serviceLabel,
icon: vendor?.Icon ? <vendor.Icon /> : undefined,
// NOTE: commenting because not useful, and creates a recursive issue in isDeepEqual - not needed, so kthxbye
// icon: vendor?.Icon ? <vendor.Icon /> : undefined,
};
prevServiceId = llm.sId;
sepCount++;
Expand All @@ -81,6 +86,7 @@ function LLMDropdown(props: {
// icon: llm.id.startsWith('some vendor') ? <VendorIcon /> : undefined,
};
}

// if there's a single separator (i.e. only one source), remove it
if (sepCount === 1) {
for (const key in llmItems) {
Expand All @@ -90,7 +96,13 @@ function LLMDropdown(props: {
}
}
}
return llmItems;

// stabilize the items: reuse the full array if nothing changed
const prev = stabilizeLlmOptions.current;
if (prev && isDeepEqual(prev, llmItems)) return prev;

// otherwise update the cache and return the new items
return stabilizeLlmOptions.current = llmItems;
}, [chatLlmId, llms, filterString]);


Expand Down
4 changes: 2 additions & 2 deletions src/common/stores/llms/llms.parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const DModelParameterRegistry = {
incompatibleWith: ['temperature'] as const,
} as const,

'vnd.oai.reasoning_effort': {
llmVndOaiReasoningEffort: {
label: 'Reasoning Effort',
type: 'enum' as const,
description: 'Constrains effort on reasoning for OpenAI reasoning models',
Expand All @@ -87,7 +87,7 @@ export type DModelParameterValues = {
[K in DModelParameterId]?: DModelParameterValue<K>;
}

export type DModelParameterId = keyof typeof DModelParameterRegistry; // max_tokens, temperature, top_p, vnd.oai.reasoning_effort, ...
export type DModelParameterId = keyof typeof DModelParameterRegistry;
// type _ExtendedParameterId = keyof typeof _ExtendedParameterRegistry;

type _EnumValues<T> = T extends { type: 'enum', values: readonly (infer U)[] } ? U : never;
Expand Down
16 changes: 13 additions & 3 deletions src/common/stores/llms/store-llms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { persist } from 'zustand/middleware';
import type { DOpenRouterServiceSettings } from '~/modules/llms/vendors/openrouter/openrouter.vendor';
import type { ModelVendorId } from '~/modules/llms/vendors/vendors.registry';

import { DLLM, DLLMId, LLM_IF_OAI_Fn, LLM_IF_OAI_Vision } from './llms.types';
import type { DModelParameterId } from './llms.parameters';
import type { DModelsService, DModelsServiceId } from './modelsservice.types';
import { DLLM, DLLMId, LLM_IF_OAI_Fn, LLM_IF_OAI_Vision } from './llms.types';
import { getLlmCostForTokens, portModelPricingV2toV3 } from './llms.pricing';


Expand All @@ -33,6 +34,7 @@ interface LlmsActions {
rerankLLMsByServices: (serviceIdOrder: DModelsServiceId[]) => void;
updateLLM: (id: DLLMId, partial: Partial<DLLM>) => void;
updateLLMUserParameters: (id: DLLMId, partial: Partial<DLLM['userParameters']>) => void;
deleteLLMUserParameter: (id: DLLMId, parameterId: DModelParameterId) => void;

addService: (service: DModelsService) => void;
removeService: (id: DModelsServiceId) => void;
Expand Down Expand Up @@ -133,14 +135,22 @@ export const useModelsStore = create<LlmsState & LlmsActions>()(persist(
})),

updateLLMUserParameters: (id: DLLMId, partialUserParameters: Partial<DLLM['userParameters']>) =>
set(state => ({
llms: state.llms.map((llm: DLLM): DLLM =>
set(({ llms }) => ({
llms: llms.map((llm: DLLM): DLLM =>
llm.id === id
? { ...llm, userParameters: { ...llm.userParameters, ...partialUserParameters } }
: llm,
),
})),

deleteLLMUserParameter: (id: DLLMId, parameterId: DModelParameterId) =>
set(({ llms }) => ({
llms: llms.map((llm: DLLM): DLLM =>
llm.id === id && llm.userParameters
? { ...llm, userParameters: Object.fromEntries(Object.entries(llm.userParameters).filter(([key]) => key !== parameterId)) }
: llm,
),
})),

addService: (service: DModelsService) =>
set(state => {
Expand Down
30 changes: 19 additions & 11 deletions src/modules/aix/client/aix.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,23 +29,31 @@ export function aixCreateChatGenerateContext(name: AixAPI_Context_ChatGenerate['
}

export function aixCreateModelFromLLMOptions(
llmOptions: DModelParameterValues | undefined,
llmOptionsOverride: DModelParameterValues | undefined,
llmOptions: DModelParameterValues,
llmOptionsOverride: Omit<DModelParameterValues, 'llmRef'> | undefined,
debugLlmId: string,
): AixAPI_Model {
// model params (llm)
let { llmRef, llmTemperature, llmResponseTokens } = llmOptions || {};
if (!llmRef || llmTemperature === undefined)

// destructure input with the overrides
const { llmRef, llmTemperature, llmResponseTokens, llmTopP, llmVndOaiReasoningEffort } = {
...llmOptions,
...llmOptionsOverride,
};

// llmRef is absolutely required
if (!llmRef)
throw new Error(`AIX: Error in configuration for model ${debugLlmId} (missing ref, temperature): ${JSON.stringify(llmOptions)}`);

// model params overrides
if (llmOptionsOverride?.llmTemperature !== undefined) llmTemperature = llmOptionsOverride.llmTemperature;
if (llmOptionsOverride?.llmResponseTokens !== undefined) llmResponseTokens = llmOptionsOverride.llmResponseTokens;
// llmTemperature is highly recommended, so we display a note if it's missing
if (llmTemperature === undefined)
console.warn(`[DEV] AIX: Missing temperature for model ${debugLlmId}, using default.`);

return {
id: llmRef,
temperature: llmTemperature,
...(llmResponseTokens ? { maxTokens: llmResponseTokens } : {}),
...(llmTemperature !== undefined ? { temperature: llmTemperature } : {}),
...(llmResponseTokens /* null: similar to undefined, will omit the value */ ? { maxTokens: llmResponseTokens } : {}),
...(llmTopP !== undefined ? { topP: llmTopP } : {}),
...(llmVndOaiReasoningEffort ? { vndOaiReasoningEffort: llmVndOaiReasoningEffort } : {}),
};
}

Expand All @@ -70,7 +78,7 @@ type StreamMessageStatus = {
interface AixClientOptions {
abortSignal: AbortSignal | 'NON_ABORTABLE'; // 'NON_ABORTABLE' is a special case for non-abortable operations
throttleParallelThreads?: number; // 0: disable, 1: default throttle (12Hz), 2+ reduce frequency with the square root
llmOptionsOverride?: DModelParameterValues;
llmOptionsOverride?: Omit<DModelParameterValues, 'llmRef'>; // overrides for the LLM options
}


Expand Down
2 changes: 2 additions & 0 deletions src/modules/aix/server/api/aix.wiretypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ export namespace AixWire_API {
id: z.string(),
temperature: z.number().min(0).max(2).optional(),
maxTokens: z.number().min(1).optional(),
topP: z.number().min(0).max(1).optional(),
vndOaiReasoningEffort: z.enum(['low', 'medium', 'high']).optional(),
});

/// Context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ export function aixToAnthropicMessageCreate(model: AixAPI_Model, chatGenerate: A
// top_p: undefined,
};

// Top-P instead of temperature
if (model.topP !== undefined) {
payload.top_p = model.topP;
delete payload.temperature
}

// Preemptive error detection with server-side payload validation before sending it upstream
const validated = AnthropicWire_API_Message_Create.Request_schema.safeParse(payload);
if (!validated.success) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ export function aixToGeminiGenerateContent(model: AixAPI_Model, chatGenerate: Ai
},
};

// Top-P instead of temperature
if (model.topP !== undefined) {
delete payload.generationConfig!.temperature;
payload.generationConfig!.topP = model.topP;
}

// Preemptive error detection with server-side payload validation before sending it upstream
const validated = GeminiWire_API_Generate_Content.Request_schema.safeParse(payload);
if (!validated.success) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ export function aixToOpenAIChatCompletions(openAIDialect: OpenAIDialects, model:
user: undefined,
};

// Top-P instead of temperature
if (model.topP !== undefined) {
delete payload.temperature;
payload.top_p = model.topP;
}

// [OpenAI] Vendor-specific reasoning effort, for o1 models only as of 2024-12-24
if (model.vndOaiReasoningEffort) {
payload.reasoning_effort = model.vndOaiReasoningEffort;
}

if (hotFixOpenAIo1Family)
payload = _fixRequestForOpenAIO1_maxCompletionTokens(payload);

Expand Down
Loading

0 comments on commit 7053ac3

Please sign in to comment.