Skip to content

REST API and Web UI Now Support Dynamic Pattern Variables #1533

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

Merged
Show file tree
Hide file tree
Changes from all commits
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
27 changes: 0 additions & 27 deletions patterns/raycast/capture_thinkers_work

This file was deleted.

27 changes: 0 additions & 27 deletions patterns/raycast/create_story_explanation

This file was deleted.

27 changes: 0 additions & 27 deletions patterns/raycast/extract_primary_problem

This file was deleted.

27 changes: 0 additions & 27 deletions patterns/raycast/extract_wisdom

This file was deleted.

27 changes: 0 additions & 27 deletions patterns/raycast/yt

This file was deleted.

20 changes: 11 additions & 9 deletions restapi/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ type ChatHandler struct {
}

type PromptRequest struct {
UserInput string `json:"userInput"`
Vendor string `json:"vendor"`
Model string `json:"model"`
ContextName string `json:"contextName"`
PatternName string `json:"patternName"`
StrategyName string `json:"strategyName"` // Optional strategy name
UserInput string `json:"userInput"`
Vendor string `json:"vendor"`
Model string `json:"model"`
ContextName string `json:"contextName"`
PatternName string `json:"patternName"`
StrategyName string `json:"strategyName"` // Optional strategy name
Variables map[string]string `json:"variables,omitempty"` // Pattern variables
}

type ChatRequest struct {
Expand Down Expand Up @@ -118,9 +119,10 @@ func (h *ChatHandler) HandleChat(c *gin.Context) {
Role: "user",
Content: p.UserInput,
},
PatternName: p.PatternName,
ContextName: p.ContextName,
Language: request.Language, // Pass the language field
PatternName: p.PatternName,
ContextName: p.ContextName,
PatternVariables: p.Variables, // Pass pattern variables
Language: request.Language, // Pass the language field
}

opts := &common.ChatOptions{
Expand Down
105 changes: 105 additions & 0 deletions restapi/docs/API_VARIABLES_EXAMPLE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# REST API Pattern Variables Example

This example demonstrates how to use pattern variables in REST API calls to the `/chat` endpoint.

## Example: Using the `translate` pattern with variables

### Request

```json
{
"prompts": [
{
"userInput": "Hello my name is Kayvan",
"patternName": "translate",
"model": "gpt-4o",
"vendor": "openai",
"contextName": "",
"strategyName": "",
"variables": {
"lang_code": "fr"
}
}
],
"language": "en",
"temperature": 0.7,
"topP": 0.9,
"frequencyPenalty": 0.0,
"presencePenalty": 0.0
}
```

### Pattern Content

The `translate` pattern contains:

```markdown
You are an expert translator... translate them as accurately and perfectly as possible into the language specified by its language code {{lang_code}}...

...

- Translate the document as accurately as possible keeping a 1:1 copy of the original text translated to {{lang_code}}.

{{input}}
```

### How it works

1. The pattern is loaded from `patterns/translate/system.md`
2. The `{{lang_code}}` variable is replaced with `"fr"` from the variables map
3. The `{{input}}` placeholder is replaced with `"Hello my name is Kayvan"`
4. The resulting processed pattern is sent to the AI model

### Expected Result

The AI would receive a prompt asking it to translate "Hello my name is Kayvan" to French (fr), and would respond with something like "Bonjour, je m'appelle Kayvan".

## Testing with curl

```bash
curl -X POST http://localhost:8080/api/chat \
-H "Content-Type: application/json" \
-d '{
"prompts": [
{
"userInput": "Hello my name is Kayvan",
"patternName": "translate",
"model": "gpt-4o",
"vendor": "openai",
"variables": {
"lang_code": "fr"
}
}
],
"temperature": 0.7
}'
```

## Multiple Variables Example

For patterns that use multiple variables:

```json
{
"prompts": [
{
"userInput": "Analyze this business model",
"patternName": "custom_analysis",
"model": "gpt-4o",
"variables": {
"role": "expert consultant",
"experience": "15",
"focus_areas": "revenue, scalability, market fit",
"output_format": "bullet points"
}
}
]
}
```

## Implementation Details

- Variables are passed in the `variables` field as a key-value map
- Variables are processed using Go's template system
- The `{{input}}` variable is automatically handled and should not be included in the variables map
- Variables support the same features as CLI variables (plugins, extensions, etc.)
66 changes: 58 additions & 8 deletions restapi/patterns.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,70 @@ type PatternsHandler struct {

// NewPatternsHandler creates a new PatternsHandler
func NewPatternsHandler(r *gin.Engine, patterns *fsdb.PatternsEntity) (ret *PatternsHandler) {
ret = &PatternsHandler{
StorageHandler: NewStorageHandler(r, "patterns", patterns), patterns: patterns}
// Create a storage handler but don't register any routes yet
storageHandler := &StorageHandler[fsdb.Pattern]{storage: patterns}
ret = &PatternsHandler{StorageHandler: storageHandler, patterns: patterns}

// TODO: Add custom, replacement routes here
//r.GET("/patterns/:name", ret.Get)
// Register routes manually - use custom Get for patterns, others from StorageHandler
r.GET("/patterns/:name", ret.Get) // Custom method with variables support
r.GET("/patterns/names", ret.GetNames) // From StorageHandler
r.DELETE("/patterns/:name", ret.Delete) // From StorageHandler
r.GET("/patterns/exists/:name", ret.Exists) // From StorageHandler
r.PUT("/patterns/rename/:oldName/:newName", ret.Rename) // From StorageHandler
r.POST("/patterns/:name", ret.Save) // From StorageHandler
// Add POST route for patterns with variables in request body
r.POST("/patterns/:name/apply", ret.ApplyPattern)
return
}

// Get handles the GET /patterns/:name route
// Get handles the GET /patterns/:name route - returns raw pattern without variable processing
func (h *PatternsHandler) Get(c *gin.Context) {
name := c.Param("name")
variables := make(map[string]string) // Assuming variables are passed somehow
input := "" // Assuming input is passed somehow
pattern, err := h.patterns.GetApplyVariables(name, variables, input)

// Get the raw pattern content without any variable processing
content, err := h.patterns.Load(name + "/" + h.patterns.SystemPatternFile)
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
return
}

// Return raw pattern in the same format as the processed patterns
pattern := &fsdb.Pattern{
Name: name,
Description: "",
Pattern: string(content),
}
c.JSON(http.StatusOK, pattern)
}

// PatternApplyRequest represents the request body for applying a pattern
type PatternApplyRequest struct {
Input string `json:"input"`
Variables map[string]string `json:"variables,omitempty"`
}

// ApplyPattern handles the POST /patterns/:name/apply route
func (h *PatternsHandler) ApplyPattern(c *gin.Context) {
name := c.Param("name")

var request PatternApplyRequest
if err := c.ShouldBindJSON(&request); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

// Merge query parameters with request body variables (body takes precedence)
variables := make(map[string]string)
for key, values := range c.Request.URL.Query() {
if len(values) > 0 {
variables[key] = values[0]
}
}
for key, value := range request.Variables {
variables[key] = value
}

pattern, err := h.patterns.GetApplyVariables(name, variables, request.Input)
if err != nil {
c.JSON(http.StatusInternalServerError, err.Error())
return
Expand Down
Loading
Loading