Register Requesty (https://router.requesty.ai/v1) next to OpenRouter on the
existing OpenAI-compatible transport: config and env vars
(GOCLAW_REQUESTY_API_KEY, GOCLAW_REQUESTY_BASE_URL), secret masking, DB and
in-memory registration, CLI setup, doctor, placeholder provider, OpenAPI enum,
Web/Desktop provider lists and docs.
The models list merges Requesty managed policies (GET /models/managed) with
the key's catalog from GET /models.
* feat(hooks/observe): add structured output validation hook (ObserveHook)
- hooks/types.go: Add ObserveHook interface + BuiltInHookType enum
- hooks/dispatcher.go: HookDispatcher emits ObserveHook with PhaseResult payload
- pipeline/observe_stage.go: ObserveStage emits hook after ObserveResult built
- pipeline/substates.go: ObserveStageResult carries hook results + validation errors
- hooks/config.go: BuiltInHookTypeObserve added to BuiltInHookType enum
PhaseResult carries structured output, token usage, tool calls + validation errors
emitted post-ObserveStage. ObserveHook implementations can validate structured
output against schemas, detect tool-call loops, enforce token budgets, etc.
Hook fires after ObserveStage produces ObserveResult, before results propagate
to next stage. ValidationError returned by hook halts pipeline and propagates
error to caller without further stage execution.
Co-Authored-By: Claude <noreply@anthropic.com>
* ui(hooks): add post_model_response event to web UI
- Add event to Zod schema, filter dropdown, and form dialog
- Implement conditional test panel UI for model response payload
- Add translations (en/zh/vi) for new test panel fields
- Updated beta description to reference the new event
Co-Authored-By: Claude <noreply@anthropic.com>
* feat(mcp): add MCP CRUD server exposing goclaw resources at /api/mcp/ with Bearer token auth
and X-GoClaw-Tenant-Id header, default to master tenant
* feat(mcp): add goclaw_skills_write_file tool to edit skill files on disk
The CRUD MCP server's goclaw_skills_update only touched skill DB metadata,
with no way to edit a skill's SKILL.md/file content on the filesystem. Extract
the versioned write logic from the web UI's skill file editor
(SkillsHandler.handleWriteFile) into skills.WriteVersionedFile so both
surfaces share identical validation and versioning, and expose it as a new
MCP tool.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
---------
Co-authored-by: Bruno Clermont <bruno.clermont@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
* feat(providers): add Google Cloud Vertex AI provider (#576)
Add `vertex` built-in provider type that routes Gemini calls through Google
Cloud Vertex AI's OpenAI-compatible endpoint. Enterprises on GCP can now use
regional endpoints for data residency, consolidate AI spend under existing GCP
billing, enforce IAM/VPC-SC controls, and use committed-use discounts instead
of standalone Google AI Studio API keys.
Implementation reuses OpenAIProvider via the OpenAI-compat path; the only
provider-specific logic is OAuth2 auth wiring:
- New factory NewVertexProvider in internal/providers/vertex.go builds an
*http.Client with oauth2.Transport, which auto-refreshes GCP access tokens
(1-hour lifetime) transparently. Credentials precedence:
inline SA JSON > credentials_file path > Application Default Credentials
(works on GKE/Cloud Run/Compute Engine via metadata server).
- OpenAIProvider gets WithHTTPClient() + WithoutAuthHeader() options so the
oauth2 transport injects Authorization rather than doRequest() setting a
static Bearer header.
- Endpoint URL computed at registration time from project_id + region:
https://{region}-aiplatform.googleapis.com/v1/projects/{p}/locations/{r}/endpoints/openapi
- Store: api_key column holds AES-256-GCM-encrypted SA JSON (same as other
providers); settings JSONB holds {project_id, region, model}.
- Env vars: GOCLAW_VERTEX_{API_KEY,CREDENTIALS_FILE,PROJECT_ID,REGION,MODEL}.
Registration wired through all three paths: config-driven startup, DB-driven
startup, and HTTP CRUD in-memory registration. Vertex handled before the
generic "api_key empty" guard so ADC deployments register correctly.
Code-review fixes applied:
- H1 (correctness): Gemini thought_signature detection in openai.go now
recognizes providerType="vertex" and apiBase suffix "aiplatform". Previously
only worked because the default model string coincidentally contained
"gemini"; custom model IDs or fine-tuned endpoint numeric IDs would drop the
signature on passback and trigger HTTP 400 mid-tool-loop. Regression test
added (TestVertexProviderForwardsThoughtSignatureOnToolCalls).
- M1 (hardening): region and project_id are regex-validated before URL
concatenation to prevent hostname injection (e.g. region="evil.com/a?").
- M2 (hardening): APIBaseOverride must be https + *.googleapis.com host to
prevent data exfiltration via crafted DB rows.
- M3 (documentation): CredentialsFile marked operator-only in the struct
comment — never expose via admin UI or DB settings without path allow-list.
Tests: 17 Vertex-related unit tests. go build ./... + go build -tags sqliteonly
./... + go vet ./... all clean. Pre-existing TestSignMediaPath failure on
Windows (file_token.go uses path/filepath) is unrelated to this change.
* chore: trigger CI on digitopvn/goclaw fork
* ci: ping
* ci: retrigger workflows
Remove Tools.Web and related WebToolsConfig, DuckDuckGoConfig from config
struct and Default(). Web search providers now resolved dynamically from
config_secrets (tenant-scoped) and builtin_tool_tenant_configs instead of
hardcoded config.json5.
Update config_load_test to match removed config paths. Separate config_secrets
and config_channels loading to clarify schema evolution.
* feat(providers): add Ollama local and Ollama Cloud provider support
Adds two new provider variants:
ollama — local/self-hosted Ollama instance
- Gated on providers.ollama.host in config (or GOCLAW_OLLAMA_HOST env)
- No API key required; Ollama's OpenAI-compat endpoint accepts any Bearer value
- Defaults to http://localhost:11434/v1 (configurable for LAN/remote hosts)
- Default model: llama3.3
ollama-cloud — Ollama Cloud (managed remote inference)
- Gated on providers.ollama_cloud.api_key (or GOCLAW_OLLAMA_CLOUD_API_KEY env)
- Bearer token from ollama.com/settings/keys
- Default base URL: https://ollama.com/v1 (overridable via api_base)
- Default model: llama3.3
Both variants use the existing NewOpenAIProvider (OpenAI-compat) — no new
provider struct needed. Both are registered from config file and DB (via
llm_providers table with ProviderOllama / ProviderOllamaCloud types).
OllamaCloud.APIKey follows all existing secret handling patterns:
MaskedCopy, StripSecrets, StripMaskedSecrets.
* feat(providers): wire Ollama into web UI and fix DB registration
- Add ollama + ollama_cloud to PROVIDER_TYPES constants (dropdowns)
- Fix setup wizard: skip API key requirement for Ollama local (isOllama)
- Fix bootstrap status: recognize Ollama local as no-API-key provider
- Add ollama_cloud to config-page KNOWN_PROVIDERS list
- Fix gateway_providers.go: move ProviderOllama before APIKey=='' guard
so DB-registered local Ollama providers actually register at startup
(same pattern as ClaudeCLI, which also needs no API key)
* feat: add Z.ai provider support (general API + coding plan)
Add Z.ai (GLM) as a new LLM provider with two variants:
- `zai`: general API (api.z.ai/api/paas/v4)
- `zai_coding`: coding plan (api.z.ai/api/coding/paas/v4)
Reuses OpenAIProvider — Z.ai API is OpenAI-compatible with Bearer
token auth, SSE streaming, and reasoning_content support.
Includes: store constants, config struct fields, env var loading
(GOCLAW_ZAI_API_KEY, GOCLAW_ZAI_CODING_API_KEY), secret masking,
config + DB registration, onboard wizard, and UI provider types.
Default model: glm-5
Closes#100
* docs: add Z.ai provider entries to providers documentation
- Add DashScope (Qwen) native provider with tools+streaming fallback
- Add Bailian Coding provider with hardcoded model list (no /v1/models API)
- Parse reasoning_content in OpenAI-compat streaming/non-streaming responses
- Emit ChatEventThinking events in agent loop for thinking models
- Add vision support for DashScope (qwen3-vl)
- Fix provider form dialog not updating API base URL when switching types
- Update README provider count from 11+ to 13+
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>