diff --git a/pkg/agent/context.go b/pkg/agent/context.go index b7c6e1108..b3fea178b 100644 --- a/pkg/agent/context.go +++ b/pkg/agent/context.go @@ -78,7 +78,9 @@ Your workspace is at: %s 3. **Memory** - When interacting with me if something seems memorable, update %s/memory/MEMORY.md -4. **Context summaries** - Conversation summaries provided as context are approximate references only. They may be incomplete or outdated. Always defer to explicit user instructions over summary content.`, +4. **Context summaries** - Conversation summaries provided as context are approximate references only. They may be incomplete or outdated. Always defer to explicit user instructions over summary content. + +5. **Current Date Context** - When using the web_search tool, you MUST use the Current Time in the system context to construct accurate date-specific queries.`, workspacePath, workspacePath, workspacePath, workspacePath, workspacePath) } diff --git a/pkg/agent/context_cache_test.go b/pkg/agent/context_cache_test.go index ba70d4c0d..c4f539cc0 100644 --- a/pkg/agent/context_cache_test.go +++ b/pkg/agent/context_cache_test.go @@ -262,9 +262,9 @@ func TestCacheStability(t *testing.T) { } } - // Static prompt must NOT contain per-request data - if strings.Contains(results[0], "Current Time") { - t.Error("static cached prompt should not contain time (added dynamically)") + // Static prompt must NOT contain per-request data (the header/block itself) + if strings.Contains(results[0], "## Current Time") { + t.Error("static cached prompt should not contain time block (added dynamically)") } } diff --git a/pkg/agent/context_test.go b/pkg/agent/context_test.go index e023c9c30..722357ec3 100644 --- a/pkg/agent/context_test.go +++ b/pkg/agent/context_test.go @@ -1,7 +1,9 @@ package agent import ( + "strings" "testing" + "time" "github.com/sipeed/picoclaw/pkg/providers" ) @@ -207,3 +209,46 @@ func assertRoles(t *testing.T, msgs []providers.Message, expected ...string) { } } } + +func TestContextBuilder_WebSearchDateContext(t *testing.T) { + cb := NewContextBuilder(t.TempDir()) + + systemPrompt := cb.BuildSystemPrompt() + + expectedInstruction := "**Current Date Context** - When using the web_search tool, you MUST use the Current Time in the system context to construct accurate date-specific queries." + + if !strings.Contains(systemPrompt, expectedInstruction) { + t.Errorf("Expected system prompt to contain web_search date instruction, got:\n%s", systemPrompt) + } +} + +func TestContextBuilder_TimeInjection(t *testing.T) { + cb := NewContextBuilder(t.TempDir()) + // Note: BuildMessages includes the dynamic context (time) + messages := cb.BuildMessages(nil, "", "hello", nil, "discord", "123") + + if len(messages) == 0 { + t.Fatal("Expected messages, got none") + } + + systemPrompt := messages[0].Content + + // Verify the Current Time header exists + if !strings.Contains(systemPrompt, "## Current Time") { + t.Error("Expected system prompt to contain '## Current Time' header") + } + + // Verify it contains the current date year (e.g. "2026-") + currentYearStr := time.Now().Format("2006-") + if !strings.Contains(systemPrompt, currentYearStr) { + t.Errorf("Expected system prompt to contain current year prefix %q", currentYearStr) + } + + // Verify the relative ordering: Rule 5 should be in the static part (first), + // and Current Time should be in the dynamic part (second). + rulePos := strings.Index(systemPrompt, "Current Date Context") + timePos := strings.Index(systemPrompt, "## Current Time") + if rulePos == -1 || timePos == -1 || rulePos > timePos { + t.Errorf("Expected 'Current Date Context' to appear before '## Current Time'. rulePos=%d, timePos=%d", rulePos, timePos) + } +}