Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
  • Loading branch information
GOvEy1nw committed Sep 9, 2024
2 parents 70819c3 + 9ec665d commit 1f30798
Show file tree
Hide file tree
Showing 368 changed files with 32,452 additions and 9,885 deletions.
8 changes: 5 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ PROXY=
# ANYSCALE_API_KEY=
# APIPIE_API_KEY=
# COHERE_API_KEY=
# DEEPSEEK_API_KEY=
# DATABRICKS_API_KEY=
# FIREWORKS_API_KEY=
# GROQ_API_KEY=
Expand All @@ -74,6 +75,7 @@ PROXY=
# PERPLEXITY_API_KEY=
# SHUTTLEAI_API_KEY=
# TOGETHERAI_API_KEY=
# UNIFY_API_KEY=

#============#
# Anthropic #
Expand Down Expand Up @@ -429,10 +431,10 @@ ALLOW_SHARED_LINKS_PUBLIC=true
# Static File Cache Control #
#==============================#

# Leave commented out to use default of 1 month for max-age and 1 week for s-maxage
# Leave commented out to use defaults: 1 day (86400 seconds) for s-maxage and 2 days (172800 seconds) for max-age
# NODE_ENV must be set to production for these to take effect
# STATIC_CACHE_MAX_AGE=604800
# STATIC_CACHE_S_MAX_AGE=259200
# STATIC_CACHE_MAX_AGE=172800
# STATIC_CACHE_S_MAX_AGE=86400

# If you have another service in front of your LibreChat doing compression, disable express based compression here
# DISABLE_COMPRESSION=true
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/frontend-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ jobs:

- name: Run unit tests
run: npm run test:ci --verbose
working-directory: client
working-directory: client
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# v0.7.4
# v0.7.5-rc1

# Base node image
FROM node:20-alpine AS node
Expand Down
49 changes: 25 additions & 24 deletions Dockerfile.multi
Original file line number Diff line number Diff line change
@@ -1,43 +1,44 @@
# v0.7.4
# Dockerfile.multi
# v0.7.5-rc1

# Build API, Client and Data Provider
# Base for all builds
FROM node:20-alpine AS base
WORKDIR /app
RUN apk --no-cache add curl
RUN npm config set fetch-retry-maxtimeout 600000 && \
npm config set fetch-retries 5 && \
npm config set fetch-retry-mintimeout 15000
COPY package*.json ./
COPY packages/data-provider/package*.json ./packages/data-provider/
COPY client/package*.json ./client/
COPY api/package*.json ./api/
RUN npm ci

# Build data-provider
FROM base AS data-provider-build
WORKDIR /app/packages/data-provider
COPY ./packages/data-provider ./
RUN npm install; npm cache clean --force
COPY packages/data-provider ./
RUN npm run build
RUN npm prune --production

# React client build
# Client build
FROM base AS client-build
WORKDIR /app/client
COPY ./client/package*.json ./
# Copy data-provider to client's node_modules
COPY --from=data-provider-build /app/packages/data-provider/ /app/client/node_modules/librechat-data-provider/
RUN npm install; npm cache clean --force
COPY ./client/ ./
COPY client ./
COPY --from=data-provider-build /app/packages/data-provider/dist /app/packages/data-provider/dist
ENV NODE_OPTIONS="--max-old-space-size=2048"
RUN npm run build
RUN npm prune --production

# Node API setup
# API setup (including client dist)
FROM base AS api-build
WORKDIR /app
COPY api ./api
COPY config ./config
COPY --from=data-provider-build /app/packages/data-provider/dist ./packages/data-provider/dist
COPY --from=client-build /app/client/dist ./client/dist
WORKDIR /app/api
COPY api/package*.json ./
COPY api/ ./
# Copy helper scripts
COPY config/ ./
# Copy data-provider to API's node_modules
COPY --from=data-provider-build /app/packages/data-provider/ /app/api/node_modules/librechat-data-provider/
RUN npm install --include prod; npm cache clean --force
COPY --from=client-build /app/client/dist /app/client/dist
RUN npm prune --production
EXPOSE 3080
ENV HOST=0.0.0.0
CMD ["node", "server/index.js"]

