From 72c4066210b58a7f76b76f6d53e7223a33177a27 Mon Sep 17 00:00:00 2001 From: dj-oyu <68707227+dj-oyu@users.noreply.github.com> Date: Tue, 24 Feb 2026 17:16:59 +0900 Subject: [PATCH] feat: capture last system prompt sent to LLM for Mini App display GetSystemPrompt() now returns the exact system prompt that was last sent to the LLM provider (including summary, channel info, and background preamble), instead of rebuilding from current state which may differ. Co-Authored-By: Claude Opus 4.6 --- pkg/agent/loop.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 20b806a22..4c2f8c4bc 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -90,6 +90,7 @@ type AgentLoop struct { sessionLocks sync.Map // sessionKey → *sessionSemaphore activeTasks sync.Map // sessionKey → *activeTask sessions *SessionTracker + lastSystemPrompt atomic.Value // string — last system prompt sent to LLM OnStateChange func() // called on plan/session/skills mutations OnUserMessage func() // called when a real user message is processed } @@ -810,6 +811,9 @@ func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opt // 1. Update tool contexts al.updateToolContexts(agent, opts.Channel, opts.ChatID) + // 1a. Set session-specific working directory for bootstrap file lookup + agent.ContextBuilder.SetWorkDir(agent.EffectiveWorkspace(opts.SessionKey)) + // 1b. Inject peer session awareness into system prompt projectPath := agent.ContextBuilder.GetPlanWorkDir() if projectPath == "" { @@ -904,6 +908,11 @@ func (al *AgentLoop) runAgentLoop(ctx context.Context, agent *AgentInstance, opt al.stats.RecordPrompt() } + // Capture the finalized system prompt for Mini App inspection + if len(messages) > 0 { + al.lastSystemPrompt.Store(messages[0].Content) + } + // 5. Run LLM iteration loop finalContent, iteration, err := al.runLLMIteration(ctx, agent, messages, opts, task, preStatus) if err != nil { @@ -2450,6 +2459,33 @@ func (al *AgentLoop) GetSessionStats() *stats.Stats { return &s } +// GetContextInfo returns the bootstrap file resolution and directory context for the default agent. +func (al *AgentLoop) GetContextInfo() (workDir, planWorkDir, workspace string, bootstrap []BootstrapFileInfo) { + agent := al.registry.GetDefaultAgent() + if agent == nil { + return "", "", "", nil + } + workspace = agent.Workspace + planWorkDir = agent.ContextBuilder.GetPlanWorkDir() + workDir = agent.ContextBuilder.workDir + bootstrap = agent.ContextBuilder.ResolveBootstrapPaths() + return +} + +// GetSystemPrompt returns the system prompt last sent to the LLM. +// Falls back to building from current state if no LLM call has occurred yet. +func (al *AgentLoop) GetSystemPrompt() string { + if v := al.lastSystemPrompt.Load(); v != nil { + return v.(string) + } + // Fallback: no LLM call yet — build from current state + agent := al.registry.GetDefaultAgent() + if agent == nil { + return "" + } + return agent.ContextBuilder.BuildSystemPrompt() +} + // formatMessagesForLog formats messages for logging func formatMessagesForLog(messages []providers.Message) string { if len(messages) == 0 {