Skip to content

Commit bb2ebf1

Browse files
authored
feat: Add comprehensive system prompt management system. (#1969)
* feat: Add comprehensive system prompt management system. * fix:fixed some bugs * fix: prevent false negatives in migration content verification Strip leading newlines before comparing saved vs original content. Obsidian may insert extra blank line after frontmatter block, causing stripFrontmatter to leave a leading newline and fail verification.
1 parent 538033e commit bb2ebf1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+7139
-1296
lines changed

package-lock.json

Lines changed: 609 additions & 915 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,19 +102,19 @@
102102
"@orama/orama": "^3.0.0-rc-2",
103103
"@radix-ui/react-checkbox": "^1.1.3",
104104
"@radix-ui/react-collapsible": "^1.1.2",
105-
"@radix-ui/react-dialog": "^1.1.3",
105+
"@radix-ui/react-dialog": "^1.1.15",
106106
"@radix-ui/react-dropdown-menu": "^2.1.4",
107-
"@radix-ui/react-label": "^2.1.0",
107+
"@radix-ui/react-label": "^2.1.7",
108108
"@radix-ui/react-popover": "^1.1.15",
109109
"@radix-ui/react-progress": "^1.1.7",
110110
"@radix-ui/react-scroll-area": "^1.2.10",
111-
"@radix-ui/react-select": "^2.1.2",
111+
"@radix-ui/react-select": "^2.2.6",
112112
"@radix-ui/react-separator": "^1.1.7",
113113
"@radix-ui/react-slider": "^1.3.5",
114114
"@radix-ui/react-slot": "^1.2.3",
115115
"@radix-ui/react-switch": "^1.1.1",
116116
"@radix-ui/react-tabs": "^1.1.3",
117-
"@radix-ui/react-tooltip": "^1.2.7",
117+
"@radix-ui/react-tooltip": "^1.2.8",
118118
"@tabler/icons-react": "^2.14.0",
119119
"async-mutex": "^0.5.0",
120120
"axios": "^1.3.4",

src/LLMProviders/chainManager.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import {
1616
VaultQAChainRunner,
1717
} from "@/LLMProviders/chainRunner/index";
1818
import { logError, logInfo } from "@/logger";
19-
import { getSettings, getSystemPrompt, subscribeToSettingsChange } from "@/settings/model";
19+
import { getSettings, subscribeToSettingsChange } from "@/settings/model";
20+
import { getSystemPrompt } from "@/system-prompts/systemPromptBuilder";
2021
import { ChatMessage } from "@/types/message";
2122
import { findCustomModel, isOSeriesModel, isSupportedChain } from "@/utils";
2223
import { MissingModelKeyError } from "@/error";

src/LLMProviders/chainRunner/AutonomousAgentChainRunner.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { MessageContent } from "@/imageProcessing/imageProcessor";
33
import { logError, logInfo, logWarn } from "@/logger";
44
import { UserMemoryManager } from "@/memory/UserMemoryManager";
55
import { checkIsPlusUser } from "@/plusUtils";
6-
import { getSettings, getSystemPromptWithMemory } from "@/settings/model";
6+
import { getSettings } from "@/settings/model";
7+
import { getSystemPromptWithMemory } from "@/system-prompts/systemPromptBuilder";
78
import { initializeBuiltinTools } from "@/tools/builtinTools";
89
import { extractParametersFromZod, SimpleTool } from "@/tools/SimpleTool";
910
import { ToolRegistry } from "@/tools/ToolRegistry";

src/LLMProviders/chainRunner/CopilotPlusChainRunner.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ import {
1515
} from "@/imageProcessing/imageProcessor";
1616
import { logInfo, logWarn } from "@/logger";
1717
import { checkIsPlusUser } from "@/plusUtils";
18-
import { getSettings, getSystemPromptWithMemory } from "@/settings/model";
18+
import { getSettings } from "@/settings/model";
19+
import { getSystemPromptWithMemory } from "@/system-prompts/systemPromptBuilder";
1920
import { writeToFileTool } from "@/tools/ComposerTools";
2021
import { ToolManager } from "@/tools/toolManager";
2122
import { ToolResultFormatter } from "@/tools/ToolResultFormatter";

src/LLMProviders/chainRunner/utils/modelAdapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ class BaseModelAdapter implements ModelAdapter {
194194
{
195195
id: "base-system-prompt",
196196
label: "System prompt with memory",
197-
source: "src/settings/model.ts#getSystemPromptWithMemory",
197+
source: "src/system-prompts/systemPromptBuilder.ts#getSystemPromptWithMemory",
198198
content: normalizedBasePrompt,
199199
},
200200
{

src/LLMProviders/chainRunner/utils/promptDebugService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import ChainManager from "@/LLMProviders/chainManager";
2-
import { getSystemPromptWithMemory } from "@/settings/model";
2+
import { getSystemPromptWithMemory } from "@/system-prompts/systemPromptBuilder";
33
import { ToolMetadata, ToolRegistry } from "@/tools/ToolRegistry";
44
import { ChatMessage } from "@/types/message";
55
import { messageRequiresTools, ModelAdapter } from "./modelAdapter";

src/LLMProviders/promptManager.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { getSystemPrompt, subscribeToSettingsChange } from "@/settings/model";
1+
import { subscribeToSettingsChange } from "@/settings/model";
2+
import { getSystemPrompt } from "@/system-prompts/systemPromptBuilder";
23
import {
34
ChatPromptTemplate,
45
HumanMessagePromptTemplate,

src/aiParams.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { ChainType } from "@/chainFactory";
22
import { BaseChatModel } from "@langchain/core/language_models/chat_models";
33
import { ChatPromptTemplate } from "@langchain/core/prompts";
44

5-
import { ModelCapability } from "@/constants";
5+
import { ModelCapability, ReasoningEffort, Verbosity } from "@/constants";
66
import { settingsAtom, settingsStore } from "@/settings/model";
77
import { SelectedTextContext } from "@/types/message";
88
import { atom, useAtom } from "jotai";
@@ -150,8 +150,8 @@ export interface CustomModel {
150150
bedrockRegion?: string;
151151

152152
// OpenAI GPT-5 and O-series specific fields
153-
reasoningEffort?: "minimal" | "low" | "medium" | "high";
154-
verbosity?: "low" | "medium" | "high";
153+
reasoningEffort?: ReasoningEffort;
154+
verbosity?: Verbosity;
155155
}
156156

157157
export function setModelKey(modelKey: string) {

src/commands/customCommandUtils.test.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,18 @@ jest.mock("@/logger", () => ({
3030
}));
3131

3232
// Mock the utility functions
33-
jest.mock("@/utils", () => ({
34-
extractTemplateNoteFiles: jest.fn().mockReturnValue([]),
35-
getFileContent: jest.fn(),
36-
getFileName: jest.fn(),
37-
getNotesFromPath: jest.fn(),
38-
getNotesFromTags: jest.fn(),
39-
processVariableNameForNotePath: jest.fn(),
40-
}));
33+
jest.mock("@/utils", () => {
34+
const actual = jest.requireActual("@/utils");
35+
return {
36+
extractTemplateNoteFiles: jest.fn().mockReturnValue([]),
37+
getFileContent: jest.fn(),
38+
getFileName: jest.fn(),
39+
getNotesFromPath: jest.fn(),
40+
getNotesFromTags: jest.fn(),
41+
processVariableNameForNotePath: jest.fn(),
42+
stripFrontmatter: actual.stripFrontmatter,
43+
};
44+
});
4145

4246
describe("processedPrompt()", () => {
4347
let mockVault: Vault;
@@ -144,6 +148,19 @@ describe("processedPrompt()", () => {
144148
expect(result.includedFiles).toEqual([]);
145149
});
146150

151+
it("should treat {} as literal when skipEmptyBraces is true", async () => {
152+
const customPrompt = "Rewrite the following text {}";
153+
const selectedText = "here is some selected text 12345";
154+
155+
const result = await processPrompt(customPrompt, selectedText, mockVault, mockActiveNote, true);
156+
157+
// {} should be preserved as literal, not replaced
158+
expect(result.processedPrompt).toBe("Rewrite the following text {}\n\n");
159+
expect(result.includedFiles).toEqual([]);
160+
expect(result.processedPrompt).not.toContain("<selected_text>");
161+
expect(result.processedPrompt).not.toContain("{selected_text}");
162+
});
163+
147164
it("should process {activeNote} correctly", async () => {
148165
const doc: CustomCommand = {
149166
title: "test-prompt",
@@ -785,6 +802,17 @@ describe("validateCommandName", () => {
785802

786803
it("returns null if unchanged currentCommandName", () => {
787804
expect(validateCommandName("Command One", baseCommands, "Command One")).toBeNull();
788-
expect(validateCommandName(" Command One ", baseCommands, "Command One")).toBeNull();
805+
});
806+
807+
it("returns error for names with leading or trailing whitespace", () => {
808+
expect(validateCommandName(" Command One ", baseCommands)).toBe(
809+
"Command name cannot have leading or trailing spaces"
810+
);
811+
expect(validateCommandName(" Leading", baseCommands)).toBe(
812+
"Command name cannot have leading or trailing spaces"
813+
);
814+
expect(validateCommandName("Trailing ", baseCommands)).toBe(
815+
"Command name cannot have leading or trailing spaces"
816+
);
789817
});
790818
});

0 commit comments

Comments
 (0)