chore: rename project to ByteClaw (module, binary, env prefix BYTECLAW_, Android package/app/theme)
This commit is contained in:
parent
bf00f56117
commit
399bcd46fb
28 changed files with 104 additions and 101 deletions
10
Dockerfile
10
Dockerfile
|
|
@ -6,15 +6,15 @@ COPY go.mod go.sum ./
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
COPY . .
|
COPY . .
|
||||||
ARG VERSION=docker
|
ARG VERSION=docker
|
||||||
RUN CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" -o /out/openclaw ./cmd/openclaw \
|
RUN CGO_ENABLED=0 go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" -o /out/byteclaw ./cmd/byteclaw \
|
||||||
&& mkdir -p /out/data
|
&& mkdir -p /out/data
|
||||||
|
|
||||||
FROM gcr.io/distroless/static-debian12:nonroot
|
FROM gcr.io/distroless/static-debian12:nonroot
|
||||||
COPY --from=build /out/openclaw /usr/local/bin/openclaw
|
COPY --from=build /out/byteclaw /usr/local/bin/byteclaw
|
||||||
COPY --from=build --chown=65532:65532 /out/data /data
|
COPY --from=build --chown=65532:65532 /out/data /data
|
||||||
ENV OPENCLAW_DATA_DIR=/data \
|
ENV BYTECLAW_DATA_DIR=/data \
|
||||||
OPENCLAW_LISTEN=0.0.0.0:8787
|
BYTECLAW_LISTEN=0.0.0.0:8787
|
||||||
USER 65532:65532
|
USER 65532:65532
|
||||||
EXPOSE 8787
|
EXPOSE 8787
|
||||||
VOLUME ["/data"]
|
VOLUME ["/data"]
|
||||||
ENTRYPOINT ["/usr/local/bin/openclaw"]
|
ENTRYPOINT ["/usr/local/bin/byteclaw"]
|
||||||
|
|
|
||||||
16
Makefile
16
Makefile
|
|
@ -1,4 +1,4 @@
|
||||||
BINARY := openclaw
|
BINARY := byteclaw
|
||||||
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
|
VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo dev)
|
||||||
LDFLAGS := -s -w -X main.version=$(VERSION)
|
LDFLAGS := -s -w -X main.version=$(VERSION)
|
||||||
GOFLAGS := -trimpath
|
GOFLAGS := -trimpath
|
||||||
|
|
@ -10,7 +10,7 @@ export CGO_ENABLED := 0
|
||||||
all: vet test build
|
all: vet test build
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o bin/$(BINARY) ./cmd/openclaw
|
go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o bin/$(BINARY) ./cmd/byteclaw
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test ./...
|
go test ./...
|
||||||
|
|
@ -27,20 +27,20 @@ run: build
|
||||||
cross: linux-amd64 linux-arm64 linux-armv7 android-arm64 android-armv7
|
cross: linux-amd64 linux-arm64 linux-armv7 android-arm64 android-armv7
|
||||||
|
|
||||||
linux-amd64:
|
linux-amd64:
|
||||||
GOOS=linux GOARCH=amd64 go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-linux-amd64 ./cmd/openclaw
|
GOOS=linux GOARCH=amd64 go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-linux-amd64 ./cmd/byteclaw
|
||||||
linux-arm64:
|
linux-arm64:
|
||||||
GOOS=linux GOARCH=arm64 go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-linux-arm64 ./cmd/openclaw
|
GOOS=linux GOARCH=arm64 go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-linux-arm64 ./cmd/byteclaw
|
||||||
linux-armv7:
|
linux-armv7:
|
||||||
GOOS=linux GOARCH=arm GOARM=7 go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-linux-armv7 ./cmd/openclaw
|
GOOS=linux GOARCH=arm GOARM=7 go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-linux-armv7 ./cmd/byteclaw
|
||||||
# Termux on Android: GOOS=android, pure Go (no NDK needed thanks to CGO_ENABLED=0)
|
# Termux on Android: GOOS=android, pure Go (no NDK needed thanks to CGO_ENABLED=0)
|
||||||
android-arm64:
|
android-arm64:
|
||||||
GOOS=android GOARCH=arm64 go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-termux-arm64 ./cmd/openclaw
|
GOOS=android GOARCH=arm64 go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-termux-arm64 ./cmd/byteclaw
|
||||||
# android/arm needs cgo+NDK; a static linux/arm binary runs fine in Termux instead.
|
# android/arm needs cgo+NDK; a static linux/arm binary runs fine in Termux instead.
|
||||||
android-armv7:
|
android-armv7:
|
||||||
GOOS=linux GOARCH=arm GOARM=7 go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-termux-armv7 ./cmd/openclaw
|
GOOS=linux GOARCH=arm GOARM=7 go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o $(DIST)/$(BINARY)-termux-armv7 ./cmd/byteclaw
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
docker build -t openclaw:$(VERSION) .
|
docker build -t byteclaw:$(VERSION) .
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf bin $(DIST)
|
rm -rf bin $(DIST)
|
||||||
|
|
|
||||||
24
README.md
24
README.md
|
|
@ -1,11 +1,11 @@
|
||||||
# OpenClaw
|
# ByteClaw
|
||||||
|
|
||||||
Schlanker, selbst gehosteter KI-Assistent: **Go-Backend** (ein statisches Binary, kein CGO) + **nativer Android-Client** (Kotlin, Jetpack Compose).
|
Schlanker, selbst gehosteter KI-Assistent: **Go-Backend** (ein statisches Binary, kein CGO) + **nativer Android-Client** (Kotlin, Jetpack Compose).
|
||||||
|
|
||||||
## Architektur
|
## Architektur
|
||||||
|
|
||||||
```
|
```
|
||||||
Android-App (Compose) Go-Backend (cmd/openclaw)
|
Android-App (Compose) Go-Backend (cmd/byteclaw)
|
||||||
├─ Einstellungen (EncryptedSharedPrefs) ├─ internal/server HTTP-API + WebSocket, Bearer-Token, Origin-Check
|
├─ Einstellungen (EncryptedSharedPrefs) ├─ internal/server HTTP-API + WebSocket, Bearer-Token, Origin-Check
|
||||||
├─ Chat ──── WebSocket /api/ws ───────▶ ├─ internal/agent Agent-Loop mit Tool-Calling, Lock pro Session
|
├─ Chat ──── WebSocket /api/ws ───────▶ ├─ internal/agent Agent-Loop mit Tool-Calling, Lock pro Session
|
||||||
└─ Sessions ─ REST /api/sessions ──────▶ ├─ internal/llm Provider-Interface + OpenAI-kompatibler Streaming-Provider
|
└─ Sessions ─ REST /api/sessions ──────▶ ├─ internal/llm Provider-Interface + OpenAI-kompatibler Streaming-Provider
|
||||||
|
|
@ -34,9 +34,9 @@ Abhängigkeiten des Backends: `gopkg.in/yaml.v3`, `modernc.org/sqlite`, `github.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cp config.example.yaml config.yaml
|
cp config.example.yaml config.yaml
|
||||||
export OPENCLAW_AUTH_TOKEN=$(openssl rand -hex 32)
|
export BYTECLAW_AUTH_TOKEN=$(openssl rand -hex 32)
|
||||||
export OPENCLAW_LLM_API_KEY=sk-... # OpenAI / OpenRouter; für Ollama leer lassen
|
export BYTECLAW_LLM_API_KEY=sk-... # OpenAI / OpenRouter; für Ollama leer lassen
|
||||||
make run # = go build + ./bin/openclaw -config config.yaml
|
make run # = go build + ./bin/byteclaw -config config.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
Provider-Beispiele (`llm.base_url` / `llm.model`):
|
Provider-Beispiele (`llm.base_url` / `llm.model`):
|
||||||
|
|
@ -51,7 +51,7 @@ Test:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl localhost:8787/healthz
|
curl localhost:8787/healthz
|
||||||
curl -H "Authorization: Bearer $OPENCLAW_AUTH_TOKEN" -d '{"text":"Wie spät ist es in Berlin?"}' localhost:8787/api/chat
|
curl -H "Authorization: Bearer $BYTECLAW_AUTH_TOKEN" -d '{"text":"Wie spät ist es in Berlin?"}' localhost:8787/api/chat
|
||||||
```
|
```
|
||||||
|
|
||||||
### API
|
### API
|
||||||
|
|
@ -79,14 +79,14 @@ make cross # dist/: linux-amd64, linux-arm64, linux-armv7, termux-arm64, te
|
||||||
make docker
|
make docker
|
||||||
```
|
```
|
||||||
|
|
||||||
Termux: `openclaw-termux-arm64` ist ein `GOOS=android`-Build; für armv7 wird ein statisches `linux/arm`-Binary gebaut, da `android/arm` ohne NDK/CGO nicht linkbar ist. In Termux z. B. nach `$PREFIX/bin` kopieren, `chmod +x` und starten.
|
Termux: `byteclaw-termux-arm64` ist ein `GOOS=android`-Build; für armv7 wird ein statisches `linux/arm`-Binary gebaut, da `android/arm` ohne NDK/CGO nicht linkbar ist. In Termux z. B. nach `$PREFIX/bin` kopieren, `chmod +x` und starten.
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker build -t openclaw .
|
docker build -t byteclaw .
|
||||||
docker run -d -p 127.0.0.1:8787:8787 -v openclaw-data:/data \
|
docker run -d -p 127.0.0.1:8787:8787 -v byteclaw-data:/data \
|
||||||
-e OPENCLAW_AUTH_TOKEN=... -e OPENCLAW_LLM_API_KEY=... openclaw
|
-e BYTECLAW_AUTH_TOKEN=... -e BYTECLAW_LLM_API_KEY=... byteclaw
|
||||||
```
|
```
|
||||||
|
|
||||||
Im Container lauscht der Server auf `0.0.0.0:8787`; nach außen nur hinter einem TLS-Reverse-Proxy (Caddy, Traefik) oder in einem VPN (z. B. Tailscale) freigeben.
|
Im Container lauscht der Server auf `0.0.0.0:8787`; nach außen nur hinter einem TLS-Reverse-Proxy (Caddy, Traefik) oder in einem VPN (z. B. Tailscale) freigeben.
|
||||||
|
|
@ -95,9 +95,9 @@ Im Container lauscht der Server auf `0.0.0.0:8787`; nach außen nur hinter einem
|
||||||
|
|
||||||
```
|
```
|
||||||
android/
|
android/
|
||||||
├─ app/src/main/java/dev/openclaw/client/
|
├─ app/src/main/java/dev/byteclaw/client/
|
||||||
│ ├─ MainActivity.kt Navigation (Chat, Sessions, Einstellungen)
|
│ ├─ MainActivity.kt Navigation (Chat, Sessions, Einstellungen)
|
||||||
│ ├─ data/OpenClawApi.kt OkHttp REST + WebSocket-Flow
|
│ ├─ data/ByteClawApi.kt OkHttp REST + WebSocket-Flow
|
||||||
│ ├─ data/SettingsStore.kt EncryptedSharedPreferences
|
│ ├─ data/SettingsStore.kt EncryptedSharedPreferences
|
||||||
│ ├─ data/Models.kt kotlinx.serialization
|
│ ├─ data/Models.kt kotlinx.serialization
|
||||||
│ └─ ui/ ChatViewModel, Compose-Screens
|
│ └─ ui/ ChatViewModel, Compose-Screens
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "dev.openclaw.client"
|
namespace = "dev.byteclaw.client"
|
||||||
compileSdk = 35
|
compileSdk = 35
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "dev.openclaw.client"
|
applicationId = "dev.byteclaw.client"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 1
|
versionCode = 1
|
||||||
|
|
|
||||||
4
android/app/proguard-rules.pro
vendored
4
android/app/proguard-rules.pro
vendored
|
|
@ -1,5 +1,5 @@
|
||||||
-keepattributes *Annotation*, InnerClasses
|
-keepattributes *Annotation*, InnerClasses
|
||||||
-keepclassmembers class dev.openclaw.client.data.** { *** Companion; }
|
-keepclassmembers class dev.byteclaw.client.data.** { *** Companion; }
|
||||||
-keepclasseswithmembers class dev.openclaw.client.data.** { kotlinx.serialization.KSerializer serializer(...); }
|
-keepclasseswithmembers class dev.byteclaw.client.data.** { kotlinx.serialization.KSerializer serializer(...); }
|
||||||
# Tink (security-crypto) compile-only annotations
|
# Tink (security-crypto) compile-only annotations
|
||||||
-dontwarn com.google.errorprone.annotations.**
|
-dontwarn com.google.errorprone.annotations.**
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:icon="@android:drawable/sym_def_app_icon"
|
android:icon="@android:drawable/sym_def_app_icon"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:theme="@android:style/Theme.Material.NoActionBar">
|
android:theme="@style/Theme.ByteClaw">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dev.openclaw.client
|
package dev.byteclaw.client
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
|
|
@ -15,10 +15,10 @@ import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import dev.openclaw.client.ui.ChatScreen
|
import dev.byteclaw.client.ui.ChatScreen
|
||||||
import dev.openclaw.client.ui.ChatViewModel
|
import dev.byteclaw.client.ui.ChatViewModel
|
||||||
import dev.openclaw.client.ui.SessionsScreen
|
import dev.byteclaw.client.ui.SessionsScreen
|
||||||
import dev.openclaw.client.ui.SettingsScreen
|
import dev.byteclaw.client.ui.SettingsScreen
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
package dev.openclaw.client.ui
|
package dev.byteclaw.client.ui
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import androidx.lifecycle.AndroidViewModel
|
import androidx.lifecycle.AndroidViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dev.openclaw.client.data.OpenClawApi
|
import dev.byteclaw.client.data.ByteClawApi
|
||||||
import dev.openclaw.client.data.ServerSettings
|
import dev.byteclaw.client.data.ServerSettings
|
||||||
import dev.openclaw.client.data.Session
|
import dev.byteclaw.client.data.Session
|
||||||
import dev.openclaw.client.data.SettingsStore
|
import dev.byteclaw.client.data.SettingsStore
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
|
@ -30,7 +30,7 @@ class ChatViewModel(app: Application) : AndroidViewModel(app) {
|
||||||
val state: StateFlow<UiState> = _state
|
val state: StateFlow<UiState> = _state
|
||||||
private var job: Job? = null
|
private var job: Job? = null
|
||||||
|
|
||||||
private fun api() = OpenClawApi(_state.value.settings)
|
private fun api() = ByteClawApi(_state.value.settings)
|
||||||
|
|
||||||
fun saveSettings(s: ServerSettings) {
|
fun saveSettings(s: ServerSettings) {
|
||||||
store.save(s)
|
store.save(s)
|
||||||
|
|
@ -39,7 +39,7 @@ class ChatViewModel(app: Application) : AndroidViewModel(app) {
|
||||||
|
|
||||||
fun testConnection(s: ServerSettings, onResult: (String) -> Unit) = viewModelScope.launch {
|
fun testConnection(s: ServerSettings, onResult: (String) -> Unit) = viewModelScope.launch {
|
||||||
val msg = runCatching {
|
val msg = runCatching {
|
||||||
OpenClawApi(s).sessions(); "Verbindung OK"
|
ByteClawApi(s).sessions(); "Verbindung OK"
|
||||||
}.getOrElse { "Fehler: ${it.message}" }
|
}.getOrElse { "Fehler: ${it.message}" }
|
||||||
onResult(msg)
|
onResult(msg)
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package dev.openclaw.client.ui
|
package dev.byteclaw.client.ui
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
|
@ -25,8 +25,8 @@ import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.text.input.KeyboardType
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
import androidx.compose.ui.text.input.PasswordVisualTransformation
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import dev.openclaw.client.data.OpenClawApi
|
import dev.byteclaw.client.data.ByteClawApi
|
||||||
import dev.openclaw.client.data.ServerSettings
|
import dev.byteclaw.client.data.ServerSettings
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -39,7 +39,7 @@ fun ChatScreen(vm: ChatViewModel, state: UiState, onSessions: () -> Unit, onSett
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = {
|
topBar = {
|
||||||
TopAppBar(
|
TopAppBar(
|
||||||
title = { Text("OpenClaw") },
|
title = { Text("ByteClaw") },
|
||||||
navigationIcon = { IconButton(onClick = onSessions) { Icon(Icons.AutoMirrored.Filled.List, "Sessions") } },
|
navigationIcon = { IconButton(onClick = onSessions) { Icon(Icons.AutoMirrored.Filled.List, "Sessions") } },
|
||||||
actions = {
|
actions = {
|
||||||
IconButton(onClick = vm::newChat) { Icon(Icons.Filled.Add, "Neuer Chat") }
|
IconButton(onClick = vm::newChat) { Icon(Icons.Filled.Add, "Neuer Chat") }
|
||||||
|
|
@ -134,7 +134,7 @@ fun SettingsScreen(vm: ChatViewModel, state: UiState, onBack: () -> Unit) {
|
||||||
var url by remember { mutableStateOf(state.settings.serverUrl) }
|
var url by remember { mutableStateOf(state.settings.serverUrl) }
|
||||||
var token by remember { mutableStateOf(state.settings.token) }
|
var token by remember { mutableStateOf(state.settings.token) }
|
||||||
var status by remember { mutableStateOf<String?>(null) }
|
var status by remember { mutableStateOf<String?>(null) }
|
||||||
val urlError = if (url.isBlank()) null else OpenClawApi.validateUrl(url)
|
val urlError = if (url.isBlank()) null else ByteClawApi.validateUrl(url)
|
||||||
Scaffold(topBar = {
|
Scaffold(topBar = {
|
||||||
TopAppBar(title = { Text("Einstellungen") },
|
TopAppBar(title = { Text("Einstellungen") },
|
||||||
navigationIcon = { IconButton(onClick = onBack) { Icon(Icons.AutoMirrored.Filled.ArrowBack, "Zurück") } })
|
navigationIcon = { IconButton(onClick = onBack) { Icon(Icons.AutoMirrored.Filled.ArrowBack, "Zurück") } })
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">OpenClaw</string>
|
<string name="app_name">ByteClaw</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
3
android/app/src/main/res/values/themes.xml
Normal file
3
android/app/src/main/res/values/themes.xml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
<resources>
|
||||||
|
<style name="Theme.ByteClaw" parent="android:Theme.Material.NoActionBar" />
|
||||||
|
</resources>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package dev.openclaw.client
|
package dev.byteclaw.client
|
||||||
|
|
||||||
import dev.openclaw.client.data.AgentEvent
|
import dev.byteclaw.client.data.AgentEvent
|
||||||
import dev.openclaw.client.data.Message
|
import dev.byteclaw.client.data.Message
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
@ -12,5 +12,5 @@ dependencyResolutionManagement {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rootProject.name = "OpenClaw"
|
rootProject.name = "ByteClaw"
|
||||||
include(":app")
|
include(":app")
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Command openclaw runs the OpenClaw assistant server.
|
// Command byteclaw runs the ByteClaw assistant server.
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -14,22 +14,22 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/agent"
|
"github.com/crypto/byteclaw/internal/agent"
|
||||||
"github.com/crypto/openclaw/internal/config"
|
"github.com/crypto/byteclaw/internal/config"
|
||||||
"github.com/crypto/openclaw/internal/llm"
|
"github.com/crypto/byteclaw/internal/llm"
|
||||||
"github.com/crypto/openclaw/internal/server"
|
"github.com/crypto/byteclaw/internal/server"
|
||||||
"github.com/crypto/openclaw/internal/store"
|
"github.com/crypto/byteclaw/internal/store"
|
||||||
"github.com/crypto/openclaw/internal/tools"
|
"github.com/crypto/byteclaw/internal/tools"
|
||||||
)
|
)
|
||||||
|
|
||||||
var version = "dev"
|
var version = "dev"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cfgPath := flag.String("config", os.Getenv("OPENCLAW_CONFIG"), "path to config file (.yaml/.yml/.json)")
|
cfgPath := flag.String("config", os.Getenv("BYTECLAW_CONFIG"), "path to config file (.yaml/.yml/.json)")
|
||||||
showVersion := flag.Bool("version", false, "print version")
|
showVersion := flag.Bool("version", false, "print version")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
if *showVersion {
|
if *showVersion {
|
||||||
fmt.Println("openclaw", version)
|
fmt.Println("byteclaw", version)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
log := slog.New(slog.NewTextHandler(os.Stderr, nil))
|
||||||
|
|
@ -47,7 +47,7 @@ func run(cfgPath string, log *slog.Logger) error {
|
||||||
if err := os.MkdirAll(cfg.DataDir, 0o750); err != nil {
|
if err := os.MkdirAll(cfg.DataDir, 0o750); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
st, err := store.Open(filepath.Join(cfg.DataDir, "openclaw.db"))
|
st, err := store.Open(filepath.Join(cfg.DataDir, "byteclaw.db"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -74,7 +74,7 @@ func run(cfgPath string, log *slog.Logger) error {
|
||||||
defer stop()
|
defer stop()
|
||||||
errc := make(chan error, 1)
|
errc := make(chan error, 1)
|
||||||
go func() {
|
go func() {
|
||||||
log.Info("openclaw listening", "addr", cfg.Listen, "model", cfg.LLM.Model, "tools", len(reg.Specs()), "version", version)
|
log.Info("byteclaw listening", "addr", cfg.Listen, "model", cfg.LLM.Model, "tools", len(reg.Specs()), "version", version)
|
||||||
errc <- hs.ListenAndServe()
|
errc <- hs.ListenAndServe()
|
||||||
}()
|
}()
|
||||||
select {
|
select {
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# OpenClaw configuration. Secrets can come from env instead:
|
# ByteClaw configuration. Secrets can come from env instead:
|
||||||
# OPENCLAW_AUTH_TOKEN, OPENCLAW_LLM_API_KEY, OPENCLAW_LLM_BASE_URL, OPENCLAW_LLM_MODEL,
|
# BYTECLAW_AUTH_TOKEN, BYTECLAW_LLM_API_KEY, BYTECLAW_LLM_BASE_URL, BYTECLAW_LLM_MODEL,
|
||||||
# OPENCLAW_LISTEN, OPENCLAW_DATA_DIR, OPENCLAW_WORKSPACE, OPENCLAW_ALLOWED_ORIGINS (comma separated)
|
# BYTECLAW_LISTEN, BYTECLAW_DATA_DIR, BYTECLAW_WORKSPACE, BYTECLAW_ALLOWED_ORIGINS (comma separated)
|
||||||
listen: 127.0.0.1:8787 # bind to 0.0.0.0 only behind TLS (reverse proxy) or in a trusted LAN
|
listen: 127.0.0.1:8787 # bind to 0.0.0.0 only behind TLS (reverse proxy) or in a trusted LAN
|
||||||
auth_token: "" # required, >= 16 chars. Generate: openssl rand -hex 32
|
auth_token: "" # required, >= 16 chars. Generate: openssl rand -hex 32
|
||||||
allowed_origins: [] # browser origins allowed besides same host; "*" only if you really mean it
|
allowed_origins: [] # browser origins allowed besides same host; "*" only if you really mean it
|
||||||
|
|
@ -15,7 +15,7 @@ llm:
|
||||||
temperature: 0.7
|
temperature: 0.7
|
||||||
|
|
||||||
agent:
|
agent:
|
||||||
system_prompt: "You are OpenClaw, a concise and helpful self-hosted assistant. Use tools when they help."
|
system_prompt: "You are ByteClaw, a concise and helpful self-hosted assistant. Use tools when they help."
|
||||||
max_iterations: 8
|
max_iterations: 8
|
||||||
history_limit: 50
|
history_limit: 50
|
||||||
|
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -1,4 +1,4 @@
|
||||||
module github.com/crypto/openclaw
|
module github.com/crypto/byteclaw
|
||||||
|
|
||||||
go 1.25.0
|
go 1.25.0
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/llm"
|
"github.com/crypto/byteclaw/internal/llm"
|
||||||
"github.com/crypto/openclaw/internal/store"
|
"github.com/crypto/byteclaw/internal/store"
|
||||||
"github.com/crypto/openclaw/internal/tools"
|
"github.com/crypto/byteclaw/internal/tools"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Event is streamed to clients while the agent works.
|
// Event is streamed to clients while the agent works.
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/llm"
|
"github.com/crypto/byteclaw/internal/llm"
|
||||||
"github.com/crypto/openclaw/internal/store"
|
"github.com/crypto/byteclaw/internal/store"
|
||||||
"github.com/crypto/openclaw/internal/tools"
|
"github.com/crypto/byteclaw/internal/tools"
|
||||||
)
|
)
|
||||||
|
|
||||||
// scripted provider returns queued responses and records requests.
|
// scripted provider returns queued responses and records requests.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Package config loads OpenClaw configuration from YAML/JSON files and env vars.
|
// Package config loads ByteClaw configuration from YAML/JSON files and env vars.
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -67,7 +67,7 @@ func Default() Config {
|
||||||
Temperature: 0.7,
|
Temperature: 0.7,
|
||||||
},
|
},
|
||||||
Agent: Agent{
|
Agent: Agent{
|
||||||
SystemPrompt: "You are OpenClaw, a concise and helpful self-hosted assistant. Use tools when they help.",
|
SystemPrompt: "You are ByteClaw, a concise and helpful self-hosted assistant. Use tools when they help.",
|
||||||
MaxIterations: 8,
|
MaxIterations: 8,
|
||||||
HistoryLimit: 50,
|
HistoryLimit: 50,
|
||||||
},
|
},
|
||||||
|
|
@ -110,14 +110,14 @@ func applyEnv(c *Config, get func(string) string) {
|
||||||
*dst = v
|
*dst = v
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set("OPENCLAW_LISTEN", &c.Listen)
|
set("BYTECLAW_LISTEN", &c.Listen)
|
||||||
set("OPENCLAW_AUTH_TOKEN", &c.AuthToken)
|
set("BYTECLAW_AUTH_TOKEN", &c.AuthToken)
|
||||||
set("OPENCLAW_DATA_DIR", &c.DataDir)
|
set("BYTECLAW_DATA_DIR", &c.DataDir)
|
||||||
set("OPENCLAW_WORKSPACE", &c.Workspace)
|
set("BYTECLAW_WORKSPACE", &c.Workspace)
|
||||||
set("OPENCLAW_LLM_BASE_URL", &c.LLM.BaseURL)
|
set("BYTECLAW_LLM_BASE_URL", &c.LLM.BaseURL)
|
||||||
set("OPENCLAW_LLM_API_KEY", &c.LLM.APIKey)
|
set("BYTECLAW_LLM_API_KEY", &c.LLM.APIKey)
|
||||||
set("OPENCLAW_LLM_MODEL", &c.LLM.Model)
|
set("BYTECLAW_LLM_MODEL", &c.LLM.Model)
|
||||||
if v := get("OPENCLAW_ALLOWED_ORIGINS"); v != "" {
|
if v := get("BYTECLAW_ALLOWED_ORIGINS"); v != "" {
|
||||||
c.AllowedOrigins = nil
|
c.AllowedOrigins = nil
|
||||||
for _, o := range strings.Split(v, ",") {
|
for _, o := range strings.Split(v, ",") {
|
||||||
if o = strings.TrimSpace(o); o != "" {
|
if o = strings.TrimSpace(o); o != "" {
|
||||||
|
|
@ -131,7 +131,7 @@ func applyEnv(c *Config, get func(string) string) {
|
||||||
func (c Config) Validate() error {
|
func (c Config) Validate() error {
|
||||||
var errs []error
|
var errs []error
|
||||||
if len(c.AuthToken) < 16 {
|
if len(c.AuthToken) < 16 {
|
||||||
errs = append(errs, errors.New("auth_token must be set and at least 16 characters (OPENCLAW_AUTH_TOKEN)"))
|
errs = append(errs, errors.New("auth_token must be set and at least 16 characters (BYTECLAW_AUTH_TOKEN)"))
|
||||||
}
|
}
|
||||||
if c.LLM.BaseURL == "" || c.LLM.Model == "" {
|
if c.LLM.BaseURL == "" || c.LLM.Model == "" {
|
||||||
errs = append(errs, errors.New("llm.base_url and llm.model are required"))
|
errs = append(errs, errors.New("llm.base_url and llm.model are required"))
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ func TestLoadYAMLAndEnv(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
p := filepath.Join(dir, "c.yaml")
|
p := filepath.Join(dir, "c.yaml")
|
||||||
os.WriteFile(p, []byte("auth_token: aaaaaaaaaaaaaaaaaaaa\nllm:\n model: llama3\n"), 0o600)
|
os.WriteFile(p, []byte("auth_token: aaaaaaaaaaaaaaaaaaaa\nllm:\n model: llama3\n"), 0o600)
|
||||||
t.Setenv("OPENCLAW_LLM_BASE_URL", "http://localhost:11434/v1")
|
t.Setenv("BYTECLAW_LLM_BASE_URL", "http://localhost:11434/v1")
|
||||||
t.Setenv("OPENCLAW_ALLOWED_ORIGINS", "https://a.example, https://b.example")
|
t.Setenv("BYTECLAW_ALLOWED_ORIGINS", "https://a.example, https://b.example")
|
||||||
c, err := Load(p)
|
c, err := Load(p)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
@ -37,7 +37,7 @@ func TestLoadJSON(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateRequiresToken(t *testing.T) {
|
func TestValidateRequiresToken(t *testing.T) {
|
||||||
t.Setenv("OPENCLAW_AUTH_TOKEN", "")
|
t.Setenv("BYTECLAW_AUTH_TOKEN", "")
|
||||||
if _, err := Load(""); err == nil {
|
if _, err := Load(""); err == nil {
|
||||||
t.Fatal("expected error without token")
|
t.Fatal("expected error without token")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ import (
|
||||||
"github.com/coder/websocket"
|
"github.com/coder/websocket"
|
||||||
"github.com/coder/websocket/wsjson"
|
"github.com/coder/websocket/wsjson"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/agent"
|
"github.com/crypto/byteclaw/internal/agent"
|
||||||
"github.com/crypto/openclaw/internal/store"
|
"github.com/crypto/byteclaw/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxBody = 256 << 10
|
const maxBody = 256 << 10
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,10 @@ import (
|
||||||
"github.com/coder/websocket"
|
"github.com/coder/websocket"
|
||||||
"github.com/coder/websocket/wsjson"
|
"github.com/coder/websocket/wsjson"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/agent"
|
"github.com/crypto/byteclaw/internal/agent"
|
||||||
"github.com/crypto/openclaw/internal/llm"
|
"github.com/crypto/byteclaw/internal/llm"
|
||||||
"github.com/crypto/openclaw/internal/store"
|
"github.com/crypto/byteclaw/internal/store"
|
||||||
"github.com/crypto/openclaw/internal/tools"
|
"github.com/crypto/byteclaw/internal/tools"
|
||||||
)
|
)
|
||||||
|
|
||||||
const tok = "test-token-0123456789"
|
const tok = "test-token-0123456789"
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/llm"
|
"github.com/crypto/byteclaw/internal/llm"
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/llm"
|
"github.com/crypto/byteclaw/internal/llm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestStoreRoundTrip(t *testing.T) {
|
func TestStoreRoundTrip(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/llm"
|
"github.com/crypto/byteclaw/internal/llm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Workspace confines file access to a root directory using os.Root
|
// Workspace confines file access to a root directory using os.Root
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/llm"
|
"github.com/crypto/byteclaw/internal/llm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TimeNow returns the current time, optionally in an IANA time zone.
|
// TimeNow returns the current time, optionally in an IANA time zone.
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/llm"
|
"github.com/crypto/byteclaw/internal/llm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Tool interface {
|
type Tool interface {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/crypto/openclaw/internal/llm"
|
"github.com/crypto/byteclaw/internal/llm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// WebFetch downloads a URL with timeout and size limit. By default it refuses
|
// WebFetch downloads a URL with timeout and size limit. By default it refuses
|
||||||
|
|
@ -91,7 +91,7 @@ func (w *WebFetch) Call(ctx context.Context, raw json.RawMessage) (string, error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
req.Header.Set("User-Agent", "OpenClaw/0.1 (+self-hosted assistant)")
|
req.Header.Set("User-Agent", "ByteClaw/0.1 (+self-hosted assistant)")
|
||||||
resp, err := w.client.Do(req)
|
resp, err := w.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue