Fix CI: restore onboard embedded workspace and harden timeout test
This commit is contained in:
parent
b3cd76128e
commit
9f662830b1
7 changed files with 204 additions and 3 deletions
12
cmd/picoclaw/internal/onboard/workspace/AGENTS.md
Normal file
12
cmd/picoclaw/internal/onboard/workspace/AGENTS.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# Agent Instructions
|
||||
|
||||
You are a helpful AI assistant. Be concise, accurate, and friendly.
|
||||
|
||||
## Guidelines
|
||||
|
||||
- Always explain what you're doing before taking actions
|
||||
- Ask for clarification when request is ambiguous
|
||||
- Use tools to help accomplish tasks
|
||||
- Remember important information in your memory files
|
||||
- Be proactive and helpful
|
||||
- Learn from user feedback
|
||||
56
cmd/picoclaw/internal/onboard/workspace/IDENTITY.md
Normal file
56
cmd/picoclaw/internal/onboard/workspace/IDENTITY.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# Identity
|
||||
|
||||
## Name
|
||||
PicoClaw 🦞
|
||||
|
||||
## Description
|
||||
Ultra-lightweight personal AI assistant written in Go, inspired by nanobot.
|
||||
|
||||
## Version
|
||||
0.1.0
|
||||
|
||||
## Purpose
|
||||
- Provide intelligent AI assistance with minimal resource usage
|
||||
- Support multiple LLM providers (OpenAI, Anthropic, Zhipu, etc.)
|
||||
- Enable easy customization through skills system
|
||||
- Run on minimal hardware ($10 boards, <10MB RAM)
|
||||
|
||||
## Capabilities
|
||||
|
||||
- Web search and content fetching
|
||||
- File system operations (read, write, edit)
|
||||
- Shell command execution
|
||||
- Multi-channel messaging (Telegram, WhatsApp, Feishu)
|
||||
- Skill-based extensibility
|
||||
- Memory and context management
|
||||
|
||||
## Philosophy
|
||||
|
||||
- Simplicity over complexity
|
||||
- Performance over features
|
||||
- User control and privacy
|
||||
- Transparent operation
|
||||
- Community-driven development
|
||||
|
||||
## Goals
|
||||
|
||||
- Provide a fast, lightweight AI assistant
|
||||
- Support offline-first operation where possible
|
||||
- Enable easy customization and extension
|
||||
- Maintain high quality responses
|
||||
- Run efficiently on constrained hardware
|
||||
|
||||
## License
|
||||
MIT License - Free and open source
|
||||
|
||||
## Repository
|
||||
https://github.com/sipeed/picoclaw
|
||||
|
||||
## Contact
|
||||
Issues: https://github.com/sipeed/picoclaw/issues
|
||||
Discussions: https://github.com/sipeed/picoclaw/discussions
|
||||
|
||||
---
|
||||
|
||||
"Every bit helps, every bit matters."
|
||||
- Picoclaw
|
||||
17
cmd/picoclaw/internal/onboard/workspace/SOUL.md
Normal file
17
cmd/picoclaw/internal/onboard/workspace/SOUL.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Soul
|
||||
|
||||
I am picoclaw, a lightweight AI assistant powered by AI.
|
||||
|
||||
## Personality
|
||||
|
||||
- Helpful and friendly
|
||||
- Concise and to the point
|
||||
- Curious and eager to learn
|
||||
- Honest and transparent
|
||||
|
||||
## Values
|
||||
|
||||
- Accuracy over speed
|
||||
- User privacy and safety
|
||||
- Transparency in actions
|
||||
- Continuous improvement
|
||||
21
cmd/picoclaw/internal/onboard/workspace/USER.md
Normal file
21
cmd/picoclaw/internal/onboard/workspace/USER.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# User
|
||||
|
||||
Information about user goes here.
|
||||
|
||||
## Preferences
|
||||
|
||||
- Communication style: (casual/formal)
|
||||
- Timezone: (your timezone)
|
||||
- Language: (your preferred language)
|
||||
|
||||
## Personal Information
|
||||
|
||||
- Name: (optional)
|
||||
- Location: (optional)
|
||||
- Occupation: (optional)
|
||||
|
||||
## Learning Goals
|
||||
|
||||
- What the user wants to learn from AI
|
||||
- Preferred interaction style
|
||||
- Areas of interest
|
||||
21
cmd/picoclaw/internal/onboard/workspace/memory/MEMORY.md
Normal file
21
cmd/picoclaw/internal/onboard/workspace/memory/MEMORY.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Long-term Memory
|
||||
|
||||
This file stores important information that should persist across sessions.
|
||||
|
||||
## User Information
|
||||
|
||||
(Important facts about user)
|
||||
|
||||
## Preferences
|
||||
|
||||
(User preferences learned over time)
|
||||
|
||||
## Important Notes
|
||||
|
||||
(Things to remember)
|
||||
|
||||
## Configuration
|
||||
|
||||
- Model preferences
|
||||
- Channel settings
|
||||
- Skills enabled
|
||||
|
|
@ -3,7 +3,10 @@
|
|||
package tools
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
|
@ -26,7 +29,57 @@ func terminateProcessTree(cmd *exec.Cmd) error {
|
|||
|
||||
// Kill the entire process group spawned by the shell command.
|
||||
_ = syscall.Kill(-pid, syscall.SIGKILL)
|
||||
// Some shells/background jobs may still leave descendants around
|
||||
// briefly; aggressively walk /proc and kill child processes too.
|
||||
killDescendants(pid)
|
||||
// Fallback kill on the shell process itself.
|
||||
_ = cmd.Process.Kill()
|
||||
return nil
|
||||
}
|
||||
|
||||
func killDescendants(ppid int) {
|
||||
if ppid <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir("/proc")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() {
|
||||
continue
|
||||
}
|
||||
childPID, err := strconv.Atoi(e.Name())
|
||||
if err != nil || childPID <= 0 || childPID == ppid {
|
||||
continue
|
||||
}
|
||||
|
||||
statPath := "/proc/" + e.Name() + "/stat"
|
||||
data, err := os.ReadFile(statPath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// /proc/<pid>/stat: pid (comm) state ppid ...
|
||||
raw := string(data)
|
||||
end := strings.LastIndex(raw, ")")
|
||||
if end == -1 || end+2 >= len(raw) {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(raw[end+2:])
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
parent, err := strconv.Atoi(fields[1])
|
||||
if err != nil || parent != ppid {
|
||||
continue
|
||||
}
|
||||
|
||||
// Recurse first, then kill child process/group.
|
||||
killDescendants(childPID)
|
||||
_ = syscall.Kill(-childPID, syscall.SIGKILL)
|
||||
_ = syscall.Kill(childPID, syscall.SIGKILL)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,33 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
func processExists(pid int) bool {
|
||||
func processRunning(pid int) bool {
|
||||
if pid <= 0 {
|
||||
return false
|
||||
}
|
||||
// kill(0) can return success for zombie processes too, so inspect /proc
|
||||
// state and treat zombies as not-running for timeout cleanup assertions.
|
||||
err := syscall.Kill(pid, 0)
|
||||
return err == nil || err == syscall.EPERM
|
||||
if err != nil && err != syscall.EPERM {
|
||||
return false
|
||||
}
|
||||
|
||||
data, readErr := os.ReadFile("/proc/" + strconv.Itoa(pid) + "/stat")
|
||||
if readErr != nil {
|
||||
return false
|
||||
}
|
||||
raw := string(data)
|
||||
end := strings.LastIndex(raw, ")")
|
||||
if end == -1 || end+2 >= len(raw) {
|
||||
return true // best effort fallback
|
||||
}
|
||||
fields := strings.Fields(raw[end+2:])
|
||||
if len(fields) == 0 {
|
||||
return true // best effort fallback
|
||||
}
|
||||
|
||||
state := fields[0]
|
||||
return state != "Z"
|
||||
}
|
||||
|
||||
func TestShellTool_TimeoutKillsChildProcess(t *testing.T) {
|
||||
|
|
@ -55,7 +76,7 @@ func TestShellTool_TimeoutKillsChildProcess(t *testing.T) {
|
|||
|
||||
deadline := time.Now().Add(2 * time.Second)
|
||||
for time.Now().Before(deadline) {
|
||||
if !processExists(childPID) {
|
||||
if !processRunning(childPID) {
|
||||
return
|
||||
}
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue