Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions pkg/apis/llm/llm_const.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,3 @@ const (
)

type LLMEnvKey string

const (
LLM_OPENCLAW_GATEWAY_TOKEN = LLMEnvKey("OPENCLAW_GATEWAY_TOKEN")
LLM_OPENCLAW_AUTH_USERNAME = LLMEnvKey("AUTH_USERNAME")
LLM_OPENCLAW_CUSTOM_USER = LLMEnvKey("CUSTOM_USER")
LLM_OPENCLAW_AUTH_PASSWORD = LLMEnvKey("AUTH_PASSWORD")
LLM_OPENCLAW_PASSWORD = LLMEnvKey("PASSWORD")
)
42 changes: 42 additions & 0 deletions pkg/apis/llm/openclaw.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package llm

const (
LLM_OPENCLAW_GATEWAY_TOKEN = LLMEnvKey("OPENCLAW_GATEWAY_TOKEN")
LLM_OPENCLAW_AUTH_USERNAME = LLMEnvKey("AUTH_USERNAME")
LLM_OPENCLAW_CUSTOM_USER = LLMEnvKey("CUSTOM_USER")
LLM_OPENCLAW_AUTH_PASSWORD = LLMEnvKey("AUTH_PASSWORD")
LLM_OPENCLAW_PASSWORD = LLMEnvKey("PASSWORD")
LLM_OPENCLAW_CUSTOM_CONFIG = LLMEnvKey("OPENCLAW_CUSTOM_CONFIG")
LLM_OPENCLAW_CUSTOM_CONFIG_FILE = "/opt/openclaw_base_config.json"

// templates
LLM_OPENCLAW_TEMPLATE_AGENTS_MD_B64 = LLMEnvKey("OPENCLAW_TEMPLATE_AGENTS_MD_B64")
LLM_OPENCLAW_TEMPLATE_SOUL_MD_B64 = LLMEnvKey("OPENCLAW_TEMPLATE_SOUL_MD_B64")
LLM_OPENCLAW_TEMPLATE_USER_MD_B64 = LLMEnvKey("OPENCLAW_TEMPLATE_USER_MD_B64")
)

type OpenClawConfig struct {
Browser *OpenClawConfigBrowser `json:"browser"`
Agents *OpenClawConfigAgents `json:"agents"`
}

type OpenClawConfigAgents map[string]*OpenClawConfigAgent

type OpenClawConfigAgent struct {
Model *OpenClawConfigAgentModel `json:"model"`
ImageModel *OpenClawConfigAgentModel `json:"imageModel"`
Workspace string `json:"workspace"`
}

type OpenClawConfigAgentModel struct {
Primary string `json:"primary"`
}

// ref: https://docs.openclaw.ai/tools/browser#configuration
type OpenClawConfigBrowser struct {
Enabled bool `json:"enabled"`
SSRFPolicy map[string]interface{} `json:"ssrfPolicy"`
DefaultProfile string `json:"defaultProfile"`
Headless bool `json:"headless"`
NoSandbox bool `json:"noSandbox"`
}
3 changes: 3 additions & 0 deletions pkg/hostman/container/volume_mount/text.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ func (t text) GetRuntimeMountHostPath(pod IPodInfo, ctrId string, vm *hostapi.Co
dirPath = rootFsPath
}
mntPath := filepath.Join(dirPath, fmt.Sprintf("%s-%s", ctrId, strings.ReplaceAll(vm.MountPath, "/", "_")))
if err := EnsureDir(filepath.Dir(mntPath)); err != nil {
return "", errors.Wrapf(err, "mkdir %s", filepath.Dir(mntPath))
}
if err := t.writeContent(ti, mntPath); err != nil {
return "", errors.Wrapf(err, "write content %s to %s", ti, mntPath)
}
Expand Down
73 changes: 69 additions & 4 deletions pkg/llm/drivers/llm_container/openclaw.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package llm_container

