mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat: init go structure & add agent structure
This commit is contained in:
Vendored
+4
-1
@@ -24,7 +24,10 @@
|
|||||||
"editor.tabSize": 2,
|
"editor.tabSize": 2,
|
||||||
"editor.insertSpaces": true
|
"editor.insertSpaces": true
|
||||||
},
|
},
|
||||||
|
"[go]": {
|
||||||
|
"editor.tabSize": 4,
|
||||||
|
"editor.insertSpaces": true
|
||||||
|
},
|
||||||
"[python]": {
|
"[python]": {
|
||||||
"editor.tabSize": 4,
|
"editor.tabSize": 4,
|
||||||
"editor.insertSpaces": true
|
"editor.insertSpaces": true
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package agent
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/firebase/genkit/go/ai"
|
||||||
|
"github.com/firebase/genkit/go/genkit"
|
||||||
|
"github.com/firebase/genkit/go/plugins/googlegenai"
|
||||||
|
|
||||||
|
"github.com/memohai/Memoh/model"
|
||||||
|
"github.com/memohai/Memoh/agent/prompts"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AgentParams struct {
|
||||||
|
Model model.Model
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentInput struct {
|
||||||
|
content string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AgentOperations struct {
|
||||||
|
Ask func(input AgentInput) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAgent(params AgentParams) AgentOperations {
|
||||||
|
return AgentOperations{
|
||||||
|
Ask: func(input AgentInput) (string, error) {
|
||||||
|
return "", nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
package prompts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Schedule represents a scheduled task
|
||||||
|
type Schedule struct {
|
||||||
|
ID string
|
||||||
|
Pattern string
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
Command string
|
||||||
|
MaxCalls *int // nil means unlimited
|
||||||
|
}
|
||||||
|
|
||||||
|
// ScheduleParams contains parameters for generating the schedule prompt
|
||||||
|
type ScheduleParams struct {
|
||||||
|
Schedule Schedule
|
||||||
|
Locale string // e.g., "en-US", "zh-CN"
|
||||||
|
Date time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// scheduleTemplateData holds data for the schedule prompt template
|
||||||
|
type scheduleTemplateData struct {
|
||||||
|
Time string
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
ID string
|
||||||
|
MaxCalls string
|
||||||
|
Pattern string
|
||||||
|
Command string
|
||||||
|
}
|
||||||
|
|
||||||
|
const schedulePromptTemplate = `---
|
||||||
|
notice: **This is a scheduled task automatically send to you by the system, not the user input**
|
||||||
|
{{.Time}}
|
||||||
|
schedule-name: {{.Name}}
|
||||||
|
schedule-description: {{.Description}}
|
||||||
|
schedule-id: {{.ID}}
|
||||||
|
max-calls: {{.MaxCalls}}
|
||||||
|
cron-pattern: {{.Pattern}}
|
||||||
|
---
|
||||||
|
|
||||||
|
**COMMAND**
|
||||||
|
|
||||||
|
{{.Command}}`
|
||||||
|
|
||||||
|
var scheduleTmpl *template.Template
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var err error
|
||||||
|
scheduleTmpl, err = template.New("schedule").Parse(schedulePromptTemplate)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SchedulePrompt generates the prompt for a scheduled task
|
||||||
|
func SchedulePrompt(params ScheduleParams) string {
|
||||||
|
timeStr := Time(TimeParams{
|
||||||
|
Date: params.Date,
|
||||||
|
Locale: params.Locale,
|
||||||
|
})
|
||||||
|
|
||||||
|
maxCallsStr := "Unlimited"
|
||||||
|
if params.Schedule.MaxCalls != nil {
|
||||||
|
maxCallsStr = fmt.Sprintf("%d", *params.Schedule.MaxCalls)
|
||||||
|
}
|
||||||
|
|
||||||
|
data := scheduleTemplateData{
|
||||||
|
Time: timeStr,
|
||||||
|
Name: params.Schedule.Name,
|
||||||
|
Description: params.Schedule.Description,
|
||||||
|
ID: params.Schedule.ID,
|
||||||
|
MaxCalls: maxCallsStr,
|
||||||
|
Pattern: params.Schedule.Pattern,
|
||||||
|
Command: params.Schedule.Command,
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := scheduleTmpl.Execute(&buf, data); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(buf.String())
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package prompts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TimeParams contains parameters for formatting time
|
||||||
|
type TimeParams struct {
|
||||||
|
Date time.Time
|
||||||
|
Locale string // e.g., "en-US", "zh-CN"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Time formats the date and time according to the locale
|
||||||
|
func Time(params TimeParams) string {
|
||||||
|
dateStr := params.Date.Format("2006-01-02")
|
||||||
|
timeStr := params.Date.Format("15:04:05")
|
||||||
|
|
||||||
|
return fmt.Sprintf("date: %s\ntime: %s", dateStr, timeStr)
|
||||||
|
}
|
||||||
@@ -0,0 +1,112 @@
|
|||||||
|
package prompts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Platform represents a messaging platform
|
||||||
|
type Platform struct {
|
||||||
|
ID string
|
||||||
|
Name string
|
||||||
|
Config map[string]interface{}
|
||||||
|
Active bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemParams contains parameters for generating the system prompt
|
||||||
|
type SystemParams struct {
|
||||||
|
Date time.Time
|
||||||
|
Locale string // e.g., "en-US", "zh-CN"
|
||||||
|
Language string
|
||||||
|
MaxContextLoadTime int // in minutes
|
||||||
|
Platforms []Platform
|
||||||
|
CurrentPlatform string
|
||||||
|
}
|
||||||
|
|
||||||
|
// systemTemplateData holds data for the system prompt template
|
||||||
|
type systemTemplateData struct {
|
||||||
|
Time string
|
||||||
|
Language string
|
||||||
|
Platforms []Platform
|
||||||
|
CurrentPlatform string
|
||||||
|
MaxContextLoadTime int
|
||||||
|
}
|
||||||
|
|
||||||
|
const systemPromptTemplate = `---
|
||||||
|
{{.Time}}
|
||||||
|
language: {{.Language}}
|
||||||
|
available-platforms:
|
||||||
|
{{- if .Platforms}}
|
||||||
|
{{- range .Platforms}}
|
||||||
|
- {{.Name}}
|
||||||
|
{{- end}}
|
||||||
|
{{- else}}
|
||||||
|
(none)
|
||||||
|
{{- end}}
|
||||||
|
current-platform: {{.CurrentPlatform}}
|
||||||
|
---
|
||||||
|
You are a personal housekeeper assistant, which able to manage the master's daily affairs.
|
||||||
|
|
||||||
|
Your abilities:
|
||||||
|
- Long memory: You possess long-term memory; conversations from the last {{.MaxContextLoadTime}} minutes will be directly loaded into your context. Additionally, you can use tools to search for past memories.
|
||||||
|
- Scheduled tasks: You can create scheduled tasks to automatically remind you to do something.
|
||||||
|
- Messaging: You may allowed to use message software to send messages to the master.
|
||||||
|
|
||||||
|
**Memory**
|
||||||
|
- Your context has been loaded from the last {{.MaxContextLoadTime}} minutes.
|
||||||
|
- You can use {{quote "search-memory"}} to search for past memories with natural language.
|
||||||
|
|
||||||
|
**Schedule**
|
||||||
|
- We use **Cron Syntax** to schedule tasks.
|
||||||
|
- You can use {{quote "get-schedules"}} to get the list of schedules.
|
||||||
|
- You can use {{quote "remove-schedule"}} to remove a schedule by id.
|
||||||
|
- You can use {{quote "schedule"}} to schedule a task.
|
||||||
|
+ The {{quote "pattern"}} is the pattern of the schedule with **Cron Syntax**.
|
||||||
|
+ The {{quote "command"}} is the natural language command to execute, will send to you when the schedule is triggered, which means the command will be executed by presence of you.
|
||||||
|
+ The {{quote "maxCalls"}} is the maximum number of calls to the schedule, If you want to run the task only once, set it to 1.
|
||||||
|
- The {{quote "command"}} should include the method (e.g. {{quote "send-message"}}) for returning the task result. If the user does not specify otherwise, the user should be asked how they would like to be notified.
|
||||||
|
|
||||||
|
**Message**
|
||||||
|
- You can use {{quote "send-message"}} to send a message to the master.
|
||||||
|
+ The {{quote "platform"}} is the platform to send the message to, it must be one of the {{quote "available-platforms"}}.
|
||||||
|
+ The {{quote "message"}} is the message to send.
|
||||||
|
+ IF: the problem is initiated by a user, regardless of the platform the user is using, the content should be directly output in the content.
|
||||||
|
+ IF: the issue is initiated by a non-user (such as a scheduled task reminder), then it should be sent using the appropriate tools on the platform specified in the requirements.`
|
||||||
|
|
||||||
|
var systemTmpl *template.Template
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
var err error
|
||||||
|
systemTmpl = template.New("system").Funcs(template.FuncMap{
|
||||||
|
"quote": Quote,
|
||||||
|
})
|
||||||
|
systemTmpl, err = systemTmpl.Parse(systemPromptTemplate)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemPrompt generates the system prompt for the agent
|
||||||
|
func SystemPrompt(params SystemParams) string {
|
||||||
|
timeStr := Time(TimeParams{
|
||||||
|
Date: params.Date,
|
||||||
|
Locale: params.Locale,
|
||||||
|
})
|
||||||
|
|
||||||
|
data := systemTemplateData{
|
||||||
|
Time: timeStr,
|
||||||
|
Language: params.Language,
|
||||||
|
Platforms: params.Platforms,
|
||||||
|
CurrentPlatform: params.CurrentPlatform,
|
||||||
|
MaxContextLoadTime: params.MaxContextLoadTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := systemTmpl.Execute(&buf, data); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.TrimSpace(buf.String())
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package prompts
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Quote wraps content with backticks
|
||||||
|
func Quote(content string) string {
|
||||||
|
return fmt.Sprintf("`%s`", content)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Block wraps content in a code block with optional tag
|
||||||
|
func Block(content string, tag string) string {
|
||||||
|
if tag != "" {
|
||||||
|
return fmt.Sprintf("```%s\n%s\n```", tag, content)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("```\n%s\n```", content)
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module github.com/memohai/Memoh
|
||||||
|
|
||||||
|
go 1.25.6
|
||||||
|
|
||||||
|
require github.com/firebase/genkit/go v1.4.0 // indirect
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
github.com/firebase/genkit/go v1.4.0 h1:CP1hNWk7z0hosyY53zMH6MFKFO1fMLtj58jGPllQo6I=
|
||||||
|
github.com/firebase/genkit/go v1.4.0/go.mod h1:HX6m7QOaGc3MDNr/DrpQZrzPLzxeuLxrkTvfFtCYlGw=
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import "github.com/memohai/Memoh/model/provider"
|
||||||
|
|
||||||
|
type Model struct {
|
||||||
|
Provider provider.Provider
|
||||||
|
ModelID string
|
||||||
|
BaseURL string
|
||||||
|
APIKey string
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package provider
|
||||||
|
|
||||||
|
type Provider int
|
||||||
|
|
||||||
|
const (
|
||||||
|
OpenAI Provider = iota
|
||||||
|
Anthropic
|
||||||
|
Google
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p Provider) String() string {
|
||||||
|
return []string{
|
||||||
|
"openai",
|
||||||
|
"anthropic",
|
||||||
|
"google",
|
||||||
|
}[p]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user