Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

systemMessageComposition experimental configuration for more control over constructed system message #4507

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Move composition of systemMessage to a single place and enforce empty…
… system message if given explicitly by user
  • Loading branch information
ferenci84 committed Mar 6, 2025
commit 11f3351eece4c4a1cf71b795f6087cc9978869a3
9 changes: 5 additions & 4 deletions core/config/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ async function intermediateToFinalConfig(
ideSettings,
writeLog,
config.completionOptions,
config.systemMessage,
config.systemMessage
);

if (llm?.providerName === "free-trial") {
Expand Down Expand Up @@ -397,8 +397,8 @@ async function intermediateToFinalConfig(
(config.contextProviders || [])
.filter(isContextProviderWithParams)
.find((cp) => cp.name === "codebase") as
| ContextProviderWithParams
| undefined
| ContextProviderWithParams
| undefined
)?.params || {};

const DEFAULT_CONTEXT_PROVIDERS = [
Expand Down Expand Up @@ -991,5 +991,6 @@ export {
finalToBrowserConfig,
intermediateToFinalConfig,
loadContinueConfigFromJson,
type BrowserSerializedContinueConfig,
type BrowserSerializedContinueConfig
};

23 changes: 22 additions & 1 deletion core/llm/constructMessages.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
BrowserSerializedContinueConfig,
ChatHistoryItem,
ChatMessage,
MessagePart,
Expand All @@ -14,12 +15,31 @@ const TOOL_USE_RULES = `When using tools, follow the following guidelines:
function constructSystemPrompt(
modelDescription: ModelDescription,
useTools: boolean,
continueConfig: BrowserSerializedContinueConfig
): string | null {
let systemMessage =
"Always include the language and file name in the info string when you write code blocks, for example '```python file.py'.";
if (useTools && modelSupportsTools(modelDescription)) {
systemMessage += "\n\n" + TOOL_USE_RULES;
}

// We we have no access to the LLM class, we final systemMessage have to be the same as in core/llm/index.ts
const userSystemMessage = modelDescription.systemMessage ?? continueConfig.systemMessage;

// logic moved from core/llm/countTokens.ts
if (userSystemMessage && userSystemMessage.trim() !== "") {
const shouldAddNewLines = systemMessage !== "";
if (shouldAddNewLines) {
systemMessage += "\n\n";
}
systemMessage += userSystemMessage;
}

if (userSystemMessage === "") {
// Used defined explicit empty system message will be forced
systemMessage = "";
}

return systemMessage;
}

Expand All @@ -30,13 +50,14 @@ export function constructMessages(
history: ChatHistoryItem[],
modelDescription: ModelDescription,
useTools: boolean,
continueConfig: BrowserSerializedContinueConfig,
): ChatMessage[] {
const filteredHistory = history.filter(
(item) => item.message.role !== "system",
);
const msgs: ChatMessage[] = [];

const systemMessage = constructSystemPrompt(modelDescription, useTools);
const systemMessage = constructSystemPrompt(modelDescription, useTools, continueConfig);
if (systemMessage) {
msgs.push({
role: "system",
Expand Down
35 changes: 30 additions & 5 deletions core/llm/countTokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ class LlamaEncoding implements Encoding {
}

class NonWorkerAsyncEncoder implements AsyncEncoder {
constructor(private readonly encoding: Encoding) {}
constructor(private readonly encoding: Encoding) { }

async close(): Promise<void> {}
async close(): Promise<void> { }

async encode(text: string): Promise<number[]> {
return this.encoding.encode(text);
Expand Down Expand Up @@ -383,8 +383,8 @@ function compileChatMessages(
): ChatMessage[] {
let msgsCopy = msgs
? msgs
.map((msg) => ({ ...msg }))
.filter((msg) => !chatMessageIsEmpty(msg) && msg.role !== "system")
.map((msg) => ({ ...msg }))
.filter((msg) => !chatMessageIsEmpty(msg) && msg.role !== "system")
: [];

msgsCopy = addSpaceToAnyEmptyMessages(msgsCopy);
Expand All @@ -397,6 +397,7 @@ function compileChatMessages(
msgsCopy.push(promptMsg);
}

/* Original logic, moved to core/llm/constructMessages.ts
if (
(systemMessage && systemMessage.trim() !== "") ||
msgs?.[0]?.role === "system"
Expand All @@ -419,6 +420,29 @@ function compileChatMessages(
// Insert as second to last
// Later moved to top, but want second-priority to last user message
msgsCopy.splice(-1, 0, systemChatMsg);
}*/

if (
msgs?.[0]?.role === "system"
) {
let content = "";

content = renderChatMessage(msgs?.[0]);

const systemChatMsg: ChatMessage = {
role: "system",
content,
};
// Insert as second to last
// Later moved to top, but want second-priority to last user message
msgsCopy.splice(-1, 0, systemChatMsg);
} else if (systemMessage && systemMessage.trim() !== "") {
// In case core/llm/constructMessages.ts constructSystemPrompt() is not called
const systemChatMsg: ChatMessage = {
role: "system",
content: systemMessage,
};
msgsCopy.splice(-1, 0, systemChatMsg);
}

let functionTokens = 0;
Expand Down Expand Up @@ -469,5 +493,6 @@ export {
pruneLinesFromTop,
pruneRawPromptFromTop,
pruneStringFromBottom,
pruneStringFromTop,
pruneStringFromTop
};

6 changes: 3 additions & 3 deletions core/llm/llms/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
IdeSettings,
ILLM,
LLMOptions,
ModelDescription,
ModelDescription
} from "../..";
import { renderTemplatedString } from "../../promptFiles/v1/renderTemplatedString";
import { BaseLLM } from "../index";
Expand All @@ -19,7 +19,6 @@ import Cohere from "./Cohere";
import DeepInfra from "./DeepInfra";
import Deepseek from "./Deepseek";
import Fireworks from "./Fireworks";
import NCompass from "./NCompass";
import Flowise from "./Flowise";
import FreeTrial from "./FreeTrial";
import FunctionNetwork from "./FunctionNetwork";
Expand All @@ -35,7 +34,9 @@ import Mistral from "./Mistral";
import MockLLM from "./Mock";
import Moonshot from "./Moonshot";
import Msty from "./Msty";
import NCompass from "./NCompass";
import Nebius from "./Nebius";
import Novita from "./Novita";
import Nvidia from "./Nvidia";
import Ollama from "./Ollama";
import OpenAI from "./OpenAI";
Expand All @@ -49,7 +50,6 @@ import ContinueProxy from "./stubs/ContinueProxy";
import TestLLM from "./Test";
import TextGenWebUI from "./TextGenWebUI";
import Together from "./Together";
import Novita from "./Novita";
import VertexAI from "./VertexAI";
import Vllm from "./Vllm";
import WatsonX from "./WatsonX";
Expand Down
9 changes: 5 additions & 4 deletions gui/src/redux/thunks/streamResponse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ const getSlashCommandForInput = (
typeof input === "string"
? input
: (
input.filter((part) => part.type === "text").slice(-1)[0] as
| TextMessagePart
| undefined
)?.text || "";
input.filter((part) => part.type === "text").slice(-1)[0] as
| TextMessagePart
| undefined
)?.text || "";

if (lastText.startsWith("/")) {
slashCommandName = lastText.split(" ")[0].substring(1);
Expand Down Expand Up @@ -124,6 +124,7 @@ export const streamResponseThunk = createAsyncThunk<
[...updatedHistory],
defaultModel,
useTools,
state.config.config
);

posthog.capture("step run", {
Expand Down
1 change: 1 addition & 0 deletions gui/src/redux/thunks/streamResponseAfterToolCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ export const streamResponseAfterToolCall = createAsyncThunk<
[...updatedHistory],
defaultModel,
useTools,
state.config.config
);
const output = await dispatch(streamNormalInput(messages));
unwrapResult(output);
Expand Down
Loading