Files
greeneclipse 8580c996c3 Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2026-08-09 22:47:43 +02:00

3.6 KiB

04 — AI fallback after FAQ miss

Agent: 4/10 (support-auto)
Status: Implemented
Coordinates with: 02-contract.md, 01-inventory.md, agent 3 MatchAutoReply


Goal

When Stage A FAQ/template match fails or confidence is below threshold, call the admin-configured platform AI (ai_roles.support) to draft or auto-send a labeled reply. On AI failure → leave the ticket claimable for humans.

No parallel BYOK secret store — reuse platformsettings.AIRoleSupport / aiprovider.ResolveCompleterForRole(..., RoleSupport).


Flow

MaybeAutoReplyOnCreate (after ticket Create)
  ├─ [sync] MatchAutoReply ≥ threshold → PostMatchedAutoReply (KB/template)
  └─ miss / low conf / FAQ off
        └─ EnqueueAIFallback → support_auto_jobs (async)
              └─ worker ProcessPendingAutoJobs
                    └─ TryAutoReplyLLM → CompleterSupportAI.RunAutoReply
                          ├─ draft (default) → internal system note (AI-assisted label)
                          ├─ auto_send → public system message + footer
                          └─ fail / low conf / handoff → auto_reply_disabled + handed_off

HTTP create never awaits the LLM. If migration 034 is missing, enqueue falls back to sync-with-timeout (AutoReplyTimeout = 25s).


Settings (support_auto_config)

Key Default Role
enabled false Master switch
ai_enabled false Stage B
ai_delivery draft draft | auto_send
ai_confidence_threshold 0.65 Min model confidence
ai_use_global_support_role true Use admin ai_roles.support
ai_model_override / ai_base_url_override empty Same API key; optional endpoint tweak

Also requires /admin/settings → AI roles → support enabled with key + model.


Symbols

Symbol Path
TryAutoReplyLLM apps/api/internal/support/ai_auto_reply.go
CompleterSupportAI apps/api/internal/support/ai_fallback.go
EnqueueAIFallback / ProcessPendingAutoJobs apps/api/internal/support/auto_jobs.go
MaybeAutoReplyOnCreate (miss → enqueue) apps/api/internal/support/match_auto_reply.go
BuildAutoReplyMessages apps/api/internal/support/auto_prompt.go
Migration apps/api/sql/schema/034_support_auto_jobs.sql

Wiring: httpapi.NewServer and cmd/worker set Support.SupportAI = NewCompleterSupportAI(aiSvc).


Security

  • Tenant isolation: ticket load checks company_id; prompts never mix tenants.
  • Ticket text wrapped as untrusted; secrets redacted before prompt/logs.
  • Rate limits: 10 AI jobs/company/hour, 30/platform/minute → handoff.
  • Logs: ticket_id, company_id, delivery, confidence — no bodies/keys/emails.
  • Docs Ask stays rule-based (never AIRoleSupport).

Labels

  • Public AI reply footer: “AI-assisted reply…”
  • Draft prefix: [AI draft — not visible to customer]
  • Handoff internal note: “Needs human review…”

Tests

cd apps/api
go test ./internal/support/ -count=1 -run "TestTryAutoReplyLLM|TestCompleterSupportAI|TestParseAIAssist|TestAIRate|TestBuildAutoReply|TestLabelAI"

Mock Completer covers draft JSON parse, low-confidence handoff, and redaction — no live OpenAI calls.


Manual check

  1. Enable support_auto.enabled + ai_enabled, set ai_delivery=draft or auto_send.
  2. Configure AI role support in admin settings.
  3. Create a ticket that does not match FAQ → job row → draft/send or handoff.
  4. Confirm ticket stays unassigned/claimable on AI failure.