agentscope-go includes a built-in HTTP Agent Service for deploying agents as web services.
svc := service.New(service.Config{
Addr: ":8080",
AllowedOrigins: []string{"*"},
}, chatModel, func(name, prompt string, _ model.ChatModel) *agent.UnifiedAgent {
return agent.NewUnifiedAgent(name, prompt, chatModel,
agent.WithToolkit(tool.NewEnhancedToolkit()),
)
})
svc.ListenAndServe()| Method | Path | Description |
|---|---|---|
| POST | /api/session |
Create a new session |
| GET | /api/sessions |
List all sessions |
| POST | /api/chat/{id} |
Send a message (sync) |
| GET | /api/chat/{id}/stream |
Stream chat via SSE |
| POST | /api/chat/{id}/confirm |
Confirm HITL request |
| GET | /api/models |
List available models |
For production deployments with multi-session management, credentials, scheduling, and workspace isolation:
app, _ := app.CreateApp(&app.AppConfig{
Addr: ":8080",
AllowedOrigins: []string{"https://your-frontend.com"},
Storage: redisStorage,
MessageBus: messagebus.NewInMemoryMessageBus(),
})For untrusted tool execution, use isolated workspaces:
| Workspace | Isolation Level | Use Case |
|---|---|---|
LocalWorkspace |
Directory-scoped | Development, trusted agents |
DockerWorkspace |
Container-level | Production, semi-trusted |
E2BWorkspace |
Cloud sandbox | Full isolation, untrusted code |
K8sWorkspace |
Kubernetes Pod | Production clusters, multi-tenant |
OpenSandboxWorkspace |
Cloud sandbox API | Remote sandbox-as-a-service |
DaytonaWorkspace |
Dev environment | Daytona-managed dev containers |
AppleContainerWorkspace |
Apple Container | macOS-native lightweight containers |
BubblewrapWorkspace |
Linux bwrap | Minimal Linux sandboxing without Docker |
ws, _ := workspace.NewDockerWorkspace(ctx, &workspace.DockerWorkspaceConfig{
Image: "python:3.11-slim",
WorkDir: "/workspace",
})
backend := workspace.NewToolBackend(ws)
// Use backend with tool context routingRun agent tool execution inside hardened ephemeral Kubernetes Pods:
ws, _ := workspace.NewK8sWorkspace(&workspace.K8sConfig{
Namespace: "agent-sandbox",
PodName: "agent-workspace",
Image: "ubuntu:22.04",
APIServer: "https://kubernetes.default.svc",
SecretToken: model.NewSecretStr(os.Getenv("K8S_TOKEN")),
PodTTLSeconds: 3600, // auto-cleanup after 1h
DisableServiceAccount: true, // no SA token inside pod
SecurityContext: &workspace.PodSecurityContext{
RunAsNonRoot: boolPtr(true),
RunAsUser: int64Ptr(1000),
},
Resources: &workspace.ResourceRequirements{
CPULimit: "2000m",
MemoryLimit: "1Gi",
CPURequest: "200m",
MemoryRequest: "256Mi",
},
Labels: map[string]string{
"app.kubernetes.io/managed-by": "agentscope",
},
})
backend := workspace.NewToolBackend(ws)
defer ws.Close()Read-only tools for querying existing clusters (no mutation, secrets blocked):
getTool := workspace.NewKubectlGetTool("/path/to/kubeconfig")
logTool := workspace.NewKubectlLogTool("/path/to/kubeconfig")
tk := tool.NewToolkit(getTool, logTool)kubectl_get supports: pods, deployments, services, configmaps, events, nodes, namespaces, ingresses, jobs, cronjobs, statefulsets, daemonsets, replicasets, pvc, hpa. Secrets are explicitly blocked.
Use the OpenSandbox API for fully managed cloud sandboxes:
ws, _ := workspace.NewOpenSandboxWorkspace(workspace.OpenSandboxConfig{
APIKey: os.Getenv("OPENSANDBOX_API_KEY"),
BaseURL: "https://api.opensandbox.dev",
Template: "python:3.11",
})Leverage Daytona for development-oriented sandbox environments:
ws, _ := workspace.NewDaytonaWorkspace(workspace.DaytonaConfig{
BaseURL: "https://daytona.example.com",
APIKey: os.Getenv("DAYTONA_API_KEY"),
WorkspaceID: "my-workspace",
})On macOS, use Apple's Container framework for lightweight native isolation:
ws, _ := workspace.NewAppleContainerWorkspace(workspace.AppleContainerConfig{
Image: "swift:latest",
Name: "agent-sandbox",
})Minimal Linux sandboxing via bwrap without needing Docker:
ws, _ := workspace.NewBubblewrapWorkspace(workspace.BubblewrapConfig{
RootDir: "/tmp/agent-sandbox",
AllowNetwork: false,
})Execute untrusted code as WebAssembly modules with strict resource limits. No container runtime needed — just a WASM runtime binary (wasmtime, wasmer, or wasm3).
rt, _ := wasm.NewCLIRuntime("") // auto-discover wasmtime/wasmer/wasm3
sandbox := wasm.NewSandbox(wasm.SandboxConfig{
Runtime: rt,
MaxMemory: 64 * 1024 * 1024, // 64MB
MaxDuration: 10 * time.Second,
MaxFuel: 1_000_000, // instruction count limit
})
result, _ := sandbox.Run(ctx, "plugin.wasm", []byte(`{"input": "hello"}`))
fmt.Println(string(result.Stdout))Key properties:
- Memory-limited: Hard cap on heap allocation
- Time-limited: Execution timeout
- CPU-limited: Fuel (instruction count) budget
- Portable: Same
.wasmbinary runs on any OS/arch - No network by default: Modules cannot access the network unless explicitly granted WASI permissions
Update agent configuration at runtime without restarting. The hotreload package watches files for changes and notifies handlers.
w := hotreload.NewWatcher(hotreload.WatcherConfig{
PollInterval: 2 * time.Second,
})
w.Watch("config/agent.json", func(evt hotreload.ChangeEvent, data []byte) error {
log.Printf("Config changed at %s", evt.Timestamp)
// Parse and apply new config
return nil
})
w.Start(ctx)
defer w.Stop()For type-safe config with automatic JSON unmarshaling:
type AgentConfig struct {
SystemPrompt string `json:"system_prompt"`
MaxIters int `json:"max_iters"`
Model string `json:"model"`
Tools []string `json:"tools"`
}
reloader, _ := hotreload.NewReloader[AgentConfig](w, "config/agent.json",
hotreload.WithOnChange(func(old, new_ *AgentConfig) {
log.Printf("Prompt changed: %q -> %q", old.SystemPrompt, new_.SystemPrompt)
}),
)
// Read the current config (lock-free atomic pointer)
cfg := reloader.Get()Fan out work across a pool of agent workers for high-throughput batch processing:
pool := runtime.NewAgentPool(
func() agent.Agent {
return agent.NewUnifiedAgent("worker", "You are a data processor.", cm,
agent.WithToolkit(tool.NewEnhancedToolkit()),
)
},
runtime.Workers(8),
runtime.QueueSize(100),
)
defer pool.Close()
// Submit work items
for _, item := range workItems {
result, _ := pool.Submit(ctx, item)
go func(r <-chan runtime.PoolResult) {
res := <-r
if res.Err != nil {
log.Printf("Error: %v", res.Err)
} else {
log.Printf("Result: %s", res.Output.GetTextContent("\n"))
}
}(result)
}Each worker owns its own agent instance — no shared state, no locking overhead.
Record agent interactions once, then replay them deterministically in CI without API keys or network access.
recorder := replay.NewRecorder()
a := agent.NewUnifiedAgent("bot", "You are a test agent.", cm,
agent.WithMiddlewares(recorder),
)
// Run the agent normally — all model calls are recorded
a.Reply(ctx, "Summarize the Q3 report")
// Save the tape
data, _ := json.Marshal(recorder.Tape())
os.WriteFile("testdata/q3_summary.tape.json", data, 0644)func TestQ3Summary(t *testing.T) {
data, _ := os.ReadFile("testdata/q3_summary.tape.json")
var tape replay.Tape
json.Unmarshal(data, &tape)
replayer := replay.NewReplayer(&tape)
a := agent.NewUnifiedAgent("bot", "You are a test agent.", nil, // no model needed!
agent.WithMiddlewares(replayer),
)
reply, err := a.Reply(context.Background(), "Summarize the Q3 report")
require.NoError(t, err)
assert.Contains(t, *reply.GetTextContent("\n"), "revenue")
}No API keys, no network, fully deterministic.
Run agent tasks on a schedule:
scheduler := schedule.NewInMemoryScheduler()
scheduler.Schedule(ctx, &schedule.Task{
Name: "daily-report",
Interval: 24 * time.Hour,
}, func(ctx context.Context, task *schedule.Task) error {
_, err := agent.Reply(ctx, "Generate the daily summary report.")
return err
})- Set
permission.ModeDefaultorModeAcceptEdits(neverBypassin production) - Use
DockerWorkspace,K8sWorkspace, orE2BWorkspacefor tool execution - Configure
ClientOptions.Timeoutfor your expected response times - Set up
TracingMiddlewarewith OpenTelemetry exporter - Use
ReplyBudgetControlMiddlewareto cap token spending; useCostTrackerMiddlewarewithWithMaxCostUSDfor hard USD spend caps - Rotate API keys and use
model.SecretStrto prevent key leakage in logs - Put the Agent Service behind authentication (it has no built-in auth)
- Use Redis-backed storage and message bus for multi-instance deployments
- Configure
accesspolicies for multi-tenant resource sharing - Enable
hotreloadto update agent configs without downtime - Use
replaytapes in CI to test agent behavior deterministically - Configure
GuardrailMiddlewarefor output content filtering - Use
AgentPoolwith appropriate worker counts for batch workloads
- Architecture — Package structure and design
- Go-Exclusive Features — Replay, Pool, Hot-reload, WASM, TCP Mesh, Bench
- Examples — Runnable demos for all deployment patterns