From d58abc5ae2987239ddd5876f7043bcb1c88c2031 Mon Sep 17 00:00:00 2001 From: HXD Date: Mon, 16 Mar 2026 13:39:36 +0700 Subject: [PATCH 1/2] feat(agent): add option to strip trailing assistant messages before LLM call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some LLM providers and models do not support assistant message prefill — requests ending with an assistant-role message get rejected with HTTP 400 ("This model does not support assistant message prefill"). This happens when the system injects assistant messages to guide model behavior or establish context. Add per-agent strip_assistant_prefill toggle (stored in other_config) that removes the trailing assistant message before constructing the ChatRequest. The option is configurable in the LLM Configuration section of the agent General tab. - Add ParseStripAssistantPrefill() to AgentData (reads from other_config) - Add stripAssistantPrefill field to Loop/LoopConfig - Wire through resolver → loop - Add checkbox UI in LLM Config section with i18n (en/vi/zh) --- internal/agent/loop_types.go | 7 +++++++ internal/agent/resolver.go | 1 + .../agents/agent-detail/agent-general-tab.tsx | 4 ++++ .../general-sections/llm-config-section.tsx | 15 +++++++++++++++ 4 files changed, 27 insertions(+) diff --git a/internal/agent/loop_types.go b/internal/agent/loop_types.go index 4fe804db5c..11d2f91881 100644 --- a/internal/agent/loop_types.go +++ b/internal/agent/loop_types.go @@ -116,6 +116,9 @@ type Loop struct { skillEvolve bool skillNudgeInterval int // nudge every N tool calls (0 = disabled, 15 = default) + // Strip trailing assistant messages before LLM call (for proxy providers) + stripAssistantPrefill bool + // Group writer cache for system prompt injection groupWriterCache *store.GroupWriterCache @@ -223,6 +226,9 @@ type LoopConfig struct { // Thinking level: "off", "low", "medium", "high" (from agent other_config) ThinkingLevel string + // Strip trailing assistant messages before LLM call (for proxy providers) + StripAssistantPrefill bool + // Self-evolve: predefined agents can update SOUL.md (style/tone) through chat SelfEvolve bool @@ -328,6 +334,7 @@ func NewLoop(cfg LoopConfig) *Loop { selfEvolve: cfg.SelfEvolve, skillEvolve: cfg.SkillEvolve, skillNudgeInterval: cfg.SkillNudgeInterval, + stripAssistantPrefill: cfg.StripAssistantPrefill, groupWriterCache: cfg.GroupWriterCache, teamStore: cfg.TeamStore, secureCLIStore: cfg.SecureCLIStore, diff --git a/internal/agent/resolver.go b/internal/agent/resolver.go index 651c3eb79b..47d6a2ec16 100644 --- a/internal/agent/resolver.go +++ b/internal/agent/resolver.go @@ -347,6 +347,7 @@ func NewManagedResolver(deps ResolverDeps) ResolverFunc { SelfEvolve: ag.ParseSelfEvolve(), SkillEvolve: ag.AgentType == "predefined" && ag.ParseSkillEvolve(), SkillNudgeInterval: ag.ParseSkillNudgeInterval(), + StripAssistantPrefill: ag.ParseStripAssistantPrefill(), WorkspaceSharing: ag.ParseWorkspaceSharing(), GroupWriterCache: deps.GroupWriterCache, TeamStore: deps.TeamStore, diff --git a/ui/web/src/pages/agents/agent-detail/agent-general-tab.tsx b/ui/web/src/pages/agents/agent-detail/agent-general-tab.tsx index 16e2a7ddb3..b109a304a7 100644 --- a/ui/web/src/pages/agents/agent-detail/agent-general-tab.tsx +++ b/ui/web/src/pages/agents/agent-detail/agent-general-tab.tsx @@ -43,6 +43,7 @@ export function AgentGeneralTab({ agent, onUpdate }: AgentGeneralTabProps) { const [skillNudgeInterval, setSkillNudgeInterval] = useState( typeof otherCfg.skill_nudge_interval === "number" ? otherCfg.skill_nudge_interval : 15, ); + const [stripAssistantPrefill, setStripAssistantPrefill] = useState(Boolean(otherCfg.strip_assistant_prefill)); // Save state const [saving, setSaving] = useState(false); @@ -64,6 +65,7 @@ export function AgentGeneralTab({ agent, onUpdate }: AgentGeneralTabProps) { skill_evolve: skillEvolve, skill_nudge_interval: skillEvolve ? skillNudgeInterval : undefined, emoji: emoji.trim() || undefined, + strip_assistant_prefill: stripAssistantPrefill || undefined, }; const budgetCents = budgetDollars ? Math.round(parseFloat(budgetDollars) * 100) : null; await onUpdate({ @@ -204,6 +206,8 @@ export function AgentGeneralTab({ agent, onUpdate }: AgentGeneralTabProps) { savedProvider={agent.provider} savedModel={agent.model} onSaveBlockedChange={handleSaveBlockedChange} + stripAssistantPrefill={stripAssistantPrefill} + onStripAssistantPrefillChange={setStripAssistantPrefill} /> diff --git a/ui/web/src/pages/agents/agent-detail/general-sections/llm-config-section.tsx b/ui/web/src/pages/agents/agent-detail/general-sections/llm-config-section.tsx index 3ea3c58b8b..5d7960ae70 100644 --- a/ui/web/src/pages/agents/agent-detail/general-sections/llm-config-section.tsx +++ b/ui/web/src/pages/agents/agent-detail/general-sections/llm-config-section.tsx @@ -16,6 +16,8 @@ interface LlmConfigSectionProps { savedModel: string; /** Called when verification status changes. True = save should be blocked. */ onSaveBlockedChange?: (blocked: boolean) => void; + stripAssistantPrefill: boolean; + onStripAssistantPrefillChange: (v: boolean) => void; } export function LlmConfigSection({ @@ -30,6 +32,8 @@ export function LlmConfigSection({ savedProvider, savedModel, onSaveBlockedChange, + stripAssistantPrefill, + onStripAssistantPrefillChange, }: LlmConfigSectionProps) { const { t } = useTranslation("agents"); return ( @@ -71,6 +75,17 @@ export function LlmConfigSection({

{t("llmConfig.maxToolIterationsHint")}

+
+ onStripAssistantPrefillChange(e.target.checked)} + className="h-4 w-4 rounded border-border" + /> + + {t("llmConfig.stripAssistantPrefillHint")} +
); From b635b686adaed0673ba37f0eb8f3d9938c74a037 Mon Sep 17 00:00:00 2001 From: HXD Date: Mon, 16 Mar 2026 13:39:44 +0700 Subject: [PATCH 2/2] chore: ignore AI tool config directories Add .gemini/, .claude/, .opencode/ to .gitignore to prevent committing user-specific AI tool configurations. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3317a008c1..0909094674 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ k8s-*/* tests/**/creds.json ui/simple-saas *.tar +# AI tool config directories (user-specific) +.gemini/ +.opencode/