# Nginx setup
FROM nginx:1.27.0-alpine AS prod-stage
COPY ./client/nginx.conf /etc/nginx/conf.d/default.conf
CMD ["nginx", "-g", "daemon off;"]
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
- OpenAI, Azure OpenAI, BingAI, ChatGPT, Google Vertex AI, Anthropic (Claude), Plugins, Assistants API (including Azure Assistants)
- ✅ Compatible across both **[Remote & Local AI services](https://www.librechat.ai/docs/configuration/librechat_yaml/ai_endpoints):**
- groq, Ollama, Cohere, Mistral AI, Apple MLX, koboldcpp, OpenRouter, together.ai, Perplexity, ShuttleAI, and more
- 🪄 Generative UI with [Code Artifacts](https://youtu.be/GfTj7O4gmd0?si=WJbdnemZpJzBrJo3)
- Create React, HTML code, and Mermaid diagrams right in chat
- 💾 Create, Save, & Share Custom Presets
- 🔀 Switch between AI Endpoints and Presets, mid-chat
- 🔄 Edit, Resubmit, and Continue Messages with Conversation branching
Expand Down
22 changes: 15 additions & 7 deletions api/app/clients/AnthropicClient.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,19 @@ class AnthropicClient extends BaseClient {
this.options = options;
}

const modelOptions = this.options.modelOptions || {};
this.modelOptions = {
...modelOptions,
model: modelOptions.model || anthropicSettings.model.default,
};
this.modelOptions = Object.assign(
{
model: anthropicSettings.model.default,
},
this.modelOptions,
this.options.modelOptions,
);

const modelMatch = matchModelName(this.modelOptions.model, EModelEndpoint.anthropic);
this.isClaude3 = modelMatch.startsWith('claude-3');
this.isLegacyOutput = !modelMatch.startsWith('claude-3-5-sonnet');
this.supportsCacheControl = this.checkPromptCacheSupport(modelMatch);
this.supportsCacheControl =
this.options.promptCache && this.checkPromptCacheSupport(modelMatch);

if (
this.isLegacyOutput &&
Expand Down Expand Up @@ -489,7 +492,10 @@ class AnthropicClient extends BaseClient {
identityPrefix = `${identityPrefix}\nYou are ${this.options.modelLabel}`;
}

let promptPrefix = (this.options.promptPrefix || '').trim();
let promptPrefix = (this.options.promptPrefix ?? '').trim();
if (typeof this.options.artifactsPrompt === 'string' && this.options.artifactsPrompt) {
promptPrefix = `${promptPrefix ?? ''}\n${this.options.artifactsPrompt}`.trim();
}
if (promptPrefix) {
// If the prompt prefix doesn't end with the end token, add it.
if (!promptPrefix.endsWith(`${this.endToken}`)) {
Expand Down Expand Up @@ -817,8 +823,10 @@ class AnthropicClient extends BaseClient {
getSaveOptions() {
return {
maxContextTokens: this.options.maxContextTokens,
artifacts: this.options.artifacts,
promptPrefix: this.options.promptPrefix,
modelLabel: this.options.modelLabel,
promptCache: this.options.promptCache,
resendFiles: this.options.resendFiles,
iconURL: this.options.iconURL,
greeting: this.options.greeting,
Expand Down
70 changes: 52 additions & 18 deletions api/app/clients/BaseClient.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
const crypto = require('crypto');
const fetch = require('node-fetch');
const { supportsBalanceCheck, Constants, CacheKeys, Time } = require('librechat-data-provider');
const {
supportsBalanceCheck,
ErrorTypes,
Constants,
CacheKeys,
Time,
} = require('librechat-data-provider');
const { getMessages, saveMessage, updateMessage, saveConvo } = require('~/models');
const { addSpaceIfNeeded, isEnabled } = require('~/server/utils');
const checkBalance = require('~/models/checkBalance');
Expand Down Expand Up @@ -28,6 +34,12 @@ class BaseClient {
this.userMessagePromise;
/** @type {ClientDatabaseSavePromise} */
this.responsePromise;
/** @type {string} */
this.user;
/** @type {string} */
this.conversationId;
/** @type {string} */
this.responseMessageId;
}

setOptions() {
Expand Down Expand Up @@ -155,6 +167,8 @@ class BaseClient {
this.currentMessages[this.currentMessages.length - 1].messageId = head;
}

this.responseMessageId = responseMessageId;

return {
...opts,
user,
Expand Down Expand Up @@ -341,7 +355,12 @@ class BaseClient {
};
}

async handleContextStrategy({ instructions, orderedMessages, formattedMessages }) {
async handleContextStrategy({
instructions,
orderedMessages,
formattedMessages,
buildTokenMap = true,
}) {
let _instructions;
let tokenCount;

Expand Down Expand Up @@ -383,9 +402,10 @@ class BaseClient {

const latestMessage = orderedWithInstructions[orderedWithInstructions.length - 1];
if (payload.length === 0 && !shouldSummarize && latestMessage) {
throw new Error(
`Prompt token count of ${latestMessage.tokenCount} exceeds max token count of ${this.maxContextTokens}.`,
);
const info = `${latestMessage.tokenCount} / ${this.maxContextTokens}`;
const errorMessage = `{ "type": "${ErrorTypes.INPUT_LENGTH}", "info": "${info}" }`;
logger.warn(`Prompt token count exceeds max token count (${info}).`);
throw new Error(errorMessage);
}

if (usePrevSummary) {
Expand All @@ -410,19 +430,23 @@ class BaseClient {
maxContextTokens: this.maxContextTokens,
});

let tokenCountMap = orderedWithInstructions.reduce((map, message, index) => {
const { messageId } = message;
if (!messageId) {
return map;
}
/** @type {Record<string, number> | undefined} */
let tokenCountMap;
if (buildTokenMap) {
tokenCountMap = orderedWithInstructions.reduce((map, message, index) => {
const { messageId } = message;
if (!messageId) {
return map;
}

if (shouldSummarize && index === summaryIndex && !usePrevSummary) {
map.summaryMessage = { ...summaryMessage, messageId, tokenCount: summaryTokenCount };
}
if (shouldSummarize && index === summaryIndex && !usePrevSummary) {
map.summaryMessage = { ...summaryMessage, messageId, tokenCount: summaryTokenCount };
}

map[messageId] = orderedWithInstructions[index].tokenCount;
return map;
}, {});
map[messageId] = orderedWithInstructions[index].tokenCount;
return map;
}, {});
}

const promptTokens = this.maxContextTokens - remainingContextTokens;

Expand Down Expand Up @@ -535,13 +559,19 @@ class BaseClient {
isEdited,
model: this.modelOptions.model,
sender: this.sender,
text: addSpaceIfNeeded(generation) + completion,
promptTokens,
iconURL: this.options.iconURL,
endpoint: this.options.endpoint,
...(this.metadata ?? {}),
};

if (typeof completion === 'string') {
responseMessage.text = addSpaceIfNeeded(generation) + completion;
} else if (completion) {
responseMessage.text = '';
responseMessage.content = completion;
}

if (
tokenCountMap &&
this.recordTokenUsage &&
Expand Down Expand Up @@ -861,8 +891,12 @@ class BaseClient {

processValue(nestedValue);
}
} else {
} else if (typeof value === 'string') {
numTokens += this.getTokenCount(value);
} else if (typeof value === 'number') {
numTokens += this.getTokenCount(value.toString());
} else if (typeof value === 'boolean') {
numTokens += this.getTokenCount(value.toString());
}
};

Expand Down
Loading

0 comments on commit 1f30798

Please sign in to comment.