https only, the golem15.golem.ssrf.allowed_hosts allowlist (overridden by GOLEM15_SSRF_ALLOWED_HOSTS) with dotted-suffix entries, and a resolve-time check that every address is public, judged by fetchguard.IsPrivateAddr. Failures carry PHP's RuntimeException messages.
golem15.golem
The shared AI plugin for SummerCMS applications: provider adapters for the Anthropic Messages API and the OpenAI-compatible chat completions API, prompts and AI responses, and an AI service that sends them through the framework's guarded outbound client.
import _ "git.golem15.com/golem15/sm-golem-plugin"
Module git.golem15.com/golem15/sm-golem-plugin, package golem, plugin ID golem15.golem.
Overview
The plugin is a compiled SummerCMS plugin ported from the WinterCMS Golem15.Golem plugin. Its init registers it with the framework, so an application loads it by listing it in summer.yaml; summer build then emits the blank import above into the application's plugins.gen.go. Another plugin that sends AI requests lists golem15.golem in its Requires() and imports the classes/... packages.
The adapters are hand-written JSON mappings with no vendor SDK. Every request goes through a fetchguard.Client: a config marked Trusted (a model an operator configured) runs in fetchguard.TrustedMode, every other config (a key a user or an organisation supplied) in fetchguard.PublicOnlyMode, which refuses private and reserved addresses at dial time.
The plugin's config keys, lang namespace and plugin ID are a contract shared by every application that mounts it: change them only in a backwards-compatible way.
Features
- Prompts.
valueobjects.Promptis an immutable request: a system prompt, user and assistant messages, messages with base64 images (AddUserMessageWithImage,AddUserMessageWithImages) or an uploaded file id (AddUserMessageWithFileID), a model override and extra options in insertion order.ToAPIPayloadbuilds the OpenAI chat completions body as avalueobjects.Payload, a JSON object that keeps its key order. - Responses.
valueobjects.AIResponsecarries the content, token usage and the provider's decoded answer (Raw, which keepsfinish_reasonandstop_reason) or the failure message.Errholds the Go error behind a failure for logs and tests and is never shown to a user. - OpenAI-compatible adapter.
providers.OpenAIAdapterposts to<base>/chat/completionswithAuthorization: Bearer, dropsresponse_format, mapsmax_tokenstomax_completion_tokensand addsreasoning_effort: lowfor o-series and gpt-5 models. It also serves compatible providers through their base URL.providers.ForNamepicks the adapter by name. - AI service.
services.AIService.Sendapplies the model's system prompt when the prompt has none and posts the prompt to the config's chat endpoint. It returns the WinterCMS plugin's failure messages: no model configured, no API key, no connection, and an answer that is not JSON.services.ForAppreturns the application's shared service.
Usage
Mount the plugin in an application as a git submodule at plugins/golem15/golem:
git submodule add git@git.golem15.com:golem15/sm-golem-plugin.git plugins/golem15/golem
Add it to the application's go.work and go.mod:
use ./plugins/golem15/golem
require git.golem15.com/golem15/sm-golem-plugin v0.0.0
replace git.golem15.com/golem15/sm-golem-plugin => ./plugins/golem15/golem
List it in summer.yaml before the plugins that require it and run summer build:
module: git.golem15.com/golem15/acme
binary: acme
plugins:
- id: golem15.golem
module: git.golem15.com/golem15/sm-golem-plugin
- id: acme.blog
module: git.golem15.com/golem15/acme/plugins/acme/blog
The plugin's own go.mod replaces the framework with ../../../../summercms.go, so it expects the framework checkout next to the application checkout.
A plugin sends a prompt with a user's own key:
svc := services.ForApp(app)
prompt := valueobjects.NewPrompt().
WithSystem("You catalog physical items.").
AddUserMessage("List the items.")
res := svc.Send(ctx, prompt, &services.ModelConfig{
Adapter: "openai",
APIKey: key,
Model: "gpt-4o-mini",
})
if !res.Success {
return errors.New(res.Error)
}
API reference
golem:Plugin, thegolem15.golemplugin.classes/valueobjects:Prompt,NewPrompt,Message,ContentPart,ImageURL,FileRef,Image,Payload,NewPayload,AIResponse,Success,Failure.classes/providers:Adapter,OpenAIAdapter,ForName,OpenAIBaseURL,AnthropicBaseURL.classes/services:ModelConfig,DefaultModelID,AIService,NewAIService,ForApp,ConfigTimeoutSeconds,DefaultTimeout.
Configuration
Defaults live in config/config.yaml and are merged under golem15.golem.*.
| Key | Default | Meaning |
|---|---|---|
golem15.golem.ssrf.allowed_hosts |
oaidalleapiprodscus.blob.core.windows.net, .openai.com |
Hosts an untrusted base URL or an AI-returned image URL may use. A leading dot matches any subdomain. |
golem15.golem.ai.timeout_seconds |
120 |
Timeout of every AI provider request. |
Dependencies
- The SummerCMS framework,
git.golem15.com/golem15/summercms(modulesbackpack,compass,fetchguard,pact,party). - GORM, as pinned in
go.mod.
Testing
go test ./...