import (
"context"
"encoding/base64"
"fmt"
"strings"

Expand All @@ -23,7 +24,8 @@ const (
// browserContainerName = "browser"
// openclawBrowserImage = "registry.cn-beijing.aliyuncs.com/cloudpods/openclaw-browser:latest"
openclawDataDir = "/data"
browserConfigDir = "/config"
desktopConfigDir = "/config"
homeDir = "/home/"
// openclawBrowserCDPPort = "9222"
)

Expand Down Expand Up @@ -230,6 +232,28 @@ func (c *openclaw) GetContainerSpec(ctx context.Context, llm *models.SLLM, image
// }
// }

func (c *openclaw) getOpenClawBaseConfig(llm *models.SLLM) *api.OpenClawConfig {
return &api.OpenClawConfig{
Browser: &api.OpenClawConfigBrowser{
Enabled: true,
DefaultProfile: "openclaw",
SSRFPolicy: map[string]interface{}{
"dangerouslyAllowPrivateNetwork": true,
},
Headless: false,
NoSandbox: false,
},
Agents: &api.OpenClawConfigAgents{
"defaults": &api.OpenClawConfigAgent{
// TODO: 支持从 llm spec 里面自动选择
ImageModel: &api.OpenClawConfigAgentModel{
Primary: "moonshot/kimi-k2.5",
},
},
},
}
}

func (c *openclaw) GetContainerSpecs(ctx context.Context, llm *models.SLLM, image *models.SLLMImage, sku *models.SLLMSku, props []string, devices []computeapi.SIsolatedDevice, diskId string) []*computeapi.PodContainerCreateInput {
diskIndex := 0

Expand All @@ -240,7 +264,15 @@ func (c *openclaw) GetContainerSpecs(ctx context.Context, llm *models.SLLM, imag
SubDirectory: "config",
},
Type: commonapi.CONTAINER_VOLUME_MOUNT_TYPE_DISK,
MountPath: browserConfigDir,
MountPath: desktopConfigDir,
},
{
Disk: &commonapi.ContainerVolumeMountDisk{
Index: &diskIndex,
SubDirectory: "home",
},
Type: commonapi.CONTAINER_VOLUME_MOUNT_TYPE_DISK,
MountPath: homeDir,
},
{
Disk: &commonapi.ContainerVolumeMountDisk{
Expand All @@ -250,6 +282,13 @@ func (c *openclaw) GetContainerSpecs(ctx context.Context, llm *models.SLLM, imag
Type: commonapi.CONTAINER_VOLUME_MOUNT_TYPE_DISK,
MountPath: openclawDataDir,
},
{
Type: commonapi.CONTAINER_VOLUME_MOUNT_TYPE_TEXT,
Text: &commonapi.ContainerVolumeMountText{
Content: jsonutils.Marshal(c.getOpenClawBaseConfig(llm)).PrettyString(),
},
MountPath: api.LLM_OPENCLAW_CUSTOM_CONFIG_FILE,
},
}
httpAuthUsername := "admin"
httpAuthPassword := "clawadmin@123"
Expand All @@ -268,6 +307,10 @@ func (c *openclaw) GetContainerSpecs(ctx context.Context, llm *models.SLLM, imag
{Key: "PUID", Value: "1000"},
{Key: "PGID", Value: "1000"},
{Key: "LC_ALL", Value: "zh_CN.UTF-8"},

// webtop envs: https://github.com/linuxserver/docker-webtop?tab=readme-ov-file#advanced-configuration
// {Key: "DISABLE_SUDO", Value: "true"},

// Provider
// {Key: "MOONSHOT_API_KEY", Value: "abc"},
// {Key: "OPENCLAW_PRIMARY_MODEL", Value: "moonshot/kimi-k2.5"},
Expand All @@ -276,12 +319,13 @@ func (c *openclaw) GetContainerSpecs(ctx context.Context, llm *models.SLLM, imag
{Key: string(api.LLM_OPENCLAW_CUSTOM_USER), Value: httpAuthUsername},
{Key: string(api.LLM_OPENCLAW_AUTH_PASSWORD), Value: httpAuthPassword},
{Key: string(api.LLM_OPENCLAW_PASSWORD), Value: httpAuthPassword},
{Key: string(api.LLM_OPENCLAW_CUSTOM_CONFIG), Value: api.LLM_OPENCLAW_CUSTOM_CONFIG_FILE},
// // Browser sidecar
// {Key: "BROWSER_CDP_URL", Value: "http://localhost" + ":" + openclawBrowserCDPPort},
// {Key: "BROWSER_DEFAULT_PROFILE", Value: "openclaw"},
// {Key: "BROWSER_EVALUATE_ENABLED", Value: "true"},
// OpenClaw env
{Key: "OPENCLAW_GATEWAY_TOKEN", Value: "abcd"},
{Key: "OPENCLAW_GATEWAY_TOKEN", Value: llm.GetId()},
{Key: "OPENCLAW_GATEWAY_PORT", Value: "18789"},
{Key: "OPENCLAW_GATEWAY_BIND", Value: "loopback"},
{Key: "OPENCLAW_STATE_DIR", Value: "/config/.openclaw"},
Expand All @@ -299,7 +343,7 @@ func (c *openclaw) GetContainerSpecs(ctx context.Context, llm *models.SLLM, imag
Index: &diskIndex,
SubDirectory: "rootfs",
},
Persistent: true,
Persistent: false,
},
}
// inject credential envs
Expand All @@ -320,6 +364,27 @@ func (c *openclaw) GetContainerSpecs(ctx context.Context, llm *models.SLLM, imag
for _, channel := range skuSpec.Channels {
openclawSpec.Envs = appendCredentialEnvs(openclawSpec.Envs, channel.Credential)
}
// inject workspace templates
if skuSpec.WorkspaceTemplates != nil {
if skuSpec.WorkspaceTemplates.AgentsMD != "" {
openclawSpec.Envs = append(openclawSpec.Envs, &commonapi.ContainerKeyValue{
Key: string(api.LLM_OPENCLAW_TEMPLATE_AGENTS_MD_B64),
Value: base64.StdEncoding.EncodeToString([]byte(skuSpec.WorkspaceTemplates.AgentsMD)),
})
}
if skuSpec.WorkspaceTemplates.SoulMD != "" {
openclawSpec.Envs = append(openclawSpec.Envs, &commonapi.ContainerKeyValue{
Key: string(api.LLM_OPENCLAW_TEMPLATE_SOUL_MD_B64),
Value: base64.StdEncoding.EncodeToString([]byte(skuSpec.WorkspaceTemplates.SoulMD)),
})
}
if skuSpec.WorkspaceTemplates.UserMD != "" {
openclawSpec.Envs = append(openclawSpec.Envs, &commonapi.ContainerKeyValue{
Key: string(api.LLM_OPENCLAW_TEMPLATE_USER_MD_B64),
Value: base64.StdEncoding.EncodeToString([]byte(skuSpec.WorkspaceTemplates.UserMD)),
})
}
}

return []*computeapi.PodContainerCreateInput{
{
Expand Down
Loading