Files
computer-playbook/roles/web-app-zammad/files/ruby/apply/ai_provider.rb
kevinveenbirkenbachandClaude Opus 5 31fa1e5540 docs(zammad): state why the ruby apply scripts have no unit mirror
The lint wants either a mirrored unit test per role script or a
nocheck: mirrored-unit-test directive with a reason.

ai_provider.rb runs in the Zammad console and writes through Setting, whose
validator pings the gateway on save, so the round trip against the live
provider is the entire contract; a mocked transport would assert the mock.
mcp_bot.rb works against User, Role and Token and depends on the
before_create hook the live models supply, none of which is callable outside
the Zammad image.

There is no tests/unit/ruby tree for such a mirror to live in.

The first reason is confirmed by this session: writing the AI provider
setting is itself the reachability proof, because Setting.set pings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 13:13:39 +02:00

38 lines
1.5 KiB
Ruby

# nocheck: mirrored-unit-test - runs in the Zammad console and writes through Setting,
# whose validator pings the gateway on save; the round trip against the live provider is
# the entire contract
#
# Bind Zammad Smart Assist to the platform LiteLLM gateway.
#
# Order matters: ai_provider is the boolean "a provider is configured", and its
# validator (Setting::Validation::AIProvider) reads ai_provider_config, so the
# config hash has to land first or the flag is refused. Writing the config runs
# AI::Provider::CustomOpenAI.ping!, so this script fails outright when the
# gateway is unreachable or rejects the virtual key.
#
# Environment:
# AI_URL: OpenAI-compatible base URL of the gateway (provider appends /chat/completions).
# AI_MODEL: model name the gateway serves.
# AI_TOKEN: this role's virtual key; optional, sent as a bearer when present.
UserInfo.current_user_id = 1
config = {
"provider" => "custom_open_ai",
"url" => ENV.fetch("AI_URL"),
"model" => ENV.fetch("AI_MODEL"),
}
token = ENV.fetch("AI_TOKEN", "")
config["token"] = token unless token.empty?
Setting.set("ai_provider_config", config)
Setting.set("ai_provider", true)
Setting.set("ai_assistance_ticket_summary", true)
Setting.set("ai_assistance_text_tools", true)
stored = Setting.get("ai_provider_config") || {}
raise "ai_provider_config url is #{stored['url'].inspect}, expected #{ENV.fetch('AI_URL').inspect}" if stored["url"] != ENV.fetch("AI_URL")
raise "ai_provider is #{Setting.get('ai_provider').inspect}, expected true" unless Setting.get("ai_provider")