v1.7.0: Integrate ClawWork Economic AI Agent Platform

This commit is contained in:
admin
2026-02-26 18:24:48 +04:00
Unverified
parent 1387a8b1c6
commit ff4da9d16c
5 changed files with 1097 additions and 6 deletions

508
src/tools/clawwork.ts Normal file
View File

@@ -0,0 +1,508 @@
/**
* ClawWork Integration for QwenClaw
*
* Economic accountability layer for AI agents
* Integrates with Agents Council and FULL RAG
*/
import { spawn } from "child_process";
import { join } from "path";
import { existsSync, readFileSync, writeFile } from "fs";
const CLAWWORK_DIR = process.env.CLAWWORK_DIR || join(process.env.HOME || process.env.USERPROFILE || "", "ClawWork");
const CONFIG_FILE = join(process.env.HOME || process.env.USERPROFILE || "", ".clawwork", "config.json");
const STATE_FILE = join(process.env.HOME || process.env.USERPROFILE || "", ".clawwork", "state.json");
export interface ClawWorkConfig {
autoStart: boolean;
dashboard: boolean;
port: number;
agent: AgentConfig;
tools: ToolsConfig;
rag: RAGConfig;
}
export interface AgentConfig {
initialBalance: number;
survivalMode: 'conservative' | 'balanced' | 'aggressive';
autoSubmit: boolean;
learningThreshold: number;
}
export interface ToolsConfig {
webSearch: {
provider: 'tavily' | 'jina';
apiKey?: string;
};
codeExecution: {
provider: 'e2b';
apiKey?: string;
};
}
export interface RAGConfig {
enabled: boolean;
shareWithCouncil: boolean;
vectorStore: 'sqlite' | 'chroma' | 'pinecone';
}
const DEFAULT_CONFIG: ClawWorkConfig = {
autoStart: true,
dashboard: true,
port: 3000,
agent: {
initialBalance: 10,
survivalMode: 'balanced',
autoSubmit: true,
learningThreshold: 50,
},
tools: {
webSearch: {
provider: 'tavily',
},
codeExecution: {
provider: 'e2b',
},
},
rag: {
enabled: true,
shareWithCouncil: true,
vectorStore: 'sqlite',
},
};
/**
* ClawWork Client
*/
export class ClawWorkClient {
private config: ClawWorkConfig;
private running: boolean = false;
constructor(config: Partial<ClawWorkConfig> = {}) {
this.config = { ...DEFAULT_CONFIG, ...config };
}
/**
* Start ClawWork server
*/
async start(): Promise<void> {
if (this.running) {
console.log("[ClawWork] Already running");
return;
}
console.log("[ClawWork] Starting ClawWork server...");
const serverProcess = spawn("python", ["-m", "clawwork.server"], {
cwd: CLAWWORK_DIR,
stdio: ["pipe", "pipe", "pipe"],
});
serverProcess.stdout?.on("data", (data) => {
console.log(`[ClawWork] ${data.toString().trim()}`);
});
serverProcess.stderr?.on("data", (data) => {
console.error(`[ClawWork Error] ${data.toString().trim()}`);
});
this.running = true;
// Start dashboard if configured
if (this.config.dashboard) {
this.startDashboard();
}
await new Promise((resolve) => setTimeout(resolve, 3000));
console.log("[ClawWork] ✅ Started");
}
/**
* Start React dashboard
*/
private startDashboard(): void {
console.log("[ClawWork] Starting dashboard...");
const dashboardProcess = spawn("npm", ["start"], {
cwd: join(CLAWWORK_DIR, "frontend"),
detached: true,
stdio: "ignore",
});
dashboardProcess.unref();
}
/**
* Stop ClawWork
*/
async stop(): Promise<void> {
this.running = false;
console.log("[ClawWork] Stopped");
}
/**
* Get agent status
*/
async getStatus(): Promise<AgentStatus> {
if (!existsSync(STATE_FILE)) {
return {
balance: this.config.agent.initialBalance,
tokenCosts: 0,
survivalTier: 'starting',
tasksCompleted: 0,
};
}
try {
const state = JSON.parse(readFileSync(STATE_FILE, "utf-8"));
return {
balance: state.balance || this.config.agent.initialBalance,
tokenCosts: state.tokenCosts || 0,
survivalTier: this.calculateSurvivalTier(state.balance),
tasksCompleted: state.tasksCompleted || 0,
};
} catch {
return {
balance: this.config.agent.initialBalance,
tokenCosts: 0,
survivalTier: 'starting',
tasksCompleted: 0,
};
}
}
/**
* Calculate survival tier based on balance
*/
private calculateSurvivalTier(balance: number): SurvivalTier {
if (balance > 500) return 'thriving';
if (balance > 100) return 'stable';
if (balance > 20) return 'surviving';
return 'at_risk';
}
/**
* Decide activity (work or learn)
*/
async decideActivity(): Promise<ActivityDecision> {
const status = await this.getStatus();
// Low balance - should learn first
if (status.balance < this.config.agent.learningThreshold) {
return {
activity: 'learn',
reason: `Balance ($${status.balance}) below threshold ($${this.config.agent.learningThreshold}). Invest in learning for higher-value tasks.`,
};
}
// Good balance - work
return {
activity: 'work',
reason: `Balance ($${status.balance}) sufficient. Ready for income-generating tasks.`,
};
}
/**
* Get available task
*/
async getTask(options?: TaskOptions): Promise<Task> {
console.log("[ClawWork] Fetching task...");
return new Promise((resolve, reject) => {
const args = ["-m", "clawwork.get_task"];
if (options?.minDifficulty) {
args.push("--difficulty", options.minDifficulty);
}
const proc = spawn("python", args, {
cwd: CLAWWORK_DIR,
stdio: ["pipe", "pipe", "pipe"],
});
let output = "";
proc.stdout?.on("data", (data) => {
output += data.toString();
});
proc.on("close", (code) => {
if (code === 0) {
try {
const task = JSON.parse(output);
resolve(task);
} catch {
reject(new Error("Failed to parse task"));
}
} else {
reject(new Error("Failed to get task"));
}
});
});
}
/**
* Work on task
*/
async work(task: Task): Promise<WorkResult> {
console.log(`[ClawWork] Working on task: ${task.id}`);
// This would integrate with QwenClaw agents to complete the task
return {
taskId: task.id,
artifact: 'artifact.pdf',
description: 'Task completed',
qualityEstimate: 0.8,
};
}
/**
* Submit completed work
*/
async submitWork(result: WorkResult): Promise<number> {
console.log(`[ClawWork] Submitting work: ${result.taskId}`);
return new Promise((resolve, reject) => {
const args = [
"-m", "clawwork.submit",
"--task", result.taskId,
"--artifact", result.artifact,
];
const proc = spawn("python", args, {
cwd: CLAWWORK_DIR,
stdio: ["pipe", "pipe", "pipe"],
});
let output = "";
proc.stdout?.on("data", (data) => {
output += data.toString();
});
proc.on("close", (code) => {
if (code === 0) {
try {
const payment = JSON.parse(output).payment;
resolve(payment);
} catch {
resolve(0);
}
} else {
reject(new Error("Submission failed"));
}
});
});
}
/**
* Learn new skill
*/
async learn(knowledge: string): Promise<void> {
if (knowledge.length < 200) {
throw new Error("Knowledge must be at least 200 characters");
}
console.log("[ClawWork] Learning new knowledge...");
return new Promise((resolve, reject) => {
const proc = spawn("python", ["-m", "clawwork.learn"], {
cwd: CLAWWORK_DIR,
stdio: ["pipe", "pipe", "pipe"],
});
proc.stdin?.write(knowledge);
proc.stdin?.end();
proc.on("close", (code) => {
if (code === 0) {
console.log("[ClawWork] ✅ Learning complete");
resolve();
} else {
reject(new Error("Learning failed"));
}
});
});
}
/**
* Search web
*/
async searchWeb(query: string): Promise<SearchResult[]> {
console.log(`[ClawWork] Searching: ${query}`);
// Would integrate with Tavily or Jina
return [];
}
/**
* Create file
*/
async createFile(file: FileSpec): Promise<string> {
console.log(`[ClawWork] Creating file: ${file.path}`);
return new Promise((resolve, reject) => {
const proc = spawn("python", ["-m", "clawwork.create_file", file.path], {
cwd: CLAWWORK_DIR,
stdio: ["pipe", "pipe", "pipe"],
});
proc.stdin?.write(JSON.stringify(file.content));
proc.stdin?.end();
proc.on("close", (code) => {
if (code === 0) {
resolve(file.path);
} else {
reject(new Error("File creation failed"));
}
});
});
}
/**
* Execute code
*/
async executeCode(code: string): Promise<CodeResult> {
console.log("[ClawWork] Executing code...");
return new Promise((resolve, reject) => {
const proc = spawn("python", ["-m", "clawwork.execute_code"], {
cwd: CLAWWORK_DIR,
stdio: ["pipe", "pipe", "pipe"],
});
let output = "";
proc.stdout?.on("data", (data) => {
output += data.toString();
});
proc.stdin?.write(code);
proc.stdin?.end();
proc.on("close", (code) => {
if (code === 0) {
resolve({ output, success: true });
} else {
resolve({ output, success: false });
}
});
});
}
}
interface AgentStatus {
balance: number;
tokenCosts: number;
survivalTier: SurvivalTier;
tasksCompleted: number;
}
type SurvivalTier = 'thriving' | 'stable' | 'surviving' | 'at_risk' | 'starting';
interface ActivityDecision {
activity: 'work' | 'learn';
reason: string;
}
interface TaskOptions {
minDifficulty?: 'easy' | 'medium' | 'hard';
}
interface Task {
id: string;
sector: string;
description: string;
estimatedHours: number;
difficulty: 'easy' | 'medium' | 'hard';
value: number;
}
interface WorkResult {
taskId: string;
artifact: string;
description: string;
qualityEstimate: number;
}
interface SearchResult {
title: string;
url: string;
snippet: string;
}
interface FileSpec {
type: 'txt' | 'xlsx' | 'docx' | 'pdf';
path: string;
content: any;
}
interface CodeResult {
output: string;
success: boolean;
}
/**
* Initialize ClawWork
*/
export async function initClawWork(): Promise<ClawWorkClient> {
const client = new ClawWorkClient();
if (client['config'].autoStart) {
await client.start();
}
return client;
}
/**
* CLI command for ClawWork
*/
export async function clawworkCommand(args: string[]): Promise<void> {
console.log("💼 ClawWork - Economic AI Agent Platform\n");
if (args.length === 0) {
console.log("Usage: qwenclaw clawwork <command> [options]");
console.log("");
console.log("Commands:");
console.log(" start - Start ClawWork server");
console.log(" dashboard - Open React dashboard");
console.log(" status - Check agent balance/status");
console.log(" work - Start working on tasks");
console.log(" learn <topic> - Learn new skill");
console.log(" submit - Submit completed work");
console.log("");
console.log("Examples:");
console.log(" qwenclaw clawwork start");
console.log(" qwenclaw clawwork status");
console.log(" qwenclaw clawwork learn 'Financial analysis'");
return;
}
const command = args[0];
const client = new ClawWorkClient();
switch (command) {
case "start":
await client.start();
break;
case "status":
const status = await client.getStatus();
console.log("ClawWork Agent Status:");
console.log(` Balance: $${status.balance.toFixed(2)}`);
console.log(` Token Costs: $${status.tokenCosts.toFixed(2)}`);
console.log(` Survival Tier: ${status.survivalTier}`);
console.log(` Tasks Completed: ${status.tasksCompleted}`);
break;
case "learn":
if (!args[1]) {
console.log("[ERROR] Knowledge topic required");
return;
}
await client.learn(args.slice(1).join(" "));
break;
default:
console.log(`[ERROR] Unknown command: ${command}`);
}
}