Package structure
Model routing
ThebuildModel function in agent/agent.go selects the model.LLM implementation based on the active provider:
OAuth + Google Antigravity
auth_method == "oauth" and oauth_provider == "google-antigravity"Uses newAntigravityModel — connects to cloudcode-pa.googleapis.com, handles ThoughtSignature parts, custom auth headers.OAuth (other providers)
auth_method == "oauth" with other providers.Uses newOpenAIModelWithTokenSource — OpenAI-compatible with auto-refreshing OAuth token callback.model.LLM interface and are wrapped in resilientModel for automatic retry with exponential backoff and context trimming on overflow errors:
genai.Content format and OpenAI’s message format, including role mapping ("model" to "assistant"), tool call assembly from streamed SSE chunks, and schema type case conversion.
ADK integration
Sorat uses Google ADK v0.4.0:| Component | Usage |
|---|---|
| Agent | llmagent.New() with model, instruction, and tools |
| Runner | runner.New() with app name, agent, and session service |
| Session service | session.InMemoryService() — ephemeral, reset on reinit |
| Tools | functiontool.New() with typed Go structs for args/results |
| Streaming | agent.RunConfig{StreamingMode: agent.StreamingModeSSE} |
Holder struct that supports lazy initialization and reinit.
Config hot-reload
When configuration changes via the admin API,reinitAgent() creates an entirely new ADK agent:
- New runner with updated model, instruction, and tools
- New in-memory session service (all active ADK sessions are lost)
- Persisted session messages on disk are preserved
- New tool instances with updated configuration
PUT /api/config, PUT /api/persona, PUT /api/soul, PUT /api/tools, skills changes.
Ephemeral agents
Cron jobs use ephemeral agents — temporary instances with:- Full tool set
- Loaded persona + soul
- 3-minute timeout
- Iteration and tool call tracking
- Results logged via
slog
Authentication flow
| Step | Description |
|---|---|
| Setup mode | No password configured — all requests allowed |
| Register | POST /api/auth/register creates super-admin |
| Login | POST /api/auth/login returns 24h bearer token |
| CLI token | Generated at startup, stored in ~/.sorat/.cli_token |
| Middleware | Exempts /api/auth/* and non-API paths |
Concurrency patterns
| Pattern | Usage |
|---|---|
| Config manager | sync.RWMutex for concurrent reads, exclusive writes |
| Agent holder | sync.RWMutex with lazy init and atomic swap on reinit |
| Ephemeral agents | Goroutine per cron job with 3-minute timeout |
| Cron service | 10-second ticker, jobs execute in goroutines |
| Atomic writes | All file persistence uses write-to-tmp + rename |