Skip to content
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: 27 additions & 0 deletions pkg/script/prompt_backend_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package script_test

import (
"strings"
"testing"

"github.com/vinodhalaharvi/agentscript/pkg/script"
)

// The grammar prompt must teach BOTH backends and default to memory.
// Regression guard for the bug where the prompt only ever showed
// "temporal static ( ... )", so the LLM emitted temporal even when the
// user said "in memory" — and memory-only verbs were then rejected as
// "not available on this backend".
func TestBuildPrompt_TeachesBothBackendsDefaultMemory(t *testing.T) {
p := script.BuildPrompt(script.DefaultRegistry())
for _, want := range []string{
"memory static", // memory block form taught
"temporal static", // temporal block form taught
"DEFAULT", // memory is the default
"in memory", // explicit "in memory" → memory
} {
if !strings.Contains(p, want) {
t.Errorf("prompt should contain %q so the LLM can pick the memory backend", want)
}
}
}
34 changes: 25 additions & 9 deletions pkg/script/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,25 +69,41 @@ func BuildPrompt(reg *registry.Registry) string {
return `You translate a user's request into a small pipeline language called AgentScript. Output ONLY the AgentScript program — no prose, no explanation, no code fences.

GRAMMAR
A program is a single block:
temporal static ( <pipeline> )
A program is a single block that names an execution backend:
memory static ( <pipeline> ) ← runs in-process, immediately
temporal static ( <pipeline> ) ← runs as a durable workflow
A pipeline is one or more commands joined by >=> (sequential, left output feeds right):
command "arg" >=> command "arg" >=> command
Parallel fan-out exists as <*> inside parentheses, but use it ONLY when the request is an explicit, unambiguous flat list of independent things to do at once. When in doubt, use sequential >=> .

CHOOSING THE BACKEND
- Use ` + "`memory`" + ` by DEFAULT — for research, summarizing, reading files, asking questions, analysis, and almost everything. It runs the full command set immediately.
- Use ` + "`temporal`" + ` ONLY when the user explicitly asks for a durable, long-running, scheduled, or background workflow. Currently only the ` + "`echo`" + ` command runs on temporal.
- If the user says "in memory", "locally", "quickly", or doesn't mention durability, use ` + "`memory`" + `.

AVAILABLE COMMANDS (you may use ONLY these — never invent a command):
` + available + `

RULES
1. Output exactly one block: temporal static ( ... ). Nothing else.
2. Use only commands from the AVAILABLE COMMANDS list. If the request needs a command that does not exist, choose the closest available command; do not invent names.
3. Prefer sequential >=> . Use <*> only for a clear list of independent parallel actions.
4. String arguments are double-quoted. Pass the user's intent as the argument text.
5. Keep it minimal — the smallest pipeline that satisfies the request.
1. Output exactly one block: ` + "`memory static ( ... )`" + ` or ` + "`temporal static ( ... )`" + `. Nothing else.
2. Default to the memory backend unless durability is explicitly requested.
3. Use only commands from the AVAILABLE COMMANDS list. If the request needs a command that does not exist, choose the closest available command; do not invent names.
4. Prefer sequential >=> . Use <*> only for a clear list of independent parallel actions.
5. String arguments are double-quoted. Pass the user's intent as the argument text.
6. Keep it minimal — the smallest pipeline that satisfies the request.

EXAMPLES
Request: summarize this article about climate policy
Output: memory static ( summarize "this article about climate policy" )

Request: research Google and Microsoft strengths, then tell me who is winning
Output: memory static ( ( search "Google strengths" >=> analyze "strengths" <*> search "Microsoft strengths" >=> analyze "strengths" ) >=> merge >=> ask "who is winning?" )

EXAMPLE
Request: say hello to the team
Output: temporal static ( echo "hello to the team" )`
Output: memory static ( echo "hello to the team" )

Request: run a durable workflow that echoes hello
Output: temporal static ( echo "hello" )`
}

// cleanDSL strips common LLM wrapping (code fences, leading/trailing
Expand Down
Loading