refactor: deprecate standalone mode, managed mode is now default (#126)

* refactor: remove managed/standalone mode distinction from codebase

Standalone mode is deprecated; managed mode is now the only mode.
Remove redundant "managed mode" qualifiers from comments, docs,
and error messages. Error strings now reference "database stores"
instead of "managed mode" for clarity.

* improve(onboard): streamline onboard process and env setup

Simplify onboard wizard, extract helpers to dedicated file,
update env example and entrypoint for default managed mode,
clean up prepare-env script, update i18n catalogs.
This commit is contained in:
Thieu Nguyen authored and GitHub committed 2026-03-11 07:27:38 +07:00
1 parent c5b886048e
commit 8ad580521d
32 files changed
+121 -110

No files matched your search

+1 -1
View File
@@ -2,7 +2,7 @@
# Copy to .env and fill in values. For Docker Compose, do NOT use 'export' prefix.
#
# Auto-generated by prepare-env.sh: GOCLAW_GATEWAY_TOKEN, GOCLAW_ENCRYPTION_KEY.
# LLM providers and channels are configured via the web dashboard setup wizard.
# LLM provider API keys: configure via the web dashboard setup wizard.
# --- Gateway (required) ---
GOCLAW_GATEWAY_TOKEN=
+8 -8
View File
@@ -9,13 +9,13 @@
| POST | `/v1/chat/completions` | OpenAI-compatible chat API |
| POST | `/v1/responses` | Responses protocol |
| POST | `/v1/tools/invoke` | Tool invocation |
| GET/POST | `/v1/agents/*` | Agent management (managed mode) |
| GET/POST | `/v1/skills/*` | Skills management (managed mode) |
| GET/POST/PUT/DELETE | `/v1/tools/custom/*` | Custom tool CRUD (managed mode) |
| GET/POST/PUT/DELETE | `/v1/mcp/*` | MCP server + grants management (managed mode) |
| GET | `/v1/traces/*` | Trace viewer (managed mode) |
| GET/POST | `/v1/agents/*` | Agent management |
| GET/POST | `/v1/skills/*` | Skills management |
| GET/POST/PUT/DELETE | `/v1/tools/custom/*` | Custom tool CRUD |
| GET/POST/PUT/DELETE | `/v1/mcp/*` | MCP server + grants management |
| GET | `/v1/traces/*` | Trace viewer |
## Custom Tools (Managed Mode)
## Custom Tools
Define shell-based tools at runtime via HTTP API — no recompile or restart needed. The LLM can invoke custom tools identically to built-in tools.
@@ -67,7 +67,7 @@ Connect external [Model Context Protocol](https://modelcontextprotocol.io) serve
**Supported transports:** `stdio`, `sse`, `streamable-http`
**Standalone mode** — configure in `config.json`:
**Static config** — configure in `config.json` (deprecated; use HTTP API for dynamic management):
```json
{
@@ -87,7 +87,7 @@ Connect external [Model Context Protocol](https://modelcontextprotocol.io) serve
}
```
**Managed mode** — full CRUD via HTTP API with per-agent and per-user access grants:
**HTTP API** — full CRUD with per-agent and per-user access grants:
| Method | Path | Description |
|---|---|---|
-1
View File
@@ -909,7 +909,6 @@ func runGateway() {
slog.Info("goclaw gateway starting",
"version", Version,
"protocol", protocol.ProtocolVersion,
"mode", "managed",
"agents", agentRouter.List(),
"tools", toolsReg.Count(),
"channels", channelMgr.GetEnabledChannels(),
+7 -7
View File
@@ -37,25 +37,25 @@ func runOnboard() {
}
}
// ── Step 1: Postgres DSN ──
// ── Step 1: Postgres connection ──
postgresDSN := os.Getenv("GOCLAW_POSTGRES_DSN")
if postgresDSN == "" {
postgresDSN = cfg.Database.PostgresDSN
}
if postgresDSN == "" {
var err error
postgresDSN, err = promptString("Postgres DSN", "Connection string (e.g. postgres://user:pass@host:5432/dbname)", "")
fmt.Println("── Database Connection ──")
fmt.Println(" Enter your PostgreSQL connection details (press Enter for defaults).")
fmt.Println()
dsn, err := promptPostgresFields()
if err != nil {
fmt.Println("Cancelled.")
return
}
postgresDSN = dsn
} else {
fmt.Printf(" Using Postgres DSN from environment\n")
}
if postgresDSN == "" {
fmt.Println(" Error: Postgres DSN is required.")
return
}
// ── Step 2: Test connection ──
fmt.Print(" Testing Postgres connection... ")
+39
View File
@@ -4,6 +4,7 @@ import (
"crypto/rand"
"encoding/hex"
"fmt"
"net/url"
"os"
"strings"
)
@@ -14,6 +15,44 @@ func onboardGenerateToken(bytes int) string {
return hex.EncodeToString(b)
}
// promptPostgresFields prompts for individual database fields and builds a DSN.
func promptPostgresFields() (string, error) {
host, err := promptString("Host", "", "localhost")
if err != nil {
return "", err
}
port, err := promptString("Port", "", "5432")
if err != nil {
return "", err
}
dbName, err := promptString("Database name", "", "goclaw")
if err != nil {
return "", err
}
user, err := promptString("Username", "", "postgres")
if err != nil {
return "", err
}
password, err := promptPassword("Password", "Leave empty if no password")
if err != nil {
return "", err
}
sslMode, err := promptString("SSL mode", "", "disable")
if err != nil {
return "", err
}
// Build DSN with proper escaping
var userInfo *url.Userinfo
if password != "" {
userInfo = url.UserPassword(user, password)
} else {
userInfo = url.User(user)
}
dsn := fmt.Sprintf("postgres://%s@%s:%s/%s?sslmode=%s", userInfo.String(), host, port, dbName, sslMode)
return dsn, nil
}
// onboardWriteEnvFile writes the minimal .env.local with only the 3 required secrets.
func onboardWriteEnvFile(path, postgresDSN, gatewayToken, encryptionKey string) {
var lines []string
+3 -3
View File
@@ -3,9 +3,9 @@ set -e
case "${1:-serve}" in
serve)
# Managed mode: auto-upgrade (schema migrations + data hooks) before starting.
if [ "$GOCLAW_MODE" = "managed" ] && [ -n "$GOCLAW_POSTGRES_DSN" ]; then
echo "Managed mode: running upgrade..."
# Auto-upgrade (schema migrations + data hooks) before starting.
if [ -n "$GOCLAW_POSTGRES_DSN" ]; then
echo "Running database upgrade..."
/app/goclaw upgrade || \
echo "Upgrade warning (may already be up-to-date)"
fi
+3 -3
View File
@@ -233,7 +233,7 @@ sequenceDiagram
---
## 7. Managed Mode Wiring
## 7. Database Wiring
The `wireManagedExtras()` function in `cmd/gateway_managed.go` wires multi-tenant components:
@@ -393,7 +393,7 @@ flowchart TD
|------|---------|
| `cmd/root.go` | Cobra CLI entry point, flag parsing |
| `cmd/gateway.go` | Gateway startup orchestrator (`runGateway()`) |
| `cmd/gateway_managed.go` | Managed mode wiring (`wireManagedExtras()`, `wireManagedHTTP()`) |
| `cmd/gateway_managed.go` | Database wiring (`wireManagedExtras()`, `wireManagedHTTP()`) |
| `cmd/gateway_callbacks.go` | Shared callbacks (user seeding, context file loading) |
| `cmd/gateway_consumer.go` | Inbound message consumer (subagent, delegate, teammate, handoff routing) |
| `cmd/gateway_providers.go` | Provider registration (config-based + DB-based) |
@@ -423,7 +423,7 @@ flowchart TD
| [02-providers.md](./02-providers.md) | LLM providers, retry logic, schema cleaning |
| [03-tools-system.md](./03-tools-system.md) | Tool registry, policy engine, interceptors, custom tools, MCP grants |
| [04-gateway-protocol.md](./04-gateway-protocol.md) | WebSocket protocol v3, HTTP API, RBAC, identity propagation |
| [05-channels-messaging.md](./05-channels-messaging.md) | Channel adapters, Telegram formatting, pairing, managed-mode user scoping |
| [05-channels-messaging.md](./05-channels-messaging.md) | Channel adapters, Telegram formatting, pairing, per-user scoping |
| [06-store-data-model.md](./06-store-data-model.md) | Store interfaces, PostgreSQL schema, session caching, custom tool store |
| [07-bootstrap-skills-memory.md](./07-bootstrap-skills-memory.md) | Bootstrap files, skills system, memory, skills grants |
| [08-scheduling-cron.md](./08-scheduling-cron.md) | Scheduler lanes, cron lifecycle |
+3 -3
View File
@@ -88,7 +88,7 @@ flowchart TD
- Increment the `activeRuns` atomic counter (no mutex -- true concurrency, especially in group chats with `maxConcurrent = 3`).
- Emit a `run.started` event to notify connected clients.
- Create a trace record (managed mode) with a generated trace UUID.
- Create a trace record with a generated trace UUID.
- Propagate context values: `WithAgentID()`, `WithUserID()`, `WithAgentType()`. Downstream tools and interceptors rely on these.
- Compute per-user workspace: `base + "/" + sanitize(userID)`. Inject via `WithToolWorkspace(ctx)` so all filesystem and shell tools use the correct directory.
- Ensure per-user files exist. A `sync.Map` cache guarantees the seeding function runs at most once per user.
@@ -381,7 +381,7 @@ flowchart TD
---
## 10. Resolver (Managed Mode)
## 10. Resolver
The `ManagedResolver` lazy-creates Loop instances from PostgreSQL data when the Router encounters a cache miss.
@@ -392,7 +392,7 @@ flowchart TD
PROV --> BOOT["Step 3: Load bootstrap files<br/>bootstrap.LoadFromStore(agentID)"]
BOOT --> DEFAULTS["Step 4: Apply defaults<br/>contextWindow <= 0 then 200K<br/>maxIterations <= 0 then 20"]
DEFAULTS --> CREATE["Step 5: Create Loop<br/>NewLoop(LoopConfig)"]
CREATE --> WIRE["Step 6: Wire managed-mode hooks<br/>EnsureUserFilesFunc, ContextFileLoaderFunc"]
CREATE --> WIRE["Step 6: Wire hooks<br/>EnsureUserFilesFunc, ContextFileLoaderFunc"]
WIRE --> DONE["Return Loop to Router for caching"]
```
+2 -2
View File
@@ -202,9 +202,9 @@ The Anthropic provider calls `CleanSchemaForProvider("anthropic", ...)` when con
---
## 7. Managed Mode -- Providers from Database
## 7. Providers from Database
In managed mode, providers are loaded from the `llm_providers` table in addition to the config file. Database providers override config providers with the same name.
Providers are loaded from the `llm_providers` table in addition to the config file. Database providers override config providers with the same name.
### Loading Flow
+4 -4
View File
@@ -141,7 +141,7 @@ Context keys ensure each tool call receives the correct per-call values without
## 3. Filesystem Tools and Virtual FS Routing
In managed mode, filesystem operations are intercepted before hitting the host disk. Two interceptor layers route specific paths to the database instead.
Filesystem operations are intercepted before hitting the host disk. Two interceptor layers route specific paths to the database instead.
```mermaid
flowchart TD
@@ -570,9 +570,9 @@ GoClaw integrates with Model Context Protocol (MCP) servers via `internal/mcp/`.
- Tools are registered with a prefix (e.g., `mcp_servername_toolname`)
- Dynamic tool group registration: `mcp` and `mcp:{serverName}` groups
### Access Control (Managed Mode)
### Access Control
In managed mode, MCP server access is controlled through per-agent and per-user grants stored in PostgreSQL.
MCP server access is controlled through per-agent and per-user grants stored in PostgreSQL.
```mermaid
flowchart TD
@@ -602,7 +602,7 @@ flowchart LR
---
## 13. Custom Tools (Managed Mode)
## 13. Custom Tools
Define shell-based tools at runtime via the HTTP API -- no recompile or restart needed. Custom tools are stored in the `custom_tools` PostgreSQL table and loaded dynamically into the agent's tool registry.
+8 -8
View File
@@ -96,7 +96,7 @@ flowchart TD
Token comparison uses `crypto/subtle.ConstantTimeCompare` to prevent timing attacks.
In managed mode, `user_id` in the connect parameters is required for per-user session scoping and context file routing. GoClaw uses the **Identity Propagation** pattern — it trusts the upstream service to provide accurate user identity. The `user_id` is opaque (VARCHAR 255); multi-tenant deployments use the compound format `tenant.{tenantId}.user.{userId}`. See [00-architecture-overview.md Section 5](./00-architecture-overview.md) for details.
The `user_id` in the connect parameters is required for per-user session scoping and context file routing. GoClaw uses the **Identity Propagation** pattern — it trusts the upstream service to provide accurate user identity. The `user_id` is opaque (VARCHAR 255); multi-tenant deployments use the compound format `tenant.{tenantId}.user.{userId}`. See [00-architecture-overview.md Section 5](./00-architecture-overview.md) for details.
### Three Roles
@@ -161,7 +161,7 @@ flowchart TD
| `agent.wait` | Wait for an agent to become available |
| `agent.identity.get` | Get agent identity (name, description) |
| `agents.list` | List all accessible agents |
| `agents.create` | Create a new agent (managed mode) |
| `agents.create` | Create a new agent |
| `agents.update` | Update agent configuration |
| `agents.delete` | Soft-delete an agent |
| `agents.files.list` | List agent context files |
@@ -301,7 +301,7 @@ flowchart TD
- `Authorization: Bearer <token>` -- timing-safe comparison via `crypto/subtle.ConstantTimeCompare`
- No token configured: all requests allowed
- `X-GoClaw-User-Id`: required in managed mode for per-user scoping
- `X-GoClaw-User-Id`: required for per-user scoping
- `X-GoClaw-Agent-Id`: specify target agent for the request
### Endpoints
@@ -334,9 +334,9 @@ Direct tool invocation without the agent loop. Supports `dryRun: true` to return
Returns `{"status":"ok","protocol":3}`.
#### Managed Mode CRUD Endpoints
#### CRUD Endpoints
All managed endpoints require `Authorization: Bearer <token>` and `X-GoClaw-User-Id` header for per-user scoping.
All CRUD endpoints require `Authorization: Bearer <token>` and `X-GoClaw-User-Id` header for per-user scoping.
**Agents** (`/v1/agents`):
@@ -482,9 +482,9 @@ Error responses include `retryable` (boolean) and `retryAfterMs` (integer) field
| `internal/http/chat_completions.go` | POST /v1/chat/completions (OpenAI-compatible) |
| `internal/http/responses.go` | POST /v1/responses (OpenResponses protocol) |
| `internal/http/tools_invoke.go` | POST /v1/tools/invoke (direct tool execution) |
| `internal/http/agents.go` | Agent CRUD HTTP handlers (managed mode) |
| `internal/http/skills.go` | Skills HTTP handlers (managed mode) |
| `internal/http/traces.go` | Traces HTTP handlers (managed mode) |
| `internal/http/agents.go` | Agent CRUD HTTP handlers |
| `internal/http/skills.go` | Skills HTTP handlers |
| `internal/http/traces.go` | Traces HTTP handlers |
| `internal/http/delegations.go` | Delegation history HTTP handlers |
| `internal/http/summoner.go` | LLM-powered agent setup (XML parsing, context file generation) |
| `internal/http/auth.go` | Bearer token authentication, timing-safe comparison |
+3 -3
View File
@@ -57,7 +57,7 @@ flowchart LR
Internal channels (`cli`, `system`, `subagent`) are silently skipped by the outbound dispatcher and never forwarded to external platforms.
### Handoff Routing (Managed Mode)
### Handoff Routing
Before normal agent routing, the consumer checks the `handoff_routes` table for an active routing override. If a handoff route exists for the incoming channel + chat ID, the message is redirected to the target agent instead of the original.
@@ -504,7 +504,7 @@ flowchart TD
WS2 --> USER3["user_charlie/"]
```
In managed mode, channel instances are loaded from the database with their assigned agent ID. The agent key is resolved and propagated through the message pipeline, ensuring all filesystem tools, context files, and memory operations use the correct workspace.
Channel instances are loaded from the database with their assigned agent ID. The agent key is resolved and propagated through the message pipeline, ensuring all filesystem tools, context files, and memory operations use the correct workspace.
---
@@ -570,7 +570,7 @@ flowchart TD
|------|---------|
| `internal/channels/channel.go` | Channel interface, BaseChannel, extended interfaces, HandleMessage |
| `internal/channels/manager.go` | Manager: registration, StartAll, StopAll, outbound dispatch, webhook collection |
| `internal/channels/instance_loader.go` | DB-based channel instance loading (managed mode) |
| `internal/channels/instance_loader.go` | DB-based channel instance loading |
| `internal/channels/telegram/channel.go` | Telegram core: long polling, mention gating, typing indicators |
| `internal/channels/telegram/handlers.go` | Message handling, media processing, forum topic detection |
| `internal/channels/telegram/topic_config.go` | Per-topic config layering and resolution |
+2 -2
View File
@@ -77,7 +77,7 @@ flowchart TD
## 4. Agent Access Control
In managed mode, agent access is checked via a 4-step pipeline.
Agent access is checked via a 4-step pipeline.
```mermaid
flowchart TD
@@ -477,7 +477,7 @@ flowchart TD
| Key | Type | Purpose |
|-----|------|---------|
| `goclaw_user_id` | string | External user ID (e.g., Telegram user ID) |
| `goclaw_agent_id` | uuid.UUID | Agent UUID (managed mode) |
| `goclaw_agent_id` | uuid.UUID | Agent UUID |
| `goclaw_agent_type` | string | Agent type: `"open"` or `"predefined"` |
| `goclaw_sender_id` | string | Original individual sender ID (in group chats, `user_id` is group-scoped but `sender_id` preserves the actual person) |
+7 -7
View File
@@ -186,7 +186,7 @@ This ensures resolver-injected virtual files (`DELEGATION.md`, `TEAM.md`) surviv
---
## 7. Agent Summoning (Managed Mode)
## 7. Agent Summoning
Creating a predefined agent requires 4 context files (SOUL.md, IDENTITY.md, AGENTS.md, TOOLS.md) with specific formatting conventions. Agent summoning generates all 4 files from a natural language description in a single LLM call.
@@ -260,9 +260,9 @@ IDF is computed as: `log((N - df + 0.5) / (df + 0.5) + 1)`
---
## 11. Skills -- Embedding Search (Managed Mode)
## 11. Skills -- Embedding Search
In managed mode, skill search uses a hybrid approach combining BM25 and vector similarity.
Skill search uses a hybrid approach combining BM25 and vector similarity.
```mermaid
flowchart TD
@@ -283,9 +283,9 @@ flowchart TD
---
## 12. Skills Grants & Visibility (Managed Mode)
## 12. Skills Grants & Visibility
In managed mode, skill access is controlled through a 3-tier visibility model with explicit agent and user grants.
Skill access is controlled through a 3-tier visibility model with explicit agent and user grants.
```mermaid
flowchart TD
@@ -315,7 +315,7 @@ flowchart TD
**Resolution**: `ListAccessible(agentID, userID)` performs a DISTINCT join across `skills`, `skill_agent_grants`, and `skill_user_grants` with the visibility filter, returning only active skills the caller can access.
**Managed-mode Tier 4**: In managed mode, global skills (Tier 4 in the hierarchy) are loaded from the `skills` PostgreSQL table instead of the filesystem.
**Tier 4**: Global skills (Tier 4 in the hierarchy) are loaded from the `skills` PostgreSQL table instead of the filesystem.
---
@@ -489,7 +489,7 @@ The flush is idempotent per compaction cycle -- it will not run again until the
| Document | Relevant Content |
|----------|-----------------|
| [00-architecture-overview.md](./00-architecture-overview.md) | Startup sequence, managed mode wiring |
| [00-architecture-overview.md](./00-architecture-overview.md) | Startup sequence, database wiring |
| [01-agent-loop.md](./01-agent-loop.md) | Agent loop calls BuildSystemPrompt, compaction flow |
| [03-tools-system.md](./03-tools-system.md) | ContextFileInterceptor routing read_file/write_file to DB |
| [06-store-data-model.md](./06-store-data-model.md) | memory_documents, memory_chunks tables |
+2 -2
View File
@@ -2,7 +2,7 @@
Defense-in-depth with five independent layers from transport to isolation. Each layer operates independently -- even if one layer is bypassed, the remaining layers continue to protect the system.
> **Managed mode**: Adds AES-256-GCM encryption for secrets stored in PostgreSQL (LLM provider API keys, MCP server API keys, custom tool environment variables), plus agent-level access control via the 4-step `CanAccess` pipeline (see [06-store-data-model.md](./06-store-data-model.md)).
> AES-256-GCM encryption protects secrets stored in PostgreSQL (LLM provider API keys, MCP server API keys, custom tool environment variables). Agent-level access control uses the 4-step `CanAccess` pipeline (see [06-store-data-model.md](./06-store-data-model.md)).
---
@@ -123,7 +123,7 @@ The workspace is injected into tools via `WithToolWorkspace(ctx)` context inject
---
## 2. Encryption (Managed Mode)
## 2. Encryption
AES-256-GCM encryption for secrets stored in PostgreSQL. Key provided via `GOCLAW_ENCRYPTION_KEY` environment variable.
+2 -2
View File
@@ -106,7 +106,7 @@ The exporter lives in a separate sub-package (`internal/tracing/otelexport/`) so
---
## 5. Trace HTTP API (Managed Mode)
## 5. Trace HTTP API
| Method | Path | Description |
|--------|------|-------------|
@@ -126,7 +126,7 @@ The exporter lives in a separate sub-package (`internal/tracing/otelexport/`) so
---
## 6. Delegation History (Managed Mode)
## 6. Delegation History
Delegation history records are stored in the `delegation_history` table and exposed alongside traces for cross-referencing agent interactions.
+1 -1
View File
@@ -323,7 +323,7 @@ func NewManagedResolver(deps ResolverDeps) ResolverFunc {
}
}
// Managed mode: filter skills by visibility + agent grants.
// Filter skills by visibility + agent grants.
// Only public skills and explicitly granted internal skills appear in the system prompt.
var skillAllowList []string
if deps.SkillAccessStore != nil {
+1 -1
View File
@@ -66,7 +66,7 @@ func (m *AgentsMethods) handleCreate(ctx context.Context, client *gateway.Client
}
if m.agentStore != nil {
// --- Managed mode: create agent in DB ---
// --- DB-backed: create agent in store ---
ctx := context.Background()
// Check if agent already exists in DB
+1 -1
View File
@@ -39,7 +39,7 @@ func (m *AgentsMethods) handleDelete(ctx context.Context, client *gateway.Client
var removedBindings int
if m.agentStore != nil {
// --- Managed mode: delete from DB ---
// --- DB-backed: delete from store ---
ctx := context.Background()
ag, err := m.agentStore.GetByKey(ctx, params.AgentID)
if err != nil {
+3 -3
View File
@@ -36,7 +36,7 @@ func (m *AgentsMethods) handleFilesList(ctx context.Context, client *gateway.Cli
}
if m.agentStore != nil {
// --- Managed mode: list from DB ---
// --- DB-backed: list from store ---
ctx := context.Background()
ag, err := m.agentStore.GetByKey(ctx, params.AgentID)
if err != nil {
@@ -135,7 +135,7 @@ func (m *AgentsMethods) handleFilesGet(ctx context.Context, client *gateway.Clie
}
if m.agentStore != nil {
// --- Managed mode: read from DB ---
// --- DB-backed: read from store ---
ctx := context.Background()
ag, err := m.agentStore.GetByKey(ctx, params.AgentID)
if err != nil {
@@ -234,7 +234,7 @@ func (m *AgentsMethods) handleFilesSet(ctx context.Context, client *gateway.Clie
}
if m.agentStore != nil {
// --- Managed mode: write to DB ---
// --- DB-backed: write to store ---
ctx := context.Background()
ag, err := m.agentStore.GetByKey(ctx, params.AgentID)
if err != nil {
+1 -1
View File
@@ -41,7 +41,7 @@ func (m *AgentsMethods) handleIdentityGet(_ context.Context, client *gateway.Cli
}
if m.agentStore != nil {
// --- Managed mode: read identity from DB ---
// --- DB-backed: read identity from store ---
ctx := context.Background()
ag, err := m.agentStore.GetByKey(ctx, params.AgentID)
if err == nil {
+1 -1
View File
@@ -45,7 +45,7 @@ func (m *AgentsMethods) handleUpdate(ctx context.Context, client *gateway.Client
}
if m.agentStore != nil {
// --- Managed mode: update agent in DB ---
// --- DB-backed: update agent in store ---
ctx := context.Background()
ag, err := m.agentStore.GetByKey(ctx, params.AgentID)
if err != nil {
+10 -10
View File
@@ -160,52 +160,52 @@ func (s *Server) BuildMux() *http.ServeMux {
mux.Handle("/v1/tools/invoke", toolsHandler)
}
// Managed mode: agent CRUD + shares API
// Agent CRUD + shares API
if s.agentsHandler != nil {
s.agentsHandler.RegisterRoutes(mux)
}
// Managed mode: skill management API
// Skill management API
if s.skillsHandler != nil {
s.skillsHandler.RegisterRoutes(mux)
}
// Managed mode: LLM trace listing API
// LLM trace listing API
if s.tracesHandler != nil {
s.tracesHandler.RegisterRoutes(mux)
}
// Managed mode: MCP server management API
// MCP server management API
if s.mcpHandler != nil {
s.mcpHandler.RegisterRoutes(mux)
}
// Managed mode: custom tool CRUD API
// Custom tool CRUD API
if s.customToolsHandler != nil {
s.customToolsHandler.RegisterRoutes(mux)
}
// Managed mode: channel instance CRUD API
// Channel instance CRUD API
if s.channelInstancesHandler != nil {
s.channelInstancesHandler.RegisterRoutes(mux)
}
// Managed mode: provider & model CRUD API
// Provider & model CRUD API
if s.providersHandler != nil {
s.providersHandler.RegisterRoutes(mux)
}
// Managed mode: delegation history API
// Delegation history API
if s.delegationsHandler != nil {
s.delegationsHandler.RegisterRoutes(mux)
}
// Managed mode: builtin tool management API
// Builtin tool management API
if s.builtinToolsHandler != nil {
s.builtinToolsHandler.RegisterRoutes(mux)
}
// Managed mode: pending messages API
// Pending messages API
if s.pendingMessagesHandler != nil {
s.pendingMessagesHandler.RegisterRoutes(mux)
}
+1 -1
View File
@@ -53,7 +53,7 @@ func init() {
// HTTP API
MsgInvalidAuth: "invalid authentication",
MsgMsgsRequired: "messages is required",
MsgUserIDHeader: "X-GoClaw-User-Id header is required in managed mode",
MsgUserIDHeader: "X-GoClaw-User-Id header is required",
MsgFileTooLarge: "file too large or invalid multipart form",
MsgMissingFileField: "missing 'file' field",
MsgInvalidFilename: "invalid filename",
+1 -1
View File
@@ -53,7 +53,7 @@ func init() {
// HTTP API
MsgInvalidAuth: "xác thực không hợp lệ",
MsgMsgsRequired: "messages là bắt buộc",
MsgUserIDHeader: "header X-GoClaw-User-Id là bắt buộc ở chế độ managed",
MsgUserIDHeader: "header X-GoClaw-User-Id là bắt buộc",
MsgFileTooLarge: "tệp quá lớn hoặc form multipart không hợp lệ",
MsgMissingFileField: "thiếu trường 'file'",
MsgInvalidFilename: "tên tệp không hợp lệ",
+1 -1
View File
@@ -53,7 +53,7 @@ func init() {
// HTTP API
MsgInvalidAuth: "身份验证无效",
MsgMsgsRequired: "messages 是必填项",
MsgUserIDHeader: "托管模式下需要 X-GoClaw-User-Id 请求头",
MsgUserIDHeader: "需要 X-GoClaw-User-Id 请求头",
MsgFileTooLarge: "文件过大或 multipart 表单无效",
MsgMissingFileField: "缺少 'file' 字段",
MsgInvalidFilename: "文件名无效",
+1 -1
View File
@@ -17,7 +17,7 @@ import (
// BridgeToolNames is the subset of GoClaw tools exposed via the MCP bridge.
// Excluded: spawn (agent loop), create_forum_topic (channels),
// handoff/delegate_search/evaluate_loop/team_* (managed mode stores).
// handoff/delegate_search/evaluate_loop/team_* (require database stores).
var BridgeToolNames = map[string]bool{
// Filesystem
"read_file": true,
+2 -2
View File
@@ -72,7 +72,7 @@ type Manager struct {
// DB-backed servers
store store.MCPServerStore
// Shared connection pool (nil = standalone mode)
// Shared connection pool (nil = config-only mode)
pool *Pool
poolServers map[string]struct{} // server names acquired from pool (for cleanup)
poolToolNames map[string][]string // per-agent tool names for pool-backed servers
@@ -179,7 +179,7 @@ func (m *Manager) LoadForAgent(ctx context.Context, agentID uuid.UUID, userID st
continue
}
} else {
// Standalone mode: create per-agent connection
// Per-agent mode: create per-agent connection
if err := m.connectServer(ctx, srv.Name, srv.Transport, srv.Command,
args, env, srv.URL, headers,
srv.ToolPrefix, srv.TimeoutSec); err != nil {
+1 -1
View File
@@ -18,7 +18,7 @@ import (
func (dm *DelegateManager) prepareDelegation(ctx context.Context, opts DelegateOpts, mode string) (*DelegationTask, *store.AgentLinkData, error) {
sourceAgentID := store.AgentIDFromContext(ctx)
if sourceAgentID == uuid.Nil {
return nil, nil, fmt.Errorf("delegation requires managed mode (no agent ID in context)")
return nil, nil, fmt.Errorf("delegation requires database stores (no agent ID in context)")
}
sourceAgent, err := dm.agentStore.GetByID(ctx, sourceAgentID)
+1 -1
View File
@@ -104,7 +104,7 @@ func (t *HandoffTool) executeTransfer(ctx context.Context, args map[string]any)
// Get current agent and channel context
sourceAgentID := store.AgentIDFromContext(ctx)
if sourceAgentID == uuid.Nil {
return ErrorResult("handoff requires managed mode")
return ErrorResult("handoff requires database stores")
}
sourceAgent, err := t.delegateMgr.agentStore.GetByID(ctx, sourceAgentID)
+1 -1
View File
@@ -47,7 +47,7 @@ func (m *TeamToolManager) SetDelegateManager(dm *DelegateManager) {
func (m *TeamToolManager) resolveTeam(ctx context.Context) (*store.TeamData, uuid.UUID, error) {
agentID := store.AgentIDFromContext(ctx)
if agentID == uuid.Nil {
return nil, uuid.Nil, fmt.Errorf("no agent context — team tools require managed mode")
return nil, uuid.Nil, fmt.Errorf("no agent context — team tools require database stores")
}
// Check cache first
-27
View File
@@ -81,33 +81,6 @@ else
echo " [exists] GOCLAW_GATEWAY_TOKEN"
fi
# 4. Check provider API key
has_provider=false
for key in GOCLAW_OPENROUTER_API_KEY GOCLAW_ANTHROPIC_API_KEY GOCLAW_OPENAI_API_KEY \
GOCLAW_MINIMAX_API_KEY GOCLAW_GROQ_API_KEY GOCLAW_DEEPSEEK_API_KEY \
GOCLAW_GEMINI_API_KEY GOCLAW_MISTRAL_API_KEY GOCLAW_XAI_API_KEY \
GOCLAW_COHERE_API_KEY GOCLAW_PERPLEXITY_API_KEY; do
val="$(get_env_val "$key")"
if [ -n "$val" ]; then
has_provider=true
echo " [exists] $key"
break
fi
done
if [ "$has_provider" = false ]; then
echo " [missing] No LLM provider API key found"
echo ""
echo " Add at least one provider key to .env before starting:"
echo " GOCLAW_OPENROUTER_API_KEY=sk-or-..."
echo " GOCLAW_ANTHROPIC_API_KEY=sk-ant-..."
echo " GOCLAW_MINIMAX_API_KEY=..."
echo ""
echo "=== Done (action required) ==="
echo ""
exit 0
fi
echo ""
echo "=== Done ==="
echo ""