Skip to content

Commit 384350d

Browse files
committed
move option for initial prompt/attachment and system prompt; add option for adding initial messages
1 parent a8c1564 commit 384350d

File tree

12 files changed

+246
-87
lines changed

12 files changed

+246
-87
lines changed

frontend/src/store/history.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const buildSystemMessage = (): HistoryEntry => ({
2525
Role: Role.System,
2626
ContentParts: [{
2727
Type: ContentType.Text,
28-
Content: useConfigStore().profile.LLM.CallOptions.SystemPrompt,
28+
Content: useConfigStore().profile.LLM.CallOptions.Prompt.System,
2929
}],
3030
Created: Math.floor(new Date().getTime() / 1000),
3131
}),

frontend/src/views/Chat.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ export default {
150150
appbarHeight: 0,
151151
progress: false,
152152
input: {
153-
prompt: this.$appProfile.UI.Prompt.InitValue,
154-
attachments: this.$appProfile.UI.Prompt.InitAttachments,
153+
prompt: this.$appProfile.LLM.CallOptions.Prompt.InitValue,
154+
attachments: this.$appProfile.LLM.CallOptions.Prompt.InitAttachments,
155155
} as ChatInputType,
156156
outputStream: [
157157
{
@@ -362,8 +362,8 @@ export default {
362362
await this.processLLM(input, () => LLMAsk(args))
363363
},
364364
async waitForLLM() {
365-
this.input.prompt = this.profile.UI.Prompt.InitValue
366-
this.input.attachments = this.profile.UI.Prompt.InitAttachments
365+
this.input.prompt = this.profile.LLM.CallOptions.Prompt.InitValue
366+
this.input.attachments = this.profile.LLM.CallOptions.Prompt.InitAttachments
367367
await this.processLLM(this.input, () => LLMWait())
368368
},
369369
async onInterrupt() {
@@ -423,7 +423,7 @@ export default {
423423
424424
AppMounted()
425425
.then(() => {
426-
if (this.$appProfile.UI.Prompt.InitValue && !stateAsString) {
426+
if (this.$appProfile.LLM.CallOptions.Prompt.InitValue && !stateAsString) {
427427
this.waitForLLM()
428428
}
429429
})

frontend/wailsjs/go/models.ts

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1837,8 +1837,58 @@ export namespace llm {
18371837
}
18381838
}
18391839

1840+
export class Message {
1841+
Role: string;
1842+
Content: string;
1843+
1844+
static createFrom(source: any = {}) {
1845+
return new Message(source);
1846+
}
1847+
1848+
constructor(source: any = {}) {
1849+
if ('string' === typeof source) source = JSON.parse(source);
1850+
this.Role = source["Role"];
1851+
this.Content = source["Content"];
1852+
}
1853+
}
1854+
export class PromptConfig {
1855+
System: string;
1856+
InitMessages: Message[];
1857+
InitValue: string;
1858+
InitAttachments: string[];
1859+
1860+
static createFrom(source: any = {}) {
1861+
return new PromptConfig(source);
1862+
}
1863+
1864+
constructor(source: any = {}) {
1865+
if ('string' === typeof source) source = JSON.parse(source);
1866+
this.System = source["System"];
1867+
this.InitMessages = this.convertValues(source["InitMessages"], Message);
1868+
this.InitValue = source["InitValue"];
1869+
this.InitAttachments = source["InitAttachments"];
1870+
}
1871+
1872+
convertValues(a: any, classs: any, asMap: boolean = false): any {
1873+
if (!a) {
1874+
return a;
1875+
}
1876+
if (a.slice && a.map) {
1877+
return (a as any[]).map(elem => this.convertValues(elem, classs));
1878+
} else if ("object" === typeof a) {
1879+
if (asMap) {
1880+
for (const key of Object.keys(a)) {
1881+
a[key] = new classs(a[key]);
1882+
}
1883+
return a;
1884+
}
1885+
return new classs(a);
1886+
}
1887+
return a;
1888+
}
1889+
}
18401890
export class CallOptionsConfig {
1841-
SystemPrompt: string;
1891+
Prompt: PromptConfig;
18421892
MaxToken: number;
18431893
Temperature: number;
18441894
TopK: number;
@@ -1852,14 +1902,32 @@ export namespace llm {
18521902

18531903
constructor(source: any = {}) {
18541904
if ('string' === typeof source) source = JSON.parse(source);
1855-
this.SystemPrompt = source["SystemPrompt"];
1905+
this.Prompt = this.convertValues(source["Prompt"], PromptConfig);
18561906
this.MaxToken = source["MaxToken"];
18571907
this.Temperature = source["Temperature"];
18581908
this.TopK = source["TopK"];
18591909
this.TopP = source["TopP"];
18601910
this.MinLength = source["MinLength"];
18611911
this.MaxLength = source["MaxLength"];
18621912
}
1913+
1914+
convertValues(a: any, classs: any, asMap: boolean = false): any {
1915+
if (!a) {
1916+
return a;
1917+
}
1918+
if (a.slice && a.map) {
1919+
return (a as any[]).map(elem => this.convertValues(elem, classs));
1920+
} else if ("object" === typeof a) {
1921+
if (asMap) {
1922+
for (const key of Object.keys(a)) {
1923+
a[key] = new classs(a[key]);
1924+
}
1925+
return a;
1926+
}
1927+
return new classs(a);
1928+
}
1929+
return a;
1930+
}
18631931
}
18641932
export class DeepSeekConfig {
18651933
APIKey: common.Secret;
@@ -2121,6 +2189,8 @@ export namespace llm {
21212189

21222190

21232191

2192+
2193+
21242194

21252195
}
21262196

@@ -2642,8 +2712,6 @@ export namespace model {
26422712
}
26432713
}
26442714
export class PromptConfig {
2645-
InitValue: string;
2646-
InitAttachments: string[];
26472715
MinRows?: number;
26482716
MaxRows?: number;
26492717
PinTop?: boolean;
@@ -2655,8 +2723,6 @@ export namespace model {
26552723

26562724
constructor(source: any = {}) {
26572725
if ('string' === typeof source) source = JSON.parse(source);
2658-
this.InitValue = source["InitValue"];
2659-
this.InitAttachments = source["InitAttachments"];
26602726
this.MinRows = source["MinRows"];
26612727
this.MaxRows = source["MaxRows"];
26622728
this.PinTop = source["PinTop"];

internal/config/config_test.go

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,37 +81,37 @@ func TestConfig_Parse(t *testing.T) {
8181
},
8282
{
8383
name: "Set UI prompt value",
84-
args: []string{"--ui.prompt.value=test"},
84+
args: []string{"--llm.call.prompt.init-value=test"},
8585
expected: modifiedConfig(func(c *model.Config) {
86-
c.MainProfile.UI.Prompt.InitValue = "test"
86+
c.MainProfile.LLM.CallOptions.Prompt.InitValue = "test"
8787
}),
8888
},
8989
{
9090
name: "Set UI prompt value - shorthand",
9191
args: []string{"-p=test"},
9292
expected: modifiedConfig(func(c *model.Config) {
93-
c.MainProfile.UI.Prompt.InitValue = "test"
93+
c.MainProfile.LLM.CallOptions.Prompt.InitValue = "test"
9494
}),
9595
},
9696
{
9797
name: "Set system prompt value",
98-
args: []string{"--llm.call.system-prompt=test"},
98+
args: []string{"--llm.call.prompt.system=test"},
9999
expected: modifiedConfig(func(c *model.Config) {
100-
c.MainProfile.LLM.CallOptions.SystemPrompt = "test"
100+
c.MainProfile.LLM.CallOptions.Prompt.System = "test"
101101
}),
102102
},
103103
{
104104
name: "Set UI prompt initial attachments",
105-
args: []string{"--ui.prompt.attachments.[0]=file1.txt", "--ui.prompt.attachments.[1]=file2.txt"},
105+
args: []string{"--llm.call.prompt.init-attachment.[0]=file1.txt", "--llm.call.prompt.init-attachment.[1]=file2.txt"},
106106
expected: modifiedConfig(func(c *model.Config) {
107-
c.MainProfile.UI.Prompt.InitAttachments = []string{"file1.txt", "file2.txt"}
107+
c.MainProfile.LLM.CallOptions.Prompt.InitAttachments = []string{"file1.txt", "file2.txt"}
108108
}),
109109
},
110110
{
111111
name: "Set UI prompt initial attachments - shorthand",
112112
args: []string{"-a=file1.txt", "-a=file2.txt"},
113113
expected: modifiedConfig(func(c *model.Config) {
114-
c.MainProfile.UI.Prompt.InitAttachments = []string{"file1.txt", "file2.txt"}
114+
c.MainProfile.LLM.CallOptions.Prompt.InitAttachments = []string{"file1.txt", "file2.txt"}
115115
}),
116116
},
117117
{
@@ -385,9 +385,9 @@ func TestConfig_Parse(t *testing.T) {
385385
},
386386
{
387387
name: "Set environment variable for init prompt",
388-
env: []string{EnvironmentPrefix + "=--ui.prompt.value=test"},
388+
env: []string{EnvironmentPrefix + "=--llm.call.prompt.init-value=test"},
389389
expected: modifiedConfig(func(c *model.Config) {
390-
c.MainProfile.UI.Prompt.InitValue = "test"
390+
c.MainProfile.LLM.CallOptions.Prompt.InitValue = "test"
391391
}),
392392
},
393393
{
@@ -470,11 +470,11 @@ func TestConfig_Parse(t *testing.T) {
470470
{
471471
name: "Set environment variable for UI prompt initial attachments",
472472
env: []string{
473-
EnvironmentPrefix + "=--ui.prompt.attachments.[1]=file2.txt",
474-
EnvironmentPrefix + "=--ui.prompt.attachments.[0]=file1.txt",
473+
EnvironmentPrefix + "=--llm.call.prompt.init-attachment.[1]=file2.txt",
474+
EnvironmentPrefix + "=--llm.call.prompt.init-attachment.[0]=file1.txt",
475475
},
476476
expected: modifiedConfig(func(c *model.Config) {
477-
c.MainProfile.UI.Prompt.InitAttachments = []string{"file1.txt", "file2.txt"}
477+
c.MainProfile.LLM.CallOptions.Prompt.InitAttachments = []string{"file1.txt", "file2.txt"}
478478
}),
479479
},
480480
{
@@ -672,10 +672,10 @@ func TestConfig_Parse(t *testing.T) {
672672
},
673673
{
674674
name: "Argument will override environment",
675-
args: []string{"--ui.prompt.value=arg-prompt"},
676-
env: []string{EnvironmentPrefix + "=--ui.prompt.value=env-prompt"},
675+
args: []string{"--llm.call.prompt.init-value=arg-prompt"},
676+
env: []string{EnvironmentPrefix + "=--llm.call.prompt.init-value=env-prompt"},
677677
expected: modifiedConfig(func(c *model.Config) {
678-
c.MainProfile.UI.Prompt.InitValue = "arg-prompt"
678+
c.MainProfile.LLM.CallOptions.Prompt.InitValue = "arg-prompt"
679679
}),
680680
},
681681
{
@@ -714,12 +714,12 @@ func TestConfig_Parse(t *testing.T) {
714714
args: []string{"--profiles.test.description=test", "-P", "test", "-p", "What is the answer?"},
715715
expected: modifiedConfig(func(c *model.Config) {
716716
c.ActiveProfile = "test"
717-
c.MainProfile.UI.Prompt.InitValue = "What is the answer?"
717+
c.MainProfile.LLM.CallOptions.Prompt.InitValue = "What is the answer?"
718718

719719
testProfile := &model.Profile{}
720720
yacl.NewConfig(testProfile).ApplyDefaults()
721721
testProfile.Meta.Description = "test"
722-
testProfile.UI.Prompt.InitValue = "What is the answer?"
722+
testProfile.LLM.CallOptions.Prompt.InitValue = "What is the answer?"
723723

724724
c.Profiles = map[string]*model.Profile{
725725
"test": testProfile,

internal/config/help.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,15 +173,19 @@ func printHelpConfig(output io.Writer) {
173173
},
174174
},
175175
CallOptions: llm.CallOptionsConfig{
176-
SystemPrompt: "You are a helpful assistant.",
176+
Prompt: llm.PromptConfig{
177+
System: "You are a helpful assistant.",
178+
},
177179
},
178180
},
179181
},
180182
Profiles: map[string]*model.Profile{
181183
"evil": {
182184
LLM: llm.LLMConfig{
183185
CallOptions: llm.CallOptionsConfig{
184-
SystemPrompt: "You are a evil assistant.",
186+
Prompt: llm.PromptConfig{
187+
System: "You are a evil assistant.",
188+
},
185189
},
186190
},
187191
},

internal/config/model/llm/calloptions.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ import (
66
)
77

88
type CallOptionsConfig struct {
9-
SystemPrompt string `yaml:"system-prompt,omitempty" short:"S" usage:"System Prompt"`
10-
MaxToken int `yaml:"max-token,omitempty" usage:"Max Token"`
11-
Temperature float64 `yaml:"temperature,omitempty" usage:"Temperature"`
12-
TopK int `yaml:"top-k,omitempty" usage:"Top-K"`
13-
TopP float64 `yaml:"top-p,omitempty" usage:"Top-P"`
14-
MinLength int `yaml:"min-length,omitempty" usage:"Min Length"`
15-
MaxLength int `yaml:"max-length,omitempty" usage:"Max Length"`
9+
Prompt PromptConfig `yaml:"prompt,omitempty"`
10+
MaxToken int `yaml:"max-token,omitempty" usage:"Max Token"`
11+
Temperature float64 `yaml:"temperature,omitempty" usage:"Temperature"`
12+
TopK int `yaml:"top-k,omitempty" usage:"Top-K"`
13+
TopP float64 `yaml:"top-p,omitempty" usage:"Top-P"`
14+
MinLength int `yaml:"min-length,omitempty" usage:"Min Length"`
15+
MaxLength int `yaml:"max-length,omitempty" usage:"Max Length"`
1616
}
1717

1818
func (c *CallOptionsConfig) AsOptions() (opts []llms.CallOption) {
@@ -58,5 +58,9 @@ func (c *CallOptionsConfig) Validate() error {
5858
return fmt.Errorf("LLM-Call Max Length")
5959
}
6060

61+
if ve := c.Prompt.Validate(); ve != nil {
62+
return ve
63+
}
64+
6165
return nil
6266
}

internal/config/model/llm/general.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ type LLMConfig struct {
3030
DeepSeek DeepSeekConfig `yaml:"deepseek,omitempty" usage:"DeepSeek " llm:""`
3131
Google GoogleAIConfig `yaml:"google,omitempty" usage:"Google " llm:""`
3232

33-
CallOptions CallOptionsConfig `yaml:"call,omitempty" usage:"Call option "`
33+
CallOptions CallOptionsConfig `yaml:"call,omitempty"`
3434
Tool tools.Config `yaml:"tool,omitempty"`
3535
}
3636

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package llm
2+
3+
import (
4+
"fmt"
5+
"github.com/tmc/langchaingo/llms"
6+
)
7+
8+
type PromptConfig struct {
9+
System string `yaml:"system,omitempty" short:"S" usage:"System Prompt"`
10+
11+
InitMessages []Message `yaml:"init-message,omitempty" usage:"initial message(s) to use: "`
12+
InitValue string `yaml:"init-value,omitempty" short:"p" usage:"the initial prompt to use"`
13+
InitAttachments []string `yaml:"init-attachment,omitempty" short:"a" usage:"the initial attachment(s) to use"`
14+
}
15+
16+
func (p *PromptConfig) Validate() error {
17+
for _, message := range p.InitMessages {
18+
if ve := message.Validate(); ve != nil {
19+
return ve
20+
}
21+
}
22+
return nil
23+
}
24+
25+
func (p *PromptConfig) HasInitialValues() bool {
26+
return p.InitValue != "" || len(p.InitMessages) > 0 || len(p.InitAttachments) > 0
27+
}
28+
29+
type Message struct {
30+
Role llms.ChatMessageType `yaml:"role,omitempty"`
31+
Content string `yaml:"content,omitempty" usage:"content"`
32+
}
33+
34+
func (m *Message) GetUsage(field string) string {
35+
switch field {
36+
case "Role":
37+
return fmt.Sprintf("role (%s, %s)", llms.ChatMessageTypeHuman, llms.ChatMessageTypeAI)
38+
}
39+
return ""
40+
}
41+
42+
func (m *Message) Validate() error {
43+
if m.Role != llms.ChatMessageTypeHuman && m.Role != llms.ChatMessageTypeAI {
44+
return fmt.Errorf("Invalid message role '%s', must be one of %s, %s!", m.Role, llms.ChatMessageTypeHuman, llms.ChatMessageTypeAI)
45+
}
46+
if m.Content == "" {
47+
return fmt.Errorf("Message content is required!")
48+
}
49+
return nil
50+
}

internal/config/model/ui_prompt.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,10 @@ package model
33
import "github.com/rainu/go-yacl"
44

55
type PromptConfig struct {
6-
InitValue string `yaml:"value,omitempty" short:"p" usage:"The (initial) prompt to use"`
7-
InitAttachments []string `yaml:"attachments,omitempty" short:"a" usage:"The (initial) attachments to use"`
8-
MinRows *uint `yaml:"min-rows,omitempty" usage:"The minimal number of rows the prompt should have"`
9-
MaxRows *uint `yaml:"max-rows,omitempty" usage:"The maximal number of rows the prompt should have"`
10-
PinTop *bool `yaml:"pin-top,omitempty" usage:"Pin the prompt input at the top of the window (otherwise pin at the bottom)"`
11-
SubmitShortcut Shortcut `yaml:"submit,omitempty" usage:"The shortcut for submit the prompt: "`
6+
MinRows *uint `yaml:"min-rows,omitempty" usage:"The minimal number of rows the prompt should have"`
7+
MaxRows *uint `yaml:"max-rows,omitempty" usage:"The maximal number of rows the prompt should have"`
8+
PinTop *bool `yaml:"pin-top,omitempty" usage:"Pin the prompt input at the top of the window (otherwise pin at the bottom)"`
9+
SubmitShortcut Shortcut `yaml:"submit,omitempty" usage:"The shortcut for submit the prompt: "`
1210
}
1311

1412
func (p *PromptConfig) SetDefaults() {

0 commit comments

Comments
 (0)