refactor: 统一项目名称从OpenFang到ZCLAW
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
重构所有代码和文档中的项目名称,将OpenFang统一更新为ZCLAW。包括: - 配置文件中的项目名称 - 代码注释和文档引用 - 环境变量和路径 - 类型定义和接口名称 - 测试用例和模拟数据 同时优化部分代码结构,移除未使用的模块,并更新相关依赖项。
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* API Fallbacks for ZCLAW Gateway
|
||||
*
|
||||
* Provides sensible default data when OpenFang API endpoints return 404.
|
||||
* Provides sensible default data when ZCLAW API endpoints return 404.
|
||||
* This allows the UI to function gracefully even when backend features
|
||||
* are not yet implemented.
|
||||
*/
|
||||
@@ -178,7 +178,7 @@ export function getUsageStatsFallback(sessions: SessionForStats[] = []): UsageSt
|
||||
|
||||
/**
|
||||
* Convert skills to plugin status when /api/plugins/status returns 404.
|
||||
* OpenFang uses Skills instead of traditional plugins.
|
||||
* ZCLAW uses Skills instead of traditional plugins.
|
||||
*/
|
||||
export function getPluginStatusFallback(skills: SkillForPlugins[] = []): PluginStatusFallback[] {
|
||||
if (skills.length === 0) {
|
||||
@@ -215,7 +215,7 @@ export function getScheduledTasksFallback(triggers: TriggerForTasks[] = []): Sch
|
||||
|
||||
/**
|
||||
* Default security status when /api/security/status returns 404.
|
||||
* OpenFang has 16 security layers - show them with conservative defaults.
|
||||
* ZCLAW has 16 security layers - show them with conservative defaults.
|
||||
*/
|
||||
export function getSecurityStatusFallback(): SecurityStatusFallback {
|
||||
const layers: SecurityLayerFallback[] = [
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* OpenFang Configuration Parser
|
||||
* ZCLAW Configuration Parser
|
||||
*
|
||||
* Provides configuration parsing, validation, and serialization for OpenFang TOML files.
|
||||
* Provides configuration parsing, validation, and serialization for ZCLAW TOML files.
|
||||
*
|
||||
* @module lib/config-parser
|
||||
*/
|
||||
@@ -9,7 +9,7 @@
|
||||
import { tomlUtils, TomlParseError } from './toml-utils';
|
||||
import { DEFAULT_MODEL_ID, DEFAULT_PROVIDER } from '../constants/models';
|
||||
import type {
|
||||
OpenFangConfig,
|
||||
ZclawConfig,
|
||||
ConfigValidationResult,
|
||||
ConfigValidationError,
|
||||
ConfigValidationWarning,
|
||||
@@ -64,7 +64,7 @@ const REQUIRED_FIELDS: Array<{ path: string; description: string }> = [
|
||||
/**
|
||||
* Default configuration values
|
||||
*/
|
||||
const DEFAULT_CONFIG: Partial<OpenFangConfig> = {
|
||||
const DEFAULT_CONFIG: Partial<ZclawConfig> = {
|
||||
server: {
|
||||
host: '127.0.0.1',
|
||||
port: 4200,
|
||||
@@ -74,7 +74,7 @@ const DEFAULT_CONFIG: Partial<OpenFangConfig> = {
|
||||
},
|
||||
agent: {
|
||||
defaults: {
|
||||
workspace: '~/.openfang/workspace',
|
||||
workspace: '~/.zclaw/workspace',
|
||||
default_model: DEFAULT_MODEL_ID,
|
||||
},
|
||||
},
|
||||
@@ -89,7 +89,7 @@ const DEFAULT_CONFIG: Partial<OpenFangConfig> = {
|
||||
*/
|
||||
export const configParser = {
|
||||
/**
|
||||
* Parse TOML content into an OpenFang configuration object
|
||||
* Parse TOML content into a ZCLAW configuration object
|
||||
*
|
||||
* @param content - The TOML content to parse
|
||||
* @param envVars - Optional environment variables for resolution
|
||||
@@ -101,13 +101,13 @@ export const configParser = {
|
||||
* const config = configParser.parseConfig(tomlContent, { OPENAI_API_KEY: 'sk-...' });
|
||||
* ```
|
||||
*/
|
||||
parseConfig: (content: string, envVars?: Record<string, string | undefined>): OpenFangConfig => {
|
||||
parseConfig: (content: string, envVars?: Record<string, string | undefined>): ZclawConfig => {
|
||||
try {
|
||||
// First resolve environment variables
|
||||
const resolved = tomlUtils.resolveEnvVars(content, envVars);
|
||||
|
||||
// Parse TOML
|
||||
const parsed = tomlUtils.parse<OpenFangConfig>(resolved);
|
||||
const parsed = tomlUtils.parse<ZclawConfig>(resolved);
|
||||
return parsed;
|
||||
} catch (error) {
|
||||
if (error instanceof TomlParseError) {
|
||||
@@ -121,7 +121,7 @@ export const configParser = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Validate an OpenFang configuration object
|
||||
* Validate a ZCLAW configuration object
|
||||
*
|
||||
* @param config - The configuration object to validate
|
||||
* @returns Validation result with errors and warnings
|
||||
@@ -238,7 +238,7 @@ export const configParser = {
|
||||
parseAndValidate: (
|
||||
content: string,
|
||||
envVars?: Record<string, string | undefined>
|
||||
): OpenFangConfig => {
|
||||
): ZclawConfig => {
|
||||
const config = configParser.parseConfig(content, envVars);
|
||||
const result = configParser.validateConfig(config);
|
||||
if (!result.valid) {
|
||||
@@ -261,7 +261,7 @@ export const configParser = {
|
||||
* const toml = configParser.stringifyConfig(config);
|
||||
* ```
|
||||
*/
|
||||
stringifyConfig: (config: OpenFangConfig): string => {
|
||||
stringifyConfig: (config: ZclawConfig): string => {
|
||||
return tomlUtils.stringify(config as unknown as Record<string, unknown>);
|
||||
},
|
||||
|
||||
@@ -276,8 +276,8 @@ export const configParser = {
|
||||
* const fullConfig = configParser.mergeWithDefaults(partialConfig);
|
||||
* ```
|
||||
*/
|
||||
mergeWithDefaults: (config: Partial<OpenFangConfig>): OpenFangConfig => {
|
||||
return deepMerge(DEFAULT_CONFIG, config) as unknown as OpenFangConfig;
|
||||
mergeWithDefaults: (config: Partial<ZclawConfig>): ZclawConfig => {
|
||||
return deepMerge(DEFAULT_CONFIG, config) as unknown as ZclawConfig;
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -307,19 +307,19 @@ export const configParser = {
|
||||
/**
|
||||
* Get default configuration
|
||||
*
|
||||
* @returns Default OpenFang configuration
|
||||
* @returns Default ZCLAW configuration
|
||||
*/
|
||||
getDefaults: (): OpenFangConfig => {
|
||||
return JSON.parse(JSON.stringify(DEFAULT_CONFIG)) as OpenFangConfig;
|
||||
getDefaults: (): ZclawConfig => {
|
||||
return JSON.parse(JSON.stringify(DEFAULT_CONFIG)) as ZclawConfig;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if a configuration object is valid
|
||||
*
|
||||
* @param config - The configuration to check
|
||||
* @returns Type guard for OpenFangConfig
|
||||
* @returns Type guard for ZclawConfig
|
||||
*/
|
||||
isOpenFangConfig: (config: unknown): config is OpenFangConfig => {
|
||||
isZclawConfig: (config: unknown): config is ZclawConfig => {
|
||||
const result = configParser.validateConfig(config);
|
||||
return result.valid;
|
||||
},
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
* - Agents (Clones)
|
||||
* - Stats & Workspace
|
||||
* - Config (Quick Config, Channels, Skills, Scheduler, Models)
|
||||
* - Hands (OpenFang)
|
||||
* - Workflows (OpenFang)
|
||||
* - Sessions (OpenFang)
|
||||
* - Triggers (OpenFang)
|
||||
* - Audit (OpenFang)
|
||||
* - Security (OpenFang)
|
||||
* - Approvals (OpenFang)
|
||||
* - Hands (ZCLAW)
|
||||
* - Workflows (ZCLAW)
|
||||
* - Sessions (ZCLAW)
|
||||
* - Triggers (ZCLAW)
|
||||
* - Audit (ZCLAW)
|
||||
* - Security (ZCLAW)
|
||||
* - Approvals (ZCLAW)
|
||||
*
|
||||
* These methods are installed onto GatewayClient.prototype via installApiMethods().
|
||||
* The GatewayClient core class exposes restGet/restPost/restPut/restDelete/restPatch
|
||||
@@ -179,7 +179,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
|
||||
const storedAutoStart = localStorage.getItem('zclaw-autoStart');
|
||||
const storedShowToolCalls = localStorage.getItem('zclaw-showToolCalls');
|
||||
|
||||
// Map OpenFang config to frontend expected format
|
||||
// Map ZCLAW config to frontend expected format
|
||||
return {
|
||||
quickConfig: {
|
||||
agentName: 'ZCLAW',
|
||||
@@ -220,15 +220,15 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
|
||||
localStorage.setItem('zclaw-showToolCalls', String(config.showToolCalls));
|
||||
}
|
||||
|
||||
// Map frontend config back to OpenFang format
|
||||
const openfangConfig = {
|
||||
// Map frontend config back to ZCLAW format
|
||||
const zclawConfig = {
|
||||
data_dir: config.workspaceDir,
|
||||
default_model: config.defaultModel ? {
|
||||
model: config.defaultModel,
|
||||
provider: config.defaultProvider || 'bailian',
|
||||
} : undefined,
|
||||
};
|
||||
return this.restPut('/api/config', openfangConfig);
|
||||
return this.restPut('/api/config', zclawConfig);
|
||||
};
|
||||
|
||||
// ─── Skills ───
|
||||
@@ -333,7 +333,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
|
||||
return this.restPatch(`/api/scheduler/tasks/${id}`, { enabled });
|
||||
};
|
||||
|
||||
// ─── OpenFang Hands API ───
|
||||
// ─── ZCLAW Hands API ───
|
||||
|
||||
proto.listHands = async function (this: GatewayClient): Promise<{
|
||||
hands: {
|
||||
@@ -407,7 +407,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
|
||||
return this.restGet(`/api/hands/${name}/runs?${params}`);
|
||||
};
|
||||
|
||||
// ─── OpenFang Workflows API ───
|
||||
// ─── ZCLAW Workflows API ───
|
||||
|
||||
proto.listWorkflows = async function (this: GatewayClient): Promise<{ workflows: { id: string; name: string; steps: number }[] }> {
|
||||
return this.restGet('/api/workflows');
|
||||
@@ -476,7 +476,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
|
||||
return this.restDelete(`/api/workflows/${id}`);
|
||||
};
|
||||
|
||||
// ─── OpenFang Session API ───
|
||||
// ─── ZCLAW Session API ───
|
||||
|
||||
proto.listSessions = async function (this: GatewayClient, opts?: { limit?: number; offset?: number }): Promise<{
|
||||
sessions: Array<{
|
||||
@@ -539,7 +539,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
|
||||
return this.restGet(`/api/sessions/${sessionId}/messages?${params}`);
|
||||
};
|
||||
|
||||
// ─── OpenFang Triggers API ───
|
||||
// ─── ZCLAW Triggers API ───
|
||||
|
||||
proto.listTriggers = async function (this: GatewayClient): Promise<{ triggers: { id: string; type: string; enabled: boolean }[] }> {
|
||||
return this.restGet('/api/triggers');
|
||||
@@ -580,7 +580,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
|
||||
return this.restDelete(`/api/triggers/${id}`);
|
||||
};
|
||||
|
||||
// ─── OpenFang Audit API ───
|
||||
// ─── ZCLAW Audit API ───
|
||||
|
||||
proto.getAuditLogs = async function (this: GatewayClient, opts?: { limit?: number; offset?: number }): Promise<{ logs: unknown[] }> {
|
||||
const params = new URLSearchParams();
|
||||
@@ -598,7 +598,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
|
||||
return this.restGet(`/api/audit/verify/${logId}`);
|
||||
};
|
||||
|
||||
// ─── OpenFang Security API ───
|
||||
// ─── ZCLAW Security API ───
|
||||
|
||||
proto.getSecurityStatus = async function (this: GatewayClient): Promise<{ layers: { name: string; enabled: boolean }[] }> {
|
||||
try {
|
||||
@@ -626,7 +626,7 @@ export function installApiMethods(ClientClass: { prototype: GatewayClient }): vo
|
||||
}
|
||||
};
|
||||
|
||||
// ─── OpenFang Approvals API ───
|
||||
// ─── ZCLAW Approvals API ───
|
||||
|
||||
proto.listApprovals = async function (this: GatewayClient, status?: string): Promise<{
|
||||
approvals: {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
/**
|
||||
* ZCLAW Gateway Client (Browser/Tauri side)
|
||||
*
|
||||
* Core WebSocket client for OpenFang Kernel protocol.
|
||||
* Core WebSocket client for ZCLAW Kernel protocol.
|
||||
* Handles connection management, WebSocket framing, heartbeat,
|
||||
* event dispatch, and chat/stream operations.
|
||||
*
|
||||
@@ -22,7 +22,7 @@ export type {
|
||||
GatewayPong,
|
||||
GatewayFrame,
|
||||
AgentStreamDelta,
|
||||
OpenFangStreamEvent,
|
||||
ZclawStreamEvent,
|
||||
ConnectionState,
|
||||
EventCallback,
|
||||
} from './gateway-types';
|
||||
@@ -51,7 +51,7 @@ import type {
|
||||
GatewayFrame,
|
||||
GatewayResponse,
|
||||
GatewayEvent,
|
||||
OpenFangStreamEvent,
|
||||
ZclawStreamEvent,
|
||||
ConnectionState,
|
||||
EventCallback,
|
||||
AgentStreamDelta,
|
||||
@@ -158,7 +158,7 @@ function createIdempotencyKey(): string {
|
||||
|
||||
export class GatewayClient {
|
||||
private ws: WebSocket | null = null;
|
||||
private openfangWs: WebSocket | null = null; // OpenFang stream WebSocket
|
||||
private zclawWs: WebSocket | null = null; // ZCLAW stream WebSocket
|
||||
private state: ConnectionState = 'disconnected';
|
||||
private requestId = 0;
|
||||
private pendingRequests = new Map<string, {
|
||||
@@ -243,20 +243,20 @@ export class GatewayClient {
|
||||
|
||||
// === Connection ===
|
||||
|
||||
/** Connect using REST API only (for OpenFang mode) */
|
||||
/** Connect using REST API only (for ZCLAW mode) */
|
||||
async connectRest(): Promise<void> {
|
||||
if (this.state === 'connected') {
|
||||
return;
|
||||
}
|
||||
this.setState('connecting');
|
||||
try {
|
||||
// Check if OpenFang API is healthy
|
||||
// Check if ZCLAW API is healthy
|
||||
const health = await this.restGet<{ status: string; version?: string }>('/api/health');
|
||||
if (health.status === 'ok') {
|
||||
this.reconnectAttempts = 0;
|
||||
this.setState('connected');
|
||||
this.startHeartbeat(); // Start heartbeat after successful connection
|
||||
this.log('info', `Connected to OpenFang via REST API${health.version ? ` (v${health.version})` : ''}`);
|
||||
this.log('info', `Connected to ZCLAW via REST API${health.version ? ` (v${health.version})` : ''}`);
|
||||
this.emitEvent('connected', { version: health.version });
|
||||
} else {
|
||||
throw new Error('Health check failed');
|
||||
@@ -264,7 +264,7 @@ export class GatewayClient {
|
||||
} catch (err: unknown) {
|
||||
this.setState('disconnected');
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
throw new Error(`Failed to connect to OpenFang: ${errorMessage}`);
|
||||
throw new Error(`Failed to connect to ZCLAW: ${errorMessage}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ export class GatewayClient {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// Check if URL is for OpenFang (port 4200 or 50051) - use REST mode
|
||||
// Check if URL is for ZCLAW (port 4200 or 50051) - use REST mode
|
||||
if (this.url.includes(':4200') || this.url.includes(':50051')) {
|
||||
return this.connectRest();
|
||||
}
|
||||
@@ -389,10 +389,10 @@ export class GatewayClient {
|
||||
|
||||
// === High-level API ===
|
||||
|
||||
// Default agent ID for OpenFang (will be set dynamically from /api/agents)
|
||||
// Default agent ID for ZCLAW (will be set dynamically from /api/agents)
|
||||
private defaultAgentId: string = '';
|
||||
|
||||
/** Try to fetch default agent ID from OpenFang /api/agents endpoint */
|
||||
/** Try to fetch default agent ID from ZCLAW /api/agents endpoint */
|
||||
async fetchDefaultAgentId(): Promise<string | null> {
|
||||
try {
|
||||
// Use /api/agents endpoint which returns array of agents
|
||||
@@ -422,7 +422,7 @@ export class GatewayClient {
|
||||
return this.defaultAgentId;
|
||||
}
|
||||
|
||||
/** Send message to agent (OpenFang chat API) */
|
||||
/** Send message to agent (ZCLAW chat API) */
|
||||
async chat(message: string, opts?: {
|
||||
sessionKey?: string;
|
||||
agentId?: string;
|
||||
@@ -432,24 +432,24 @@ export class GatewayClient {
|
||||
temperature?: number;
|
||||
maxTokens?: number;
|
||||
}): Promise<{ runId: string; sessionId?: string; response?: string }> {
|
||||
// OpenFang uses /api/agents/{agentId}/message endpoint
|
||||
// ZCLAW uses /api/agents/{agentId}/message endpoint
|
||||
let agentId = opts?.agentId || this.defaultAgentId;
|
||||
|
||||
// If no agent ID, try to fetch from OpenFang status
|
||||
// If no agent ID, try to fetch from ZCLAW status
|
||||
if (!agentId) {
|
||||
await this.fetchDefaultAgentId();
|
||||
agentId = this.defaultAgentId;
|
||||
}
|
||||
|
||||
if (!agentId) {
|
||||
throw new Error('No agent available. Please ensure OpenFang has at least one agent.');
|
||||
throw new Error('No agent available. Please ensure ZCLAW has at least one agent.');
|
||||
}
|
||||
|
||||
const result = await this.restPost<{ response?: string; input_tokens?: number; output_tokens?: number }>(`/api/agents/${agentId}/message`, {
|
||||
message,
|
||||
session_id: opts?.sessionKey,
|
||||
});
|
||||
// OpenFang returns { response, input_tokens, output_tokens }
|
||||
// ZCLAW returns { response, input_tokens, output_tokens }
|
||||
return {
|
||||
runId: createIdempotencyKey(),
|
||||
sessionId: opts?.sessionKey,
|
||||
@@ -457,7 +457,7 @@ export class GatewayClient {
|
||||
};
|
||||
}
|
||||
|
||||
/** Send message with streaming response (OpenFang WebSocket) */
|
||||
/** Send message with streaming response (ZCLAW WebSocket) */
|
||||
async chatStream(
|
||||
message: string,
|
||||
callbacks: {
|
||||
@@ -472,20 +472,20 @@ export class GatewayClient {
|
||||
agentId?: string;
|
||||
}
|
||||
): Promise<{ runId: string }> {
|
||||
let agentId = opts?.agentId || this.defaultAgentId;
|
||||
const agentId = opts?.agentId || this.defaultAgentId;
|
||||
const runId = createIdempotencyKey();
|
||||
const sessionId = opts?.sessionKey || `session_${Date.now()}`;
|
||||
|
||||
// If no agent ID, try to fetch from OpenFang status (async, but we'll handle it in connectOpenFangStream)
|
||||
// If no agent ID, try to fetch from ZCLAW status (async, but we'll handle it in connectZclawStream)
|
||||
if (!agentId) {
|
||||
// Try to get default agent asynchronously
|
||||
this.fetchDefaultAgentId().then(() => {
|
||||
const resolvedAgentId = this.defaultAgentId;
|
||||
if (resolvedAgentId) {
|
||||
this.streamCallbacks.set(runId, callbacks);
|
||||
this.connectOpenFangStream(resolvedAgentId, runId, sessionId, message);
|
||||
this.connectZclawStream(resolvedAgentId, runId, sessionId, message);
|
||||
} else {
|
||||
callbacks.onError('No agent available. Please ensure OpenFang has at least one agent.');
|
||||
callbacks.onError('No agent available. Please ensure ZCLAW has at least one agent.');
|
||||
callbacks.onComplete();
|
||||
}
|
||||
}).catch((err) => {
|
||||
@@ -498,22 +498,22 @@ export class GatewayClient {
|
||||
// Store callbacks for this run
|
||||
this.streamCallbacks.set(runId, callbacks);
|
||||
|
||||
// Connect to OpenFang WebSocket if not connected
|
||||
this.connectOpenFangStream(agentId, runId, sessionId, message);
|
||||
// Connect to ZCLAW WebSocket if not connected
|
||||
this.connectZclawStream(agentId, runId, sessionId, message);
|
||||
|
||||
return { runId };
|
||||
}
|
||||
|
||||
/** Connect to OpenFang streaming WebSocket */
|
||||
private connectOpenFangStream(
|
||||
/** Connect to ZCLAW streaming WebSocket */
|
||||
private connectZclawStream(
|
||||
agentId: string,
|
||||
runId: string,
|
||||
sessionId: string,
|
||||
message: string
|
||||
): void {
|
||||
// Close existing connection if any
|
||||
if (this.openfangWs && this.openfangWs.readyState !== WebSocket.CLOSED) {
|
||||
this.openfangWs.close();
|
||||
if (this.zclawWs && this.zclawWs.readyState !== WebSocket.CLOSED) {
|
||||
this.zclawWs.close();
|
||||
}
|
||||
|
||||
// Build WebSocket URL
|
||||
@@ -528,34 +528,34 @@ export class GatewayClient {
|
||||
wsUrl = httpUrl.replace(/^http/, 'ws') + `/api/agents/${agentId}/ws`;
|
||||
}
|
||||
|
||||
this.log('info', `Connecting to OpenFang stream: ${wsUrl}`);
|
||||
this.log('info', `Connecting to ZCLAW stream: ${wsUrl}`);
|
||||
|
||||
try {
|
||||
this.openfangWs = new WebSocket(wsUrl);
|
||||
this.zclawWs = new WebSocket(wsUrl);
|
||||
|
||||
this.openfangWs.onopen = () => {
|
||||
this.log('info', 'OpenFang WebSocket connected');
|
||||
// Send chat message using OpenFang actual protocol
|
||||
this.zclawWs.onopen = () => {
|
||||
this.log('info', 'ZCLAW WebSocket connected');
|
||||
// Send chat message using ZCLAW actual protocol
|
||||
const chatRequest = {
|
||||
type: 'message',
|
||||
content: message,
|
||||
session_id: sessionId,
|
||||
};
|
||||
this.openfangWs?.send(JSON.stringify(chatRequest));
|
||||
this.zclawWs?.send(JSON.stringify(chatRequest));
|
||||
};
|
||||
|
||||
this.openfangWs.onmessage = (event) => {
|
||||
this.zclawWs.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
this.handleOpenFangStreamEvent(runId, data, sessionId);
|
||||
this.handleZclawStreamEvent(runId, data, sessionId);
|
||||
} catch (err: unknown) {
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
this.log('error', `Failed to parse stream event: ${errorMessage}`);
|
||||
}
|
||||
};
|
||||
|
||||
this.openfangWs.onerror = (_event) => {
|
||||
this.log('error', 'OpenFang WebSocket error');
|
||||
this.zclawWs.onerror = (_event) => {
|
||||
this.log('error', 'ZCLAW WebSocket error');
|
||||
const callbacks = this.streamCallbacks.get(runId);
|
||||
if (callbacks) {
|
||||
callbacks.onError('WebSocket connection failed');
|
||||
@@ -563,14 +563,14 @@ export class GatewayClient {
|
||||
}
|
||||
};
|
||||
|
||||
this.openfangWs.onclose = (event) => {
|
||||
this.log('info', `OpenFang WebSocket closed: ${event.code} ${event.reason}`);
|
||||
this.zclawWs.onclose = (event) => {
|
||||
this.log('info', `ZCLAW WebSocket closed: ${event.code} ${event.reason}`);
|
||||
const callbacks = this.streamCallbacks.get(runId);
|
||||
if (callbacks && event.code !== 1000) {
|
||||
callbacks.onError(`Connection closed: ${event.reason || 'unknown'}`);
|
||||
}
|
||||
this.streamCallbacks.delete(runId);
|
||||
this.openfangWs = null;
|
||||
this.zclawWs = null;
|
||||
};
|
||||
} catch (err: unknown) {
|
||||
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||
@@ -583,13 +583,13 @@ export class GatewayClient {
|
||||
}
|
||||
}
|
||||
|
||||
/** Handle OpenFang stream events */
|
||||
private handleOpenFangStreamEvent(runId: string, data: OpenFangStreamEvent, sessionId: string): void {
|
||||
/** Handle ZCLAW stream events */
|
||||
private handleZclawStreamEvent(runId: string, data: ZclawStreamEvent, sessionId: string): void {
|
||||
const callbacks = this.streamCallbacks.get(runId);
|
||||
if (!callbacks) return;
|
||||
|
||||
switch (data.type) {
|
||||
// OpenFang actual event types
|
||||
// ZCLAW actual event types
|
||||
case 'text_delta':
|
||||
// Stream delta content
|
||||
if (data.content) {
|
||||
@@ -602,8 +602,8 @@ export class GatewayClient {
|
||||
if (data.phase === 'done') {
|
||||
callbacks.onComplete();
|
||||
this.streamCallbacks.delete(runId);
|
||||
if (this.openfangWs) {
|
||||
this.openfangWs.close(1000, 'Stream complete');
|
||||
if (this.zclawWs) {
|
||||
this.zclawWs.close(1000, 'Stream complete');
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -617,8 +617,8 @@ export class GatewayClient {
|
||||
// Mark complete if phase done wasn't sent
|
||||
callbacks.onComplete();
|
||||
this.streamCallbacks.delete(runId);
|
||||
if (this.openfangWs) {
|
||||
this.openfangWs.close(1000, 'Stream complete');
|
||||
if (this.zclawWs) {
|
||||
this.zclawWs.close(1000, 'Stream complete');
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -649,14 +649,14 @@ export class GatewayClient {
|
||||
case 'error':
|
||||
callbacks.onError(data.message || data.code || data.content || 'Unknown error');
|
||||
this.streamCallbacks.delete(runId);
|
||||
if (this.openfangWs) {
|
||||
this.openfangWs.close(1011, 'Error');
|
||||
if (this.zclawWs) {
|
||||
this.zclawWs.close(1011, 'Error');
|
||||
}
|
||||
break;
|
||||
|
||||
case 'connected':
|
||||
// Connection established
|
||||
this.log('info', `OpenFang agent connected: ${data.agent_id}`);
|
||||
this.log('info', `ZCLAW agent connected: ${data.agent_id}`);
|
||||
break;
|
||||
|
||||
case 'agents_updated':
|
||||
@@ -687,12 +687,12 @@ export class GatewayClient {
|
||||
callbacks.onError('Stream cancelled');
|
||||
this.streamCallbacks.delete(runId);
|
||||
}
|
||||
if (this.openfangWs && this.openfangWs.readyState === WebSocket.OPEN) {
|
||||
this.openfangWs.close(1000, 'User cancelled');
|
||||
if (this.zclawWs && this.zclawWs.readyState === WebSocket.OPEN) {
|
||||
this.zclawWs.close(1000, 'User cancelled');
|
||||
}
|
||||
}
|
||||
|
||||
// === REST API Helpers (OpenFang) ===
|
||||
// === REST API Helpers (ZCLAW) ===
|
||||
|
||||
public getRestBaseUrl(): string {
|
||||
// In browser dev mode, use Vite proxy (empty string = relative path)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* OpenFang Gateway Configuration Types
|
||||
* ZCLAW Gateway Configuration Types
|
||||
*
|
||||
* Types for gateway configuration and model choices.
|
||||
*/
|
||||
|
||||
@@ -42,7 +42,7 @@ export function isLocalhost(url: string): boolean {
|
||||
|
||||
// === URL Constants ===
|
||||
|
||||
// OpenFang endpoints (port 50051 - actual running port)
|
||||
// ZCLAW endpoints (port 50051 - actual running port)
|
||||
// Note: REST API uses relative path to leverage Vite proxy for CORS bypass
|
||||
export const DEFAULT_GATEWAY_URL = `${DEFAULT_WS_PROTOCOL}127.0.0.1:50051/ws`;
|
||||
export const REST_API_URL = ''; // Empty = use relative path (Vite proxy)
|
||||
|
||||
@@ -66,8 +66,8 @@ export interface AgentStreamDelta {
|
||||
workflowResult?: unknown;
|
||||
}
|
||||
|
||||
/** OpenFang WebSocket stream event types */
|
||||
export interface OpenFangStreamEvent {
|
||||
/** ZCLAW WebSocket stream event types */
|
||||
export interface ZclawStreamEvent {
|
||||
type: 'text_delta' | 'phase' | 'response' | 'typing' | 'tool_call' | 'tool_result' | 'hand' | 'workflow' | 'error' | 'connected' | 'agents_updated';
|
||||
content?: string;
|
||||
phase?: 'streaming' | 'done';
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Health Check Library
|
||||
*
|
||||
* Provides Tauri health check command wrappers and utilities
|
||||
* for monitoring the health status of the OpenFang backend.
|
||||
* for monitoring the health status of the ZCLAW backend.
|
||||
*/
|
||||
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
@@ -19,7 +19,7 @@ export interface HealthCheckResult {
|
||||
details?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface OpenFangHealthResponse {
|
||||
export interface ZclawHealthResponse {
|
||||
healthy: boolean;
|
||||
message?: string;
|
||||
details?: Record<string, unknown>;
|
||||
@@ -43,7 +43,7 @@ export async function performHealthCheck(): Promise<HealthCheckResult> {
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await invoke<OpenFangHealthResponse>('openfang_health_check');
|
||||
const response = await invoke<ZclawHealthResponse>('zclaw_health_check');
|
||||
|
||||
return {
|
||||
status: response.healthy ? 'healthy' : 'unhealthy',
|
||||
|
||||
@@ -239,6 +239,14 @@ export const memory = {
|
||||
async dbPath(): Promise<string> {
|
||||
return invoke('memory_db_path');
|
||||
},
|
||||
|
||||
async buildContext(
|
||||
agentId: string,
|
||||
query: string,
|
||||
maxTokens: number | null,
|
||||
): Promise<{ systemPromptAddition: string; totalTokens: number; memoriesUsed: number }> {
|
||||
return invoke('memory_build_context', { agentId, query, maxTokens });
|
||||
},
|
||||
};
|
||||
|
||||
// === Heartbeat API ===
|
||||
|
||||
@@ -771,7 +771,7 @@ function saveSnapshotsToStorage(snapshots: IdentitySnapshot[]): void {
|
||||
}
|
||||
|
||||
const fallbackIdentities = loadIdentitiesFromStorage();
|
||||
let fallbackProposals = loadProposalsFromStorage();
|
||||
const fallbackProposals = loadProposalsFromStorage();
|
||||
let fallbackSnapshots = loadSnapshotsFromStorage();
|
||||
|
||||
const fallbackIdentity = {
|
||||
@@ -1073,6 +1073,27 @@ export const intelligenceClient = {
|
||||
}
|
||||
return fallbackMemory.dbPath();
|
||||
},
|
||||
|
||||
buildContext: async (
|
||||
agentId: string,
|
||||
query: string,
|
||||
maxTokens?: number,
|
||||
): Promise<{ systemPromptAddition: string; totalTokens: number; memoriesUsed: number }> => {
|
||||
if (isTauriEnv()) {
|
||||
return intelligence.memory.buildContext(agentId, query, maxTokens ?? null);
|
||||
}
|
||||
// Fallback: use basic search
|
||||
const memories = await fallbackMemory.search({
|
||||
agentId,
|
||||
query,
|
||||
limit: 8,
|
||||
minImportance: 3,
|
||||
});
|
||||
const addition = memories.length > 0
|
||||
? `## 相关记忆\n${memories.map(m => `- [${m.type}] ${m.content}`).join('\n')}`
|
||||
: '';
|
||||
return { systemPromptAddition: addition, totalTokens: 0, memoriesUsed: memories.length };
|
||||
},
|
||||
},
|
||||
|
||||
heartbeat: {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* ZCLAW Kernel Client (Tauri Internal)
|
||||
*
|
||||
* Client for communicating with the internal ZCLAW Kernel via Tauri commands.
|
||||
* This replaces the external OpenFang Gateway WebSocket connection.
|
||||
* This replaces the external ZCLAW Gateway WebSocket connection.
|
||||
*
|
||||
* Phase 5 of Intelligence Layer Migration.
|
||||
*/
|
||||
@@ -648,24 +648,14 @@ export class KernelClient {
|
||||
* Approve a hand execution
|
||||
*/
|
||||
async approveHand(name: string, runId: string, approved: boolean, reason?: string): Promise<{ status: string }> {
|
||||
try {
|
||||
return await invoke('hand_approve', { handName: name, runId, approved, reason });
|
||||
} catch {
|
||||
this.log('warn', `hand_approve not yet implemented, returning fallback`);
|
||||
return { status: approved ? 'approved' : 'rejected' };
|
||||
}
|
||||
return await invoke('hand_approve', { handName: name, runId, approved, reason });
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel a hand execution
|
||||
*/
|
||||
async cancelHand(name: string, runId: string): Promise<{ status: string }> {
|
||||
try {
|
||||
return await invoke('hand_cancel', { handName: name, runId });
|
||||
} catch {
|
||||
this.log('warn', `hand_cancel not yet implemented, returning fallback`);
|
||||
return { status: 'cancelled' };
|
||||
}
|
||||
return await invoke('hand_cancel', { handName: name, runId });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* Supports multiple backends:
|
||||
* - OpenAI (GPT-4, GPT-3.5)
|
||||
* - Volcengine (Doubao)
|
||||
* - OpenFang Gateway (passthrough)
|
||||
* - ZCLAW Gateway (passthrough)
|
||||
*
|
||||
* Part of ZCLAW L4 Self-Evolution capability.
|
||||
*/
|
||||
@@ -284,7 +284,7 @@ class VolcengineLLMAdapter implements LLMServiceAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
// === Gateway Adapter (pass through to OpenFang or internal Kernel) ===
|
||||
// === Gateway Adapter (pass through to ZCLAW or internal Kernel) ===
|
||||
|
||||
class GatewayLLMAdapter implements LLMServiceAdapter {
|
||||
private config: LLMConfig;
|
||||
@@ -346,7 +346,7 @@ class GatewayLLMAdapter implements LLMServiceAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
// External Gateway mode: Use OpenFang's chat endpoint
|
||||
// External Gateway mode: Use ZCLAW's chat endpoint
|
||||
const agentId = localStorage.getItem('zclaw-default-agent-id') || 'default';
|
||||
|
||||
const response = await fetch(`/api/agents/${agentId}/message`, {
|
||||
@@ -403,7 +403,7 @@ class GatewayLLMAdapter implements LLMServiceAdapter {
|
||||
}
|
||||
|
||||
isAvailable(): boolean {
|
||||
// Gateway is available if we're in browser (can connect to OpenFang)
|
||||
// Gateway is available if we're in browser (can connect to ZCLAW)
|
||||
return typeof window !== 'undefined';
|
||||
}
|
||||
|
||||
@@ -460,7 +460,7 @@ export function loadConfig(): LLMConfig {
|
||||
// Ignore parse errors
|
||||
}
|
||||
|
||||
// Default to gateway (OpenFang passthrough) for L4 self-evolution
|
||||
// Default to gateway (ZCLAW passthrough) for L4 self-evolution
|
||||
return DEFAULT_CONFIGS.gateway;
|
||||
}
|
||||
|
||||
|
||||
@@ -239,12 +239,7 @@ export function generateWelcomeMessage(config: {
|
||||
const { userName, agentName, emoji, personality, scenarios } = config;
|
||||
|
||||
// Build greeting
|
||||
let greeting = '';
|
||||
if (userName) {
|
||||
greeting = `你好,${userName}!`;
|
||||
} else {
|
||||
greeting = '你好!';
|
||||
}
|
||||
const greeting = userName ? `你好,${userName}!` : '你好!';
|
||||
|
||||
// Build introduction
|
||||
let intro = `我是${emoji ? ' ' + emoji : ''} ${agentName}`;
|
||||
|
||||
@@ -41,7 +41,7 @@ export function escapeHtml(input: string): string {
|
||||
if (typeof input !== 'string') {
|
||||
return '';
|
||||
}
|
||||
return input.replace(/[&<>"'`=\/]/g, char => HTML_ENTITIES[char] || char);
|
||||
return input.replace(/[&<>"'`=/]/g, (char) => HTML_ENTITIES[char] || char);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -502,12 +502,13 @@ export function sanitizeFilename(filename: string): string {
|
||||
}
|
||||
|
||||
// Remove path separators
|
||||
let sanitized = filename.replace(/[\/\\]/g, '_');
|
||||
let sanitized = filename.replace(/[/\\]/g, '_');
|
||||
|
||||
// Remove null bytes
|
||||
sanitized = sanitized.replace(/\0/g, '');
|
||||
|
||||
// Remove control characters
|
||||
// eslint-disable-next-line no-control-regex
|
||||
sanitized = sanitized.replace(/[\x00-\x1f\x7f]/g, '');
|
||||
|
||||
// Remove dangerous characters
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* TOML Utility Functions
|
||||
*
|
||||
* Provides TOML parsing and serialization capabilities for OpenFang configuration files.
|
||||
* Provides TOML parsing and serialization capabilities for ZCLAW configuration files.
|
||||
* Supports environment variable interpolation in the format ${VAR_NAME}.
|
||||
*
|
||||
* @module toml-utils
|
||||
|
||||
@@ -369,7 +369,7 @@ export function yamlToCanvas(yamlString: string): WorkflowCanvas {
|
||||
|
||||
// Convert steps to nodes
|
||||
if (pipeline.spec.steps) {
|
||||
let x = 300;
|
||||
const x = 300;
|
||||
let y = 50;
|
||||
|
||||
for (const step of pipeline.spec.steps) {
|
||||
|
||||
Reference in New Issue
Block a user