feat(agent): inject TTS [[tts]] directive guidance when auto mode is "tagged"

- Add TTSAutoMode field to LoopConfig, Loop, SystemPromptConfig
- Wire from config.Tts.Auto through resolver to system prompt
- Inject "## Voice Response" section explaining [[tts]] usage
- Update AGENTS.md: voice only when user explicitly requests
This commit is contained in:
viettranx committed 2026-04-16 18:55:43 +07:00
1 parent a050079ade
commit 085b89bf72
7 files changed
+43 -1

No files matched your search

+1
View File
@@ -235,6 +235,7 @@ func wireExtras(
SkillTenantCfgs: stores.SkillTenantCfgs,
SystemConfigs: stores.SystemConfigs,
Workspace: workspace,
TTSAutoMode: appCfg.Tts.Auto,
AutoInjector: autoInjector,
EvolutionMetricsStore: stores.EvolutionMetrics,
DomainBus: domainBus,
+1
View File
@@ -231,6 +231,7 @@ func (l *Loop) buildMessages(ctx context.Context, history []providers.Message, s
SandboxWorkspaceAccess: l.sandboxWorkspaceAccess,
ShellDenyGroups: l.shellDenyGroups,
SelfEvolve: l.selfEvolve,
TTSAutoMode: l.ttsAutoMode,
ProviderType: providerTypeOf(l.provider),
CredentialCLIContext: l.buildCredentialCLIContext(ctx),
IsBootstrap: hadBootstrap && l.agentType != store.AgentTypePredefined,
+8
View File
@@ -200,6 +200,9 @@ type Loop struct {
// Self-evolve: predefined agents can update SOUL.md through chat
selfEvolve bool
// TTS auto mode from config: "off", "always", "inbound", "tagged"
ttsAutoMode string
// Skill learning loop: when skillEvolve=true, the loop injects nudges reminding
// the agent to capture reusable patterns as skills via skill_manage.
skillEvolve bool
@@ -388,6 +391,10 @@ type LoopConfig struct {
// Self-evolve: predefined agents can update SOUL.md (style/tone) through chat
SelfEvolve bool
// TTS auto mode from config: "off", "always", "inbound", "tagged"
// When "tagged", inject [[tts]] directive guidance into system prompt.
TTSAutoMode string
// Skill evolution: agent learning loop config (from other_config JSONB)
SkillEvolve bool
SkillNudgeInterval int // 0 = disabled, 15 = default
@@ -529,6 +536,7 @@ func NewLoop(cfg LoopConfig) *Loop {
promptMode: cfg.PromptMode,
pinnedSkills: cfg.PinnedSkills,
selfEvolve: cfg.SelfEvolve,
ttsAutoMode: cfg.TTSAutoMode,
skillEvolve: cfg.SkillEvolve,
skillNudgeInterval: cfg.SkillNudgeInterval,
isTeamLead: cfg.IsTeamLead,
+4
View File
@@ -120,6 +120,9 @@ type ResolverDeps struct {
// Global workspace root (GOCLAW_WORKSPACE)
Workspace string
// TTS auto mode from config: "off", "always", "inbound", "tagged"
TTSAutoMode string
// V3 auto-inject: episodic memory injection into system prompt (nil = disabled)
AutoInjector memory.AutoInjector
@@ -511,6 +514,7 @@ func NewManagedResolver(deps ResolverDeps) ResolverFunc {
PromptMode: PromptMode(ag.ParsePromptMode()),
PinnedSkills: ag.ParsePinnedSkills(),
SelfEvolve: ag.ParseSelfEvolve(),
TTSAutoMode: deps.TTSAutoMode,
SkillEvolve: ag.AgentType == store.AgentTypePredefined && ag.ParseSkillEvolve(),
SkillNudgeInterval: ag.ParseSkillNudgeInterval(),
WorkspaceSharing: ag.ParseWorkspaceSharing(),
+9
View File
@@ -135,6 +135,10 @@ type SystemPromptConfig struct {
// Self-evolution: predefined agents can update SOUL.md (style/tone)
SelfEvolve bool
// TTSAutoMode: "off", "always", "inbound", "tagged". When "tagged", inject
// [[tts]] directive guidance so the agent knows how to trigger voice responses.
TTSAutoMode string
// ShellDenyGroups holds effective deny group overrides for this agent.
// nil = all defaults. Used to adapt system prompt instructions.
ShellDenyGroups map[string]bool
@@ -327,6 +331,11 @@ func BuildSystemPrompt(cfg SystemPromptConfig) string {
lines = append(lines, cfg.CredentialCLIContext, "")
}
// 2.6. ## Voice Response — inject when TTS auto mode is "tagged"
if (isFull || isTask) && !cfg.IsBootstrap && cfg.TTSAutoMode == "tagged" {
lines = append(lines, buildVoiceResponseSection()...)
}
// 3. ## Safety — task/none get slim version (keeps prompt injection defense)
if isTask || isNone {
lines = append(lines, buildSafetySlimSection()...)
+19
View File
@@ -729,3 +729,22 @@ func buildTeamMembersSection(members []store.TeamMemberData, teamGuidance string
lines = append(lines, "")
return lines
}
// buildVoiceResponseSection generates guidance for triggering auto TTS in "tagged" mode.
// When TTS auto mode is "tagged", agent responses containing [[tts]] are converted to voice.
func buildVoiceResponseSection() []string {
return []string{
"## Voice Response",
"",
"You can respond with voice/audio by wrapping text with `[[tts]]`:",
"",
"```",
"[[tts]]This text will be spoken aloud.[[/tts]]",
"```",
"",
"**ONLY use [[tts]] when the user explicitly asks for voice/audio response.**",
"Examples: \"read this aloud\", \"respond with voice\", \"speak this\", \"tell me a story (voice)\".",
"Do NOT add [[tts]] just because you think it would be nice — text is the default.",
"",
}
}
+1 -1
View File
@@ -113,4 +113,4 @@ Tips:
## Voice
If you have TTS capability, use voice for stories and "storytime" moments — more engaging than walls of text.
If you have TTS capability, only use voice when the user explicitly asks for it (e.g. "read aloud", "respond with voice", "tell me a story in voice").