feat(docs): initialize response wrapper and custom Pi documentation

This commit is contained in:
Tim Z. 2026-04-07 11:54:47 +02:00
parent 1175f4a62b
commit 0400b31c8e
5 changed files with 162 additions and 1 deletions

1
.gitignore vendored
View file

@ -69,3 +69,4 @@ web/backend/dist/*
docker/data
.omc/
/local_pi/

View file

@ -0,0 +1,51 @@
# Git Workflow Guide
This guide breaks down how to manage your custom `picoclaw` logic alongside upstream official releases.
## Core Concepts
- **Forking** is for **Taking Ownership**: It creates an independent copy of an entire project repository on your GitHub account so you have full read/write admin controls.
- **Branching** is for **Making Changes**: It isolates a specific line of code history (e.g., `feature/wrapper`) so you can experiment without breaking your working `main` branch.
## The "One Custom Branch" Strategy (Best & Lowest Effort)
For maintaining a personal Raspberry Pi deployment, the cleanest, least confusing, and absolute lowest effort method is to literally never switch branches again. Instead of juggling dozens of feature branches, you maintain a single dedicated branch (e.g., `custom-pi`) that holds all your custom logic.
**Initial Setup:**
1. **The Fork**: You forked `sipeed/picoclaw` to `TimZickenrott/picoclaw`.
2. **The Clone**: You downloaded your fork to your PC.
3. **The Branch**: You started on `feature/wrapper`. Let's rename this to be your permanent deploy branch:
```bash
git branch -m feature/wrapper custom-pi
```
From now on, you always work on and deploy from `custom-pi`.
### How to Save Your Work (Pushing)
When you write new custom code or edit features, just commit and push directly to `custom-pi` to save it:
```bash
git add .
git commit -m "Added my new custom logic"
git push origin custom-pi
```
## How To Pull Official Updates (Merging)
When the official Sipeed developers release a new version (e.g., bugfixes or new capabilities), you want to pull those into your `custom-pi` branch so you get the newest features without losing your wrapper code.
Here is exactly how you do it, all from your `custom-pi` branch:
*(Assuming you already added the original repo as an 'upstream' remote)*
```bash
# 1. Download the newest official code
git fetch upstream
# 2. Smoothly merge the newest official features directly into your custom code
git merge upstream/main
```
### How Git Resolves This
- **The Safe Merge:** If Sipeed changed completely different files than you did (e.g., they fixed a bug in `telegram.go`, but you modified `loop.go`), Git will automatically splice the files together perfectly silently. Your wrapper stays intact.
- **The Merge Conflict:** If the developers modified the *exact same* lines of code in `loop.go` that you modified, Git will pause the merge and declare a "Merge Conflict."
- You open `loop.go` in your IDE. You will see markers (`<<<<<<`) showing their new code alongside your custom code.
- You manually edit that block to make sure your wrapper surrounds their new logic, save it, and run `git merge --continue`.
Since your custom wrapper is self-contained and small, adjusting the code during a conflict takes barely a minute!

54
docs/custom/pi-build.md Normal file
View file

@ -0,0 +1,54 @@
# Raspberry Pi Build Guide
This guide details the step-by-step process for building a custom version of Picoclaw and transferring it to a Raspberry Pi Zero 2W running locally.
## Prerequisite: On Vulcan (Windows)
1. **Install Go**: Ensure Go is installed on your Windows machine (`https://go.dev/dl/`). Add it to your `PATH` or invoke it directly.
2. **Clone repo**: Clone your custom fork of Picoclaw:
```bash
git clone https://github.com/<your-username>/picoclaw.git
```
3. **Modify code**: Make your custom logic changes (e.g., in `pkg/agent/metrics.go` and `pkg/agent/loop.go`).
## Step A: Compile for Raspberry Pi (ARM v7)
Since the Raspberry Pi Zero 2W is an ARM-based environment (running a 32-bit `armhf` OS usually), we use Go's powerful cross-compilation features natively on Windows.
Run this single command in PowerShell from the repository root:
```powershell
$env:CGO_ENABLED="0"; $env:GOOS="linux"; $env:GOARCH="arm"; $env:GOARM="7"; go build -o picoclaw-custom ./cmd/picoclaw
```
This instructs the Go compiler to generate a standalone Linux executable tailored for the Pi's architecture.
## Step B: Transfer to Pi
Use `scp` (Secure Copy Protocol), which transfers files over an encrypted SSH connection.
```powershell
scp picoclaw-custom tim@picoclaw.local:/tmp/
```
*This copies your newly compiled `picoclaw-custom` file from Windows up to the `/tmp/` folder on your Pi.*
## Step C: Update the Raspberry Pi Service
Log into your Raspberry Pi terminal via SSH.
1. **Stop the current running service**:
```bash
sudo systemctl stop picoclaw
```
2. **Replace the old binary with the new custom one**:
```bash
sudo mv /tmp/picoclaw-custom /usr/local/bin/picoclaw
```
*(Ensure the binary is executable: `sudo chmod +x /usr/local/bin/picoclaw`)*
3. **Restart the service to utilize the new brain**:
```bash
sudo systemctl start picoclaw
```
### Why Cross-Compile?
Cross-compiling on your powerful Windows desktop ("Vulcan") saves the Raspberry Pi Zero 2W from the massive heat, CPU stress, and time-consumption of downloading the Go SDK and compiling code with 512MB of RAM.

View file

@ -1589,10 +1589,37 @@ func (al *AgentLoop) runAgentLoop(
}
if opts.SendResponse && result.finalContent != "" {
var totalTokens, promptTokens, compTokens int
if usage := ts.GetLastUsage(); usage != nil {
totalTokens = usage.TotalTokens
promptTokens = usage.PromptTokens
compTokens = usage.CompletionTokens
}
version := al.GetConfig().BuildInfo.Version
if version == "" {
version = "0.2.5"
}
providerName := al.GetConfig().Agents.Defaults.Provider
modelName := al.GetConfig().Agents.Defaults.GetModelName()
m := Metrics{
Version: version,
Agent: agent.ID,
Route: providerName,
Model: modelName,
Complexity: calculateComplexity(promptTokens, compTokens),
Tokens: totalTokens,
Processing: time.Since(ts.startedAt),
}
finalWrappedContent := WrapResponse(result.finalContent, m)
al.bus.PublishOutbound(ctx, bus.OutboundMessage{
Channel: opts.Channel,
ChatID: opts.ChatID,
Content: result.finalContent,
Content: finalWrappedContent,
})
}

28
pkg/agent/metrics.go Normal file
View file

@ -0,0 +1,28 @@
package agent
import (
"fmt"
"time"
)
type Metrics struct {
Version string
Agent string
Route string
Model string
Complexity int
Tokens int
Processing time.Duration
}
func WrapResponse(rawOutput string, m Metrics) string {
header := fmt.Sprintf(
"System: picoclaw-%s\nAgent: %s\nRoute: %s\nModel: %s\nComplexity: %d\nTokens: %d\nProcessing: %.1fs\n\n",
m.Version, m.Agent, m.Route, m.Model, m.Complexity, m.Tokens, m.Processing.Seconds(),
)
return header + rawOutput
}
func calculateComplexity(promptTokens, completionTokens int) int {
return int(float64(promptTokens)*0.1 + float64(completionTokens)*0.5)
}