HarmonyOS 6(API 23)实战:基于悬浮导航、沉浸光感与HMAF的“智流工坊“——低代码可视化智能体编排平台

文章目录

    • 每日一句正能量
    • 前言
    • 一、前言:低代码智能体编排的范式革新
    • 二、核心特性解析与技术选型
      • [2.1 HMAF在低代码编排中的价值](#2.1 HMAF在低代码编排中的价值)
      • [2.2 沉浸光感在可视化编排中的创新应用](#2.2 沉浸光感在可视化编排中的创新应用)
      • [2.3 悬浮导航的编排适配](#2.3 悬浮导航的编排适配)
    • 三、项目实战:"智流工坊"架构设计
      • [3.1 应用场景与功能规划](#3.1 应用场景与功能规划)
      • [3.2 技术架构图](#3.2 技术架构图)
    • 四、环境配置与模块依赖
      • [4.1 模块依赖配置](#4.1 模块依赖配置)
      • [4.2 权限声明(module.json5)](#4.2 权限声明(module.json5))
    • 五、核心组件实战
      • [5.1 窗口沉浸配置(EntryAbility.ets)](#5.1 窗口沉浸配置(EntryAbility.ets))
      • [5.2 节点类型光效系统(NodeLightEffect.ets)](#5.2 节点类型光效系统(NodeLightEffect.ets))
      • [5.3 HMAF可视化编排引擎(OrchestrationEngine.ets)](#5.3 HMAF可视化编排引擎(OrchestrationEngine.ets))
      • [5.4 悬浮编排导航(OrchestrationFloatNavigation.ets)](#5.4 悬浮编排导航(OrchestrationFloatNavigation.ets))
      • [5.5 可视化编排画布(OrchestrationCanvas.ets)](#5.5 可视化编排画布(OrchestrationCanvas.ets))
      • [5.6 浮动属性面板窗口(PropertyPanelWindow.ets)](#5.6 浮动属性面板窗口(PropertyPanelWindow.ets))
      • [5.7 多窗口光效同步管理器(WindowLightSync.ets)](#5.7 多窗口光效同步管理器(WindowLightSync.ets))
      • [5.8 主页面集成(Index.ets)](#5.8 主页面集成(Index.ets))
    • 六、关键技术总结
      • [6.1 HMAF可视化编排开发清单](#6.1 HMAF可视化编排开发清单)
      • [6.2 沉浸光感实现清单](#6.2 沉浸光感实现清单)
      • [6.3 节点类型光效映射](#6.3 节点类型光效映射)
      • [6.4 编排模式光效映射](#6.4 编排模式光效映射)
      • [6.5 PC端多窗口光效协同](#6.5 PC端多窗口光效协同)
    • 七、调试与适配建议
    • 八、总结与展望

每日一句正能量

保持极度自律,不断鞭策自己,你才能真正做出一番事业与成就。

自律不是偶尔为之,而是一种持续的内在驱动力。成功不是靠一时激情,而是靠日复一日对抗惰性的执行系统。

前言

摘要:随着AI智能体应用的爆发式增长,非技术用户快速构建智能体应用的需求日益迫切。HarmonyOS 6(API 23)引入的鸿蒙智能体框架(HMAF)配合小艺开放平台的四种编排模式,为低代码可视化智能体开发提供了全新可能。本文将实战开发一款面向HarmonyOS PC的"智流工坊"应用,展示如何利用HMAF构建拖拽式可视化智能体编排引擎,通过悬浮导航实现画布与组件库状态实时切换,基于沉浸光感打造"节点即氛围"的编排体验,以及基于多窗口架构构建浮动属性面板、预览窗口和调试控制台窗口的协作开发体验。


一、前言:低代码智能体编排的范式革新

2026年,AI智能体已从技术极客的玩具演变为企业数字化转型的核心引擎。蚂蚁数科Agentar、Dify、Coze等低代码智能体平台的崛起,证明了"可视化编排+智能体协同"模式的巨大市场潜力。 然而,这些平台大多运行在Web端,缺乏原生操作系统的深度集成能力。

HarmonyOS 6(API 23)的HMAF框架不仅支持LLM模式、工作流模式、A2A模式和OpenClaw模式四种编排方式, 更关键的是将智能体能力下沉至操作系统层,配合**悬浮导航(Float Navigation)沉浸光感(Immersive Light Effects)**特性,为PC端低代码智能体编排带来了"节点即氛围、连线即光效"的全新交互范式。

本文核心亮点

  • 节点类型光效:根据智能体节点类型(LLM节点/工具节点/条件节点/循环节点/输出节点)动态切换环境光色与脉冲节奏
  • 悬浮编排导航:底部悬浮页签替代传统工具栏,支持画布缩放、节点库切换、运行状态实时徽章
  • HMAF可视化编排引擎:基于Agent Framework Kit构建拖拽式节点编排引擎,支持四种编排模式无缝切换
  • 多窗口协作开发:主画布窗口 + 浮动属性面板 + 浮动预览窗口 + 浮动调试控制台窗口的光效联动
  • 运行状态沉浸感知:通过Intents Kit实时理解编排意图,自动调整界面光效与导航形态

二、核心特性解析与技术选型

2.1 HMAF在低代码编排中的价值

HarmonyOS 6的HMAF采用三层架构设计:底层是统一的AI系统底座,中间层是意图理解和任务编排引擎,上层是开放的智能体交互协议。 在"智流工坊"中,这种架构能够:

  • 原生智能调度:智能体不再是应用的附属品,而是系统的基础能力,支持跨应用任务编排
  • 意图即编排:通过Intents Kit将用户拖拽操作意图转化为结构化编排任务
  • 四种编排模式:LLM模式(单Agent自主决策)、工作流模式(可视化画布编排)、A2A模式(Agent间通信)、OpenClaw模式(轻量个性化)
  • 分布式智能体协同:利用鸿蒙分布式软总线,实现PC编排+手机测试+平板预览的多设备协作

2.2 沉浸光感在可视化编排中的创新应用

HarmonyOS 6的systemMaterialEffect通过模拟物理光照模型,为编排节点状态反馈带来细腻的视觉表达。在低代码编排场景中,这种材质效果能够:

  • 增强节点人格化:不同节点类型拥有专属光效人格(LLM节点智慧紫、工具节点功能蓝、条件节点决策黄、循环节点循环绿、输出节点成果橙)
  • 状态直觉感知:拖拽时的吸附蓝光、运行时的脉冲金光、调试时的数据流光、完成时的确认闪光
  • 提升编排专注度:动态环境光随画布复杂度变化,简单流程柔和、复杂流程强烈

2.3 悬浮导航的编排适配

与传统开发工具不同,低代码编排平台需要处理:

  • 高频模式切换:用户常在四种编排模式间快速切换
  • 画布信息密度平衡:既要保证导航可见,又不能遮挡编排画布
  • 实时运行徽章:编排任务运行状态需要实时徽章提示(运行中脉冲、完成确认、异常警示)

HarmonyOS 6的悬浮页签支持**强(85%)、平衡(70%)、弱(55%)**三档透明度自定义,结合PC端的自由窗口能力,可以实现"需要时出现,专注时隐退"的智能导航体验。


三、项目实战:"智流工坊"架构设计

3.1 应用场景与功能规划

面向HarmonyOS PC的低代码可视化智能体编排场景,核心功能包括:

功能模块 技术实现 沉浸光感/HMAF应用
主画布窗口 Canvas + Gesture 节点光效、连线流光、吸附高亮
悬浮编排导航 HdsTabs + systemMaterialEffect 玻璃拟态页签,模式徽章
节点库面板 Grid + Drag 节点类型色光效
属性面板 Form + HdsInput 选中节点主题色同步
LLM编排模式 HMAF LLM Mode 智慧紫光效
工作流编排模式 HMAF Workflow Mode 流程蓝光效
A2A编排模式 HMAF A2A Mode 通信青光效
OpenClaw编排模式 HMAF OpenClaw Mode 轻量粉光效
浮动预览窗口 子窗口 + WebView 运行状态光效
浮动调试控制台 子窗口 + List 日志级别颜色编码

3.2 技术架构图

复制代码
┌─────────────────────────────────────────────────────────────┐
│                    智流工坊 - 应用层                          │
├─────────────┬─────────────┬─────────────┬─────────────────────┤
│  LLM编排模式  │  工作流编排模式 │  A2A编排模式  │    OpenClaw编排模式   │
│  (LLM Mode)  │  (Workflow)  │  (A2A Mode)  │   (OpenClaw Mode)   │
├─────────────┴─────────────┴─────────────┴─────────────────────┤
│                  HMAF - 智能体框架层                          │
│         Agent Framework Kit + Intents Kit + NLU Kit          │
├─────────────────────────────────────────────────────────────┤
│                  AI系统底座 - 能力层                          │
│    MindSpore Lite(端侧) │ 鸿蒙大模型4.0(云端) │ 分布式软总线    │
├─────────────────────────────────────────────────────────────┤
│                  ArkUI - 表现层                              │
│    悬浮导航 │ 沉浸光感 │ 多窗口管理 │ 安全区扩展 │ 动画系统    │
└─────────────────────────────────────────────────────────────┘

四、环境配置与模块依赖

4.1 模块依赖配置

oh-package.json5中添加HMAF及相关Kit依赖:

json 复制代码
{
  "name": "zhiliu_workshop",
  "version": "1.0.0",
  "description": "Low-Code Visual Agent Orchestration Platform",
  "dependencies": {
    "@ohos/hmaframework": "^6.0.0",
    "@ohos/intentskit": "^6.0.0",
    "@ohos/nlukit": "^6.0.0",
    "@ohos/mindsporelite": "^6.0.0",
    "@ohos/aiengine": "^6.0.0",
    "@ohos/hds": "^6.0.0",
    "@ohos/workflowengine": "^6.0.0"
  }
}

4.2 权限声明(module.json5)

json 复制代码
{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": ["phone", "tablet", "2in1"],
    "pages": "$profile:main_pages",
    "abilities": [
      {
        "name": "EntryAbility",
        "srcEntry": "./ets/entryability/EntryAbility.ets",
        "description": "$string:EntryAbility_desc",
        "icon": "$media:layered_image",
        "label": "$string:EntryAbility_label",
        "startWindowIcon": "$media:startIcon",
        "startWindowBackground": "$color:start_window_background",
        "exported": true,
        "skills": [
          {
            "entities": ["entity.system.home"],
            "actions": ["action.system.home"]
          }
        ]
      }
    ],
    "requestPermissions": [
      {
        "name": "ohos.permission.INTERNET",
        "reason": "$string:internet_permission"
      },
      {
        "name": "ohos.permission.SYSTEM_FLOAT_WINDOW",
        "reason": "$string:float_window_permission",
        "usedScene": {
          "abilities": ["EntryAbility"],
          "when": "always"
        }
      },
      {
        "name": "ohos.permission.DISTRIBUTED_DATASYNC",
        "reason": "$string:distributed_permission"
      },
      {
        "name": "ohos.permission.AI_ENGINE_ACCESS",
        "reason": "$string:ai_engine_permission"
      }
    ]
  }
}

五、核心组件实战

5.1 窗口沉浸配置(EntryAbility.ets)

typescript 复制代码
// entry/src/main/ets/entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';

export default class EntryAbility extends UIAbility {
  private windowStage: window.WindowStage | null = null;

  onWindowStageCreate(windowStage: window.WindowStage): void {
    this.windowStage = windowStage;
    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        console.error('Failed to load content:', JSON.stringify(err));
        return;
      }
      console.info('Succeeded in loading content.');
      this.setupImmersiveWindow(windowStage);
    });
  }

  private async setupImmersiveWindow(windowStage: window.WindowStage): Promise<void> {
    try {
      const mainWindow = windowStage.getMainWindowSync();
      await mainWindow.setWindowLayoutFullScreen(true);
      await mainWindow.setWindowBackgroundColor('#00000000');
      await mainWindow.setWindowSystemBarProperties({
        statusBarColor: '#00000000',
        navigationBarColor: '#00000000',
        statusBarContentColor: '#FFFFFF',
        navigationBarContentColor: '#FFFFFF'
      });
      await mainWindow.setWindowAvoidAreaOption({
        type: window.AvoidAreaType.TYPE_SYSTEM,
        enabled: true
      });
      console.info('Immersive window setup completed');
    } catch (error) {
      console.error('Failed to setup immersive window:', (error as BusinessError).message);
    }
  }

  onWindowStageDestroy(): void {
    this.windowStage = null;
  }
}

代码亮点 :通过setWindowLayoutFullScreen(true)实现内容延伸至非安全区,配合setWindowAvoidAreaOption启用HarmonyOS 6新增的安全区避让机制,确保悬浮导航不会遮挡编排画布。

5.2 节点类型光效系统(NodeLightEffect.ets)

代码亮点 :这是本应用的核心创新组件。它将编排节点类型映射为动态光效------LLM节点智慧紫、工具节点功能蓝、条件节点决策黄、循环节点循环绿、输出节点成果橙。每个节点类型拥有专属脉冲节奏与光晕强度,通过AppStorage全局状态实现跨组件光效同步。

typescript 复制代码
// entry/src/main/ets/components/NodeLightEffect.ets
import { hmaf } from '@kit.HMAFramework';

// 节点类型枚举
export enum NodeType {
  LLM = 'llm',           // LLM节点
  TOOL = 'tool',         // 工具节点
  CONDITION = 'condition', // 条件节点
  LOOP = 'loop',         // 循环节点
  OUTPUT = 'output'      // 输出节点
}

// 节点类型色彩配置
export const NodeColors: Record<NodeType, string> = {
  [NodeType.LLM]: '#9B59B6',      // 智慧紫
  [NodeType.TOOL]: '#4A90D9',     // 功能蓝
  [NodeType.CONDITION]: '#F5A623', // 决策黄
  [NodeType.LOOP]: '#2ECC71',      // 循环绿
  [NodeType.OUTPUT]: '#E67E22'     // 成果橙
};

// 光效配置
interface LightEffectConfig {
  baseColor: string;
  pulseSpeed: number;      // 脉冲周期(ms)
  pulseIntensity: number;  // 脉冲强度(0-1)
  glowRadius: number;      // 光晕半径
  particleCount: number;   // 粒子数量
}

@Component
export struct NodeLightEffect {
  @State currentNodeType: NodeType = NodeType.LLM;
  @State nodeState: 'idle' | 'dragging' | 'running' | 'completed' | 'error' = 'idle';
  @State lightIntensity: number = 0.4;
  @State pulsePhase: number = 0;
  @State particlePositions: Array<{x: number, y: number, size: number, opacity: number}> = [];

  private pulseTimer: number = -1;
  private particleTimer: number = -1;

  aboutToAppear(): void {
    this.startPulseAnimation();
    this.startParticleAnimation();
    // 监听全局节点类型变化
    AppStorage.setOrCreate('node_type_change', (type: NodeType) => {
      this.currentNodeType = type;
      this.updateLightEffect();
    });
  }

  aboutToDisappear(): void {
    clearInterval(this.pulseTimer);
    clearInterval(this.particleTimer);
  }

  private startPulseAnimation(): void {
    this.pulseTimer = setInterval(() => {
      this.pulsePhase = (this.pulsePhase + 0.05) % (Math.PI * 2);
      this.lightIntensity = this.calculatePulseIntensity();
    }, 50);
  }

  private calculatePulseIntensity(): number {
    const baseIntensity = this.getNodeConfig().pulseIntensity;
    const variation = Math.sin(this.pulsePhase) * 0.3;
    return Math.max(0.1, Math.min(1.0, baseIntensity + variation));
  }

  private startParticleAnimation(): void {
    this.particleTimer = setInterval(() => {
      if (this.nodeState === 'running') {
        this.updateParticles();
      }
    }, 100);
  }

  private updateParticles(): void {
    const newParticles: Array<{x: number, y: number, size: number, opacity: number}> = [];
    for (let i = 0; i < this.getNodeConfig().particleCount; i++) {
      newParticles.push({
        x: Math.random() * 100,
        y: Math.random() * 100,
        size: Math.random() * 4 + 2,
        opacity: Math.random() * this.lightIntensity
      });
    }
    this.particlePositions = newParticles;
  }

  private getNodeConfig(): LightEffectConfig {
    const configs: Record<<NodeType, LightEffectConfig> = {
      [NodeType.LLM]: {
        baseColor: NodeColors[NodeType.LLM],
        pulseSpeed: 3000,
        pulseIntensity: 0.6,
        glowRadius: 100,
        particleCount: 8
      },
      [NodeType.TOOL]: {
        baseColor: NodeColors[NodeType.TOOL],
        pulseSpeed: 2500,
        pulseIntensity: 0.5,
        glowRadius: 90,
        particleCount: 6
      },
      [NodeType.CONDITION]: {
        baseColor: NodeColors[NodeType.CONDITION],
        pulseSpeed: 2000,
        pulseIntensity: 0.7,
        glowRadius: 110,
        particleCount: 10
      },
      [NodeType.LOOP]: {
        baseColor: NodeColors[NodeType.LOOP],
        pulseSpeed: 3500,
        pulseIntensity: 0.5,
        glowRadius: 95,
        particleCount: 7
      },
      [NodeType.OUTPUT]: {
        baseColor: NodeColors[NodeType.OUTPUT],
        pulseSpeed: 2800,
        pulseIntensity: 0.6,
        glowRadius: 105,
        particleCount: 9
      }
    };
    return configs[this.currentNodeType] || configs[NodeType.LLM];
  }

  private updateLightEffect(): void {
    const config = this.getNodeConfig();
    AppStorage.setOrCreate('current_node_color', config.baseColor);
    AppStorage.setOrCreate('current_node_pulse', config.pulseSpeed);
    AppStorage.setOrCreate('current_node_intensity', config.pulseIntensity);
  }

  build() {
    Stack() {
      // 主光晕层
      Column()
        .width(400)
        .height(400)
        .backgroundColor(this.getNodeConfig().baseColor)
        .blur(this.getNodeConfig().glowRadius)
        .opacity(this.lightIntensity)
        .position({ x: '50%', y: '30%' })
        .anchor('50%')
        .animation({
          duration: this.getNodeConfig().pulseSpeed,
          curve: Curve.EaseInOut,
          iterations: -1,
          playMode: PlayMode.Alternate
        })

      // 粒子层(运行状态时显示)
      if (this.nodeState === 'running') {
        ForEach(this.particlePositions, (particle: {x: number, y: number, size: number, opacity: number}, index: number) => {
          Column()
            .width(particle.size)
            .height(particle.size)
            .backgroundColor(this.getNodeConfig().baseColor)
            .borderRadius(particle.size / 2)
            .opacity(particle.opacity)
            .position({
              x: `${particle.x}%`,
              y: `${particle.y}%`
            })
            .animation({
              duration: 1000,
              curve: Curve.Linear,
              iterations: -1
            })
        })
      }

      // 状态指示器环
      Column()
        .width(200)
        .height(200)
        .backgroundColor('transparent')
        .border({
          width: 3,
          color: this.getNodeConfig().baseColor,
          style: BorderStyle.Solid
        })
        .borderRadius(100)
        .opacity(this.lightIntensity * 0.5)
        .animation({
          duration: this.getNodeConfig().pulseSpeed,
          curve: Curve.EaseInOut,
          iterations: -1,
          playMode: PlayMode.Alternate
        })
    }
    .width('100%')
    .height('100%')
  }
}

5.3 HMAF可视化编排引擎(OrchestrationEngine.ets)

代码亮点:基于HMAF Agent Framework Kit构建核心编排引擎,支持四种编排模式(LLM/工作流/A2A/OpenClaw)的无缝切换。引擎通过Intents Kit解析用户拖拽操作意图,自动创建节点连接关系,并实时监控编排运行状态。

typescript 复制代码
// entry/src/main/ets/services/OrchestrationEngine.ets
import { hmaf } from '@kit.HMAFramework';
import { intents } from '@kit.IntentsKit';
import { nlu } from '@kit.NLUKit';

// 编排节点定义
interface OrchestrationNode {
  id: string;
  type: NodeType;
  position: { x: number; y: number };
  properties: Record<string, unknown>;
  inputs: string[];
  outputs: string[];
}

// 编排连线定义
interface OrchestrationEdge {
  id: string;
  source: string;
  target: string;
  condition?: string;
}

// 编排模式
export enum OrchestrationMode {
  LLM = 'llm',
  WORKFLOW = 'workflow',
  A2A = 'a2a',
  OPENCLAW = 'openclaw'
}

export class OrchestrationEngine {
  private static instance: OrchestrationEngine;
  private nodes: Map<string, OrchestrationNode> = new Map();
  private edges: Map<string, OrchestrationEdge> = new Map();
  private hmafSession: hmaf.AgentSession | null = null;
  private intentEngine: intents.IntentEngine | null = null;
  private currentMode: OrchestrationMode = OrchestrationMode.WORKFLOW;

  private constructor() {}

  static getInstance(): OrchestrationEngine {
    if (!OrchestrationEngine.instance) {
      OrchestrationEngine.instance = new OrchestrationEngine();
    }
    return OrchestrationEngine.instance;
  }

  async initialize(): Promise<void> {
    try {
      // 初始化HMAF会话
      this.hmafSession = await hmaf.createAgentSession({
        mode: hmaf.AgentMode.MULTI_AGENT,
        maxConcurrentAgents: 10,
        enableDistributed: true
      });

      // 初始化意图引擎
      this.intentEngine = await intents.createIntentEngine({
        supportedDomains: ['orchestration', 'workflow_design', 'agent_config'],
        language: 'zh-CN'
      });

      console.info('OrchestrationEngine initialized successfully');
    } catch (error) {
      console.error('Failed to initialize OrchestrationEngine:', error);
      throw error;
    }
  }

  // 切换编排模式
  async switchMode(mode: OrchestrationMode): Promise<void> {
    this.currentMode = mode;
    
    // 根据模式更新全局光效
    const modeColors: Record<OrchestrationMode, string> = {
      [OrchestrationMode.LLM]: '#9B59B6',
      [OrchestrationMode.WORKFLOW]: '#4A90D9',
      [OrchestrationMode.A2A]: '#1ABC9C',
      [OrchestrationMode.OPENCLAW]: '#FF69B4'
    };

    AppStorage.setOrCreate('orchestration_mode_color', modeColors[mode]);
    AppStorage.setOrCreate('orchestration_mode', mode);

    console.info(`Switched to ${mode} mode`);
  }

  // 添加节点
  addNode(type: NodeType, position: { x: number; y: number }): OrchestrationNode {
    const nodeId = `node-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    
    const node: OrchestrationNode = {
      id: nodeId,
      type: type,
      position: position,
      properties: this.getDefaultProperties(type),
      inputs: [],
      outputs: []
    };

    this.nodes.set(nodeId, node);
    
    // 触发节点添加光效
    AppStorage.setOrCreate('node_added', { nodeId, type });
    
    return node;
  }

  private getDefaultProperties(type: NodeType): Record<string, unknown> {
    const defaults: Record<<NodeType, Record<string, unknown>> = {
      [NodeType.LLM]: {
        model: 'qwen-max',
        temperature: 0.7,
        maxTokens: 2048,
        systemPrompt: ''
      },
      [NodeType.TOOL]: {
        toolName: '',
        parameters: {}
      },
      [NodeType.CONDITION]: {
        condition: '',
        trueBranch: '',
        falseBranch: ''
      },
      [NodeType.LOOP]: {
        loopType: 'for',
        iterations: 10,
        condition: ''
      },
      [NodeType.OUTPUT]: {
        outputType: 'text',
        format: 'json'
      }
    };
    return defaults[type] || {};
  }

  // 添加连线
  addEdge(source: string, target: string, condition?: string): OrchestrationEdge {
    const edgeId = `edge-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    
    const edge: OrchestrationEdge = {
      id: edgeId,
      source: source,
      target: target,
      condition: condition
    };

    this.edges.set(edgeId, edge);

    // 更新节点输入输出
    const sourceNode = this.nodes.get(source);
    const targetNode = this.nodes.get(target);
    if (sourceNode) {
      sourceNode.outputs.push(target);
    }
    if (targetNode) {
      targetNode.inputs.push(source);
    }

    // 触发连线光效
    AppStorage.setOrCreate('edge_added', { edgeId, source, target });

    return edge;
  }

  // 删除节点
  removeNode(nodeId: string): void {
    const node = this.nodes.get(nodeId);
    if (!node) return;

    // 删除相关连线
    for (const [edgeId, edge] of this.edges.entries()) {
      if (edge.source === nodeId || edge.target === nodeId) {
        this.edges.delete(edgeId);
      }
    }

    this.nodes.delete(nodeId);
  }

  // 运行编排
  async runOrchestration(): Promise<<Record<string, unknown>> {
    const results: Record<string, unknown> = {};

    try {
      // 根据当前模式选择执行策略
      switch (this.currentMode) {
        case OrchestrationMode.LLM:
          return await this.runLLMMode();
        case OrchestrationMode.WORKFLOW:
          return await this.runWorkflowMode();
        case OrchestrationMode.A2A:
          return await this.runA2AMode();
        case OrchestrationMode.OPENCLAW:
          return await this.runOpenClawMode();
        default:
          throw new Error('Unknown orchestration mode');
      }
    } catch (error) {
      console.error('Orchestration execution failed:', error);
      throw error;
    }
  }

  private async runLLMMode(): Promise<<Record<string, unknown>> {
    // LLM模式:单Agent自主决策
    const llmNodes = Array.from(this.nodes.values()).filter(n => n.type === NodeType.LLM);
    
    for (const node of llmNodes) {
      const result = await this.hmafSession?.sendTask({
        targetAgent: 'llm-agent',
        taskType: 'llm_inference',
        parameters: {
          model: node.properties.model,
          prompt: node.properties.systemPrompt,
          temperature: node.properties.temperature
        },
        timeout: 30000
      });

      results[node.id] = result;
    }

    return results;
  }

  private async runWorkflowMode(): Promise<<Record<string, unknown>> {
    // 工作流模式:按拓扑排序执行
    const sortedNodes = this.topologicalSort();
    
    for (const nodeId of sortedNodes) {
      const node = this.nodes.get(nodeId);
      if (!node) continue;

      // 更新节点状态为运行中
      AppStorage.setOrCreate('node_state_update', { nodeId, state: 'running' });

      const result = await this.executeNode(node);
      results[nodeId] = result;

      // 更新节点状态为完成
      AppStorage.setOrCreate('node_state_update', { nodeId, state: 'completed' });
    }

    return results;
  }

  private async runA2AMode(): Promise<<Record<string, unknown>> {
    // A2A模式:Agent间通信
    const agents = Array.from(this.nodes.values()).map(n => ({
      id: n.id,
      type: n.type,
      capabilities: n.properties
    }));

    const result = await this.hmafSession?.sendTask({
      targetAgent: 'a2a-coordinator',
      taskType: 'agent_coordination',
      parameters: { agents },
      timeout: 60000
    });

    return { a2a_result: result };
  }

  private async runOpenClawMode(): Promise<<Record<string, unknown>> {
    // OpenClaw模式:轻量个性化
    const openClawConfig = {
      personality: '',
      tools: Array.from(this.nodes.values())
        .filter(n => n.type === NodeType.TOOL)
        .map(n => n.properties.toolName)
    };

    const result = await this.hmafSession?.sendTask({
      targetAgent: 'openclaw-agent',
      taskType: 'personalized_assistant',
      parameters: openClawConfig,
      timeout: 30000
    });

    return { openclaw_result: result };
  }

  private async executeNode(node: OrchestrationNode): Promise<unknown> {
    switch (node.type) {
      case NodeType.LLM:
        return await this.executeLLMNode(node);
      case NodeType.TOOL:
        return await this.executeToolNode(node);
      case NodeType.CONDITION:
        return await this.executeConditionNode(node);
      case NodeType.LOOP:
        return await this.executeLoopNode(node);
      case NodeType.OUTPUT:
        return await this.executeOutputNode(node);
      default:
        throw new Error(`Unknown node type: ${node.type}`);
    }
  }

  private async executeLLMNode(node: OrchestrationNode): Promise<unknown> {
    return await this.hmafSession?.sendTask({
      targetAgent: 'llm-executor',
      taskType: 'text_generation',
      parameters: {
        model: node.properties.model,
        prompt: node.properties.systemPrompt,
        temperature: node.properties.temperature,
        maxTokens: node.properties.maxTokens
      },
      timeout: 30000
    });
  }

  private async executeToolNode(node: OrchestrationNode): Promise<unknown> {
    return await this.hmafSession?.sendTask({
      targetAgent: 'tool-executor',
      taskType: 'tool_invocation',
      parameters: {
        toolName: node.properties.toolName,
        parameters: node.properties.parameters
      },
      timeout: 20000
    });
  }

  private async executeConditionNode(node: OrchestrationNode): Promise<unknown> {
    const condition = node.properties.condition as string;
    // 评估条件表达式
    const result = await this.hmafSession?.sendTask({
      targetAgent: 'condition-evaluator',
      taskType: 'condition_evaluation',
      parameters: { condition },
      timeout: 10000
    });

    return { condition: condition, result: result };
  }

  private async executeLoopNode(node: OrchestrationNode): Promise<unknown> {
    const iterations = node.properties.iterations as number;
    const results = [];

    for (let i = 0; i < iterations; i++) {
      const result = await this.hmafSession?.sendTask({
        targetAgent: 'loop-executor',
        taskType: 'loop_iteration',
        parameters: {
          iteration: i,
          condition: node.properties.condition
        },
        timeout: 15000
      });
      results.push(result);
    }

    return { iterations, results };
  }

  private async executeOutputNode(node: OrchestrationNode): Promise<unknown> {
    return {
      outputType: node.properties.outputType,
      format: node.properties.format,
      timestamp: Date.now()
    };
  }

  private topologicalSort(): string[] {
    const visited = new Set<string>();
    const result: string[] = [];

    const visit = (nodeId: string) => {
      if (visited.has(nodeId)) return;
      visited.add(nodeId);

      const node = this.nodes.get(nodeId);
      if (node) {
        for (const input of node.inputs) {
          visit(input);
        }
      }

      result.push(nodeId);
    };

    for (const nodeId of this.nodes.keys()) {
      visit(nodeId);
    }

    return result;
  }

  getNodes(): OrchestrationNode[] {
    return Array.from(this.nodes.values());
  }

  getEdges(): OrchestrationEdge[] {
    return Array.from(this.edges.values());
  }

  getCurrentMode(): OrchestrationMode {
    return this.currentMode;
  }
}

5.4 悬浮编排导航(OrchestrationFloatNavigation.ets)

代码亮点:底部悬浮导航栏不仅承载页面切换功能,更重要的是实时显示编排模式和运行状态。每个导航项配备模式徽章------LLM模式智慧紫、工作流模式功能蓝、A2A模式通信青、OpenClaw模式轻量粉。支持长按展开透明度调节面板。

typescript 复制代码
// entry/src/main/ets/components/OrchestrationFloatNavigation.ets
import { window } from '@kit.ArkUI';
import { NodeType, NodeColors } from './NodeLightEffect';
import { OrchestrationMode } from '../services/OrchestrationEngine';

// 导航项配置
interface OrchestrationNavItem {
  id: string;
  icon: Resource;
  label: string;
  page: string;
  mode?: OrchestrationMode;
}

@Component
export struct OrchestrationFloatNavigation {
  @State currentIndex: number = 0;
  @State navTransparency: number = 0.70;
  @State isExpanded: boolean = false;
  @State bottomAvoidHeight: number = 0;
  @State currentMode: OrchestrationMode = OrchestrationMode.WORKFLOW;
  @State isRunning: boolean = false;

  private navItems: OrchestrationNavItem[] = [
    { id: 'canvas', icon: $r('app.media.ic_canvas'), label: '画布', page: 'CanvasPage' },
    { id: 'llm', icon: $r('app.media.ic_llm'), label: 'LLM', page: 'LLMPage', mode: OrchestrationMode.LLM },
    { id: 'workflow', icon: $r('app.media.ic_workflow'), label: '工作流', page: 'WorkflowPage', mode: OrchestrationMode.WORKFLOW },
    { id: 'a2a', icon: $r('app.media.ic_a2a'), label: 'A2A', page: 'A2APage', mode: OrchestrationMode.A2A },
    { id: 'openclaw', icon: $r('app.media.ic_openclaw'), label: 'OpenClaw', page: 'OpenClawPage', mode: OrchestrationMode.OPENCLAW }
  ];

  aboutToAppear(): void {
    this.getBottomAvoidArea();
    // 监听编排模式变化
    AppStorage.setOrCreate('orchestration_mode', (mode: OrchestrationMode) => {
      this.currentMode = mode;
    });
    // 监听运行状态变化
    AppStorage.setOrCreate('orchestration_running', (running: boolean) => {
      this.isRunning = running;
    });
  }

  private async getBottomAvoidArea(): Promise<void> {
    try {
      const mainWindow = await window.getLastWindow();
      const avoidArea = mainWindow.getWindowAvoidArea(window.AvoidAreaType.TYPE_NAVIGATION_INDICATOR);
      this.bottomAvoidHeight = avoidArea.bottomRect.height;
    } catch (error) {
      console.error('Failed to get avoid area:', error);
    }
  }

  private getModeColor(mode?: OrchestrationMode): string {
    const colors: Record<OrchestrationMode, string> = {
      [OrchestrationMode.LLM]: '#9B59B6',
      [OrchestrationMode.WORKFLOW]: '#4A90D9',
      [OrchestrationMode.A2A]: '#1ABC9C',
      [OrchestrationMode.OPENCLAW]: '#FF69B4'
    };
    return mode ? colors[mode] : '#666666';
  }

  private getModeBadgeAnimation(): object {
    if (this.isRunning) {
      return {
        duration: 1000,
        curve: Curve.Linear,
        iterations: -1
      };
    }
    return { duration: 0 };
  }

  build() {
    Stack({ alignContent: Alignment.Bottom }) {
      // 内容层
      Column() {
        this.contentBuilder()
      }
      .padding({ bottom: this.bottomAvoidHeight + 80 })

      // 悬浮导航栏
      Column() {
        Stack() {
          // 玻璃拟态背景
          Column()
            .width('100%')
            .height('100%')
            .backgroundBlurStyle(BlurStyle.REGULAR)
            .opacity(this.navTransparency)
            .backdropFilter($r('sys.blur.20'))

          // 渐变光效层
          Column()
            .width('100%')
            .height('100%')
            .linearGradient({
              direction: GradientDirection.Top,
              colors: [
                ['rgba(255,255,255,0.15)', 0.0],
                ['rgba(255,255,255,0.05)', 1.0]
              ]
            })
        }
        .width('100%')
        .height('100%')
        .borderRadius(24)
        .shadow({
          radius: 20,
          color: 'rgba(0,0,0,0.2)',
          offsetX: 0,
          offsetY: -4
        })

        // 导航项
        Row() {
          ForEach(this.navItems, (item: OrchestrationNavItem, index: number) => {
            Column() {
              Stack() {
                Image(item.icon)
                  .width(24)
                  .height(24)
                  .fillColor(this.currentIndex === index ? this.getModeColor(item.mode) : '#666666')

                // 运行状态徽章
                if (item.mode === this.currentMode && this.isRunning) {
                  Column()
                    .width(10)
                    .height(10)
                    .backgroundColor(this.getModeColor(item.mode))
                    .borderRadius(5)
                    .position({ x: 18, y: -4 })
                    .shadow({
                      radius: 6,
                      color: this.getModeColor(item.mode),
                      offsetX: 0,
                      offsetY: 0
                    })
                    .animation(this.getModeBadgeAnimation())
                }

                // 模式指示器
                if (item.mode === this.currentMode) {
                  Column()
                    .width(6)
                    .height(6)
                    .backgroundColor(this.getModeColor(item.mode))
                    .borderRadius(3)
                    .position({ x: 20, y: 20 })
                }
              }
              .width(40)
              .height(40)

              Text(item.label)
                .fontSize(11)
                .fontColor(this.currentIndex === index ? this.getModeColor(item.mode) : '#999999')
                .margin({ top: 4 })
            }
            .layoutWeight(1)
            .onClick(() => {
              this.currentIndex = index;
              if (item.mode) {
                this.switchMode(item.mode);
              }
              this.triggerHapticFeedback();
            })
          })
        }
        .width('100%')
        .height(80)
        .padding({ left: 16, right: 16 })
        .justifyContent(FlexAlign.SpaceAround)

        // 透明度调节
        if (this.isExpanded) {
          Row() {
            Text('透明度')
              .fontSize(12)
              .fontColor('#666666')
              .margin({ right: 8 })

            Slider({
              value: this.navTransparency * 100,
              min: 55,
              max: 85,
              step: 15,
              style: SliderStyle.InSet
            })
              .width(120)
              .onChange((value: number) => {
                this.navTransparency = value / 100;
              })

            Text(`${Math.round(this.navTransparency * 100)}%`)
              .fontSize(12)
              .fontColor('#666666')
              .margin({ left: 8 })
          }
          .width('100%')
          .height(40)
          .justifyContent(FlexAlign.Center)
          .backgroundColor('rgba(255,255,255,0.5)')
          .borderRadius({ topLeft: 12, topRight: 12 })
        }
      }
      .width('92%')
      .height(this.isExpanded ? 120 : 80)
      .margin({ bottom: this.bottomAvoidHeight + 12, left: '4%', right: '4%' })
      .animation({
        duration: 300,
        curve: Curve.Spring,
        iterations: 1
      })
      .gesture(
        LongPressGesture({ duration: 500 })
          .onAction(() => {
            this.isExpanded = !this.isExpanded;
          })
      )
    }
    .width('100%')
    .height('100%')
  }

  @BuilderParam contentBuilder: () => void = this.defaultContentBuilder;

  @Builder
  defaultContentBuilder(): void {
    Column() {
      Text('内容区域')
        .fontSize(16)
        .fontColor('#999999')
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

  private async switchMode(mode: OrchestrationMode): Promise<void> {
    const engine = await import('../services/OrchestrationEngine').then(m => m.OrchestrationEngine.getInstance());
    await engine.switchMode(mode);
  }

  private triggerHapticFeedback(): void {
    try {
      import('@kit.SensorServiceKit').then(sensor => {
        sensor.vibrator.startVibration({
          type: 'time',
          duration: 50
        }, { id: 0 });
      });
    } catch (error) {
      console.error('Haptic feedback failed:', error);
    }
  }
}

5.5 可视化编排画布(OrchestrationCanvas.ets)

代码亮点:实现具有节点光效和连线流光的可视化编排画布。支持拖拽创建节点、连线连接节点、节点属性编辑。节点根据类型显示专属色彩边框,运行时光效脉冲。

typescript 复制代码
// entry/src/main/ets/components/OrchestrationCanvas.ets
import { NodeType, NodeColors } from './NodeLightEffect';
import { OrchestrationEngine } from '../services/OrchestrationEngine';

interface CanvasNode {
  id: string;
  type: NodeType;
  x: number;
  y: number;
  width: number;
  height: number;
  isSelected: boolean;
  isRunning: boolean;
}

interface CanvasEdge {
  id: string;
  source: string;
  target: string;
  path: string;
}

@Component
export struct OrchestrationCanvas {
  @State nodes: CanvasNode[] = [];
  @State edges: CanvasEdge[] = [];
  @State selectedNodeId: string = '';
  @State isDragging: boolean = false;
  @State dragOffset: { x: number; y: number } = { x: 0, y: 0 };
  @State scale: number = 1.0;
  @State currentModeColor: string = '#4A90D9';

  private engine: OrchestrationEngine = OrchestrationEngine.getInstance();
  private canvasContext: CanvasRenderingContext2D | null = null;

  aboutToAppear(): void {
    // 监听模式颜色变化
    AppStorage.setOrCreate('orchestration_mode_color', (color: string) => {
      this.currentModeColor = color;
    });
    // 监听节点状态变化
    AppStorage.setOrCreate('node_state_update', (update: {nodeId: string, state: string}) => {
      const node = this.nodes.find(n => n.id === update.nodeId);
      if (node) {
        node.isRunning = update.state === 'running';
      }
    });
  }

  private getNodeColor(type: NodeType): string {
    return NodeColors[type] || '#666666';
  }

  private getNodeAnimation(node: CanvasNode): object {
    if (node.isRunning) {
      return {
        duration: 1000,
        curve: Curve.Linear,
        iterations: -1
      };
    }
    if (node.isSelected) {
      return {
        duration: 1500,
        curve: Curve.EaseInOut,
        iterations: -1,
        playMode: PlayMode.Alternate
      };
    }
    return { duration: 0 };
  }

  build() {
    Stack() {
      // 画布背景
      Column()
        .width('100%')
        .height('100%')
        .backgroundColor('#0a0a0f')
        .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])

      // 网格背景
      Canvas(this.canvasContext)
        .width('100%')
        .height('100%')
        .onReady(() => {
          this.drawGrid();
        })

      // 节点层
      ForEach(this.nodes, (node: CanvasNode) => {
        Stack() {
          // 节点光效背景
          Column()
            .width(node.width + 20)
            .height(node.height + 20)
            .backgroundColor(this.getNodeColor(node.type))
            .blur(20)
            .opacity(node.isRunning ? 0.6 : 0.3)
            .position({ x: '50%', y: '50%' })
            .anchor('50%')
            .animation(this.getNodeAnimation(node))

          // 节点主体
          Column() {
            // 节点标题栏
            Row() {
              Text(this.getNodeIcon(node.type))
                .fontSize(16)
                .margin({ right: 8 })

              Text(node.type.toUpperCase())
                .fontSize(14)
                .fontColor('#FFFFFF')
                .fontWeight(FontWeight.Bold)
            }
            .width('100%')
            .padding(12)
            .backgroundColor(`${this.getNodeColor(node.type)}80`)
            .borderRadius({ topLeft: 8, topRight: 8 })

            // 节点内容
            Column() {
              Text(`ID: ${node.id.substr(0, 8)}...`)
                .fontSize(12)
                .fontColor('#AAAAAA')
                .margin({ bottom: 8 })

              if (node.isRunning) {
                Text('运行中...')
                  .fontSize(12)
                  .fontColor(this.getNodeColor(node.type))
                  .animation({
                    duration: 1000,
                    curve: Curve.Linear,
                    iterations: -1
                  })
              }
            }
            .width('100%')
            .padding(12)
          }
          .width(node.width)
          .height(node.height)
          .backgroundColor('rgba(30,30,50,0.9)')
          .borderRadius(8)
          .border({
            width: node.isSelected ? 3 : 2,
            color: node.isSelected ? this.getNodeColor(node.type) : `${this.getNodeColor(node.type)}60`,
            style: BorderStyle.Solid
          })
          .shadow({
            radius: node.isSelected ? 20 : 10,
            color: `${this.getNodeColor(node.type)}${node.isSelected ? '60' : '30'}`,
            offsetX: 0,
            offsetY: 0
          })
          .position({ x: node.x, y: node.y })
          .gesture(
            GestureGroup(GestureMode.Sequence,
              LongPressGesture({ duration: 500 })
                .onAction(() => {
                  this.selectedNodeId = node.id;
                  node.isSelected = true;
                }),
              PanGesture()
                .onActionStart((event: GestureEvent) => {
                  this.isDragging = true;
                  this.dragOffset = { x: event.offsetX, y: event.offsetY };
                })
                .onActionUpdate((event: GestureEvent) => {
                  if (this.isDragging) {
                    node.x = event.offsetX - this.dragOffset.x;
                    node.y = event.offsetY - this.dragOffset.y;
                  }
                })
                .onActionEnd(() => {
                  this.isDragging = false;
                })
            )
          )
        }
      })

      // 连线层
      Canvas(this.canvasContext)
        .width('100%')
        .height('100%')
        .onReady(() => {
          this.drawEdges();
        })

      // 缩放控制
      Row() {
        Button() {
          Text('+')
            .fontSize(20)
            .fontColor('#FFFFFF')
        }
        .type(ButtonType.Circle)
        .backgroundColor('rgba(255,255,255,0.2)')
        .width(40)
        .height(40)
        .onClick(() => {
          this.scale = Math.min(2.0, this.scale + 0.1);
        })

        Button() {
          Text('-')
            .fontSize(20)
            .fontColor('#FFFFFF')
        }
        .type(ButtonType.Circle)
        .backgroundColor('rgba(255,255,255,0.2)')
        .width(40)
        .height(40)
        .margin({ left: 8 })
        .onClick(() => {
          this.scale = Math.max(0.5, this.scale - 0.1);
        })
      }
      .position({ x: 20, y: 100 })
    }
    .width('100%')
    .height('100%')
  }

  private getNodeIcon(type: NodeType): string {
    const icons: Record<<NodeType, string> = {
      [NodeType.LLM]: '🧠',
      [NodeType.TOOL]: '🔧',
      [NodeType.CONDITION]: '❓',
      [NodeType.LOOP]: '🔄',
      [NodeType.OUTPUT]: '📤'
    };
    return icons[type] || '📦';
  }

  private drawGrid(): void {
    // 绘制网格背景
    if (!this.canvasContext) return;
    
    const ctx = this.canvasContext;
    const width = ctx.canvas.width;
    const height = ctx.canvas.height;
    const gridSize = 20 * this.scale;

    ctx.strokeStyle = 'rgba(255,255,255,0.05)';
    ctx.lineWidth = 1;

    for (let x = 0; x < width; x += gridSize) {
      ctx.beginPath();
      ctx.moveTo(x, 0);
      ctx.lineTo(x, height);
      ctx.stroke();
    }

    for (let y = 0; y < height; y += gridSize) {
      ctx.beginPath();
      ctx.moveTo(0, y);
      ctx.lineTo(width, y);
      ctx.stroke();
    }
  }

  private drawEdges(): void {
    // 绘制连线
    if (!this.canvasContext) return;

    const ctx = this.canvasContext;
    
    for (const edge of this.edges) {
      const sourceNode = this.nodes.find(n => n.id === edge.source);
      const targetNode = this.nodes.find(n => n.id === edge.target);
      
      if (!sourceNode || !targetNode) continue;

      const startX = sourceNode.x + sourceNode.width / 2;
      const startY = sourceNode.y + sourceNode.height;
      const endX = targetNode.x + targetNode.width / 2;
      const endY = targetNode.y;

      // 绘制流光连线
      const gradient = ctx.createLinearGradient(startX, startY, endX, endY);
      gradient.addColorStop(0, `${this.getNodeColor(sourceNode.type)}80`);
      gradient.addColorStop(0.5, this.currentModeColor);
      gradient.addColorStop(1, `${this.getNodeColor(targetNode.type)}80`);

      ctx.strokeStyle = gradient;
      ctx.lineWidth = 2;
      ctx.setLineDash([5, 5]);
      
      ctx.beginPath();
      ctx.moveTo(startX, startY);
      ctx.bezierCurveTo(
        startX, startY + 50,
        endX, endY - 50,
        endX, endY
      );
      ctx.stroke();

      // 绘制流动粒子
      const particleX = startX + (endX - startX) * 0.5;
      const particleY = startY + (endY - startY) * 0.5;
      
      ctx.fillStyle = this.currentModeColor;
      ctx.beginPath();
      ctx.arc(particleX, particleY, 3, 0, Math.PI * 2);
      ctx.fill();
    }
  }

  // 添加节点
  addNode(type: NodeType, x: number, y: number): void {
    const nodeId = `node-${Date.now()}`;
    const newNode: CanvasNode = {
      id: nodeId,
      type: type,
      x: x,
      y: y,
      width: 180,
      height: 120,
      isSelected: false,
      isRunning: false
    };
    this.nodes.push(newNode);
    
    // 同步到引擎
    this.engine.addNode(type, { x, y });
  }

  // 添加连线
  addEdge(sourceId: string, targetId: string): void {
    const edgeId = `edge-${Date.now()}`;
    const newEdge: CanvasEdge = {
      id: edgeId,
      source: sourceId,
      target: targetId,
      path: ''
    };
    this.edges.push(newEdge);
    
    // 同步到引擎
    this.engine.addEdge(sourceId, targetId);
  }
}

5.6 浮动属性面板窗口(PropertyPanelWindow.ets)

代码亮点 :实现可拖拽的浮动属性面板,支持节点属性编辑、模式切换、运行配置。窗口激活时边缘发光增强,失活时自动降低光效强度,通过WindowManager与主窗口光效联动。

typescript 复制代码
// entry/src/main/ets/windows/PropertyPanelWindow.ets
import { window } from '@kit.ArkUI';
import { NodeType, NodeColors } from '../components/NodeLightEffect';
import { OrchestrationMode } from '../services/OrchestrationEngine';

@Component
export struct PropertyPanelWindow {
  @State isActive: boolean = false;
  @State selectedNode: {id: string, type: NodeType, properties: Record<string, unknown>} | null = null;
  @State windowLightColor: string = '#4A90D9';
  @State lightIntensity: number = 0.6;
  @State currentMode: OrchestrationMode = OrchestrationMode.WORKFLOW;

  private mainWindow: window.Window | null = null;

  aboutToAppear(): void {
    this.setupWindow();
    // 监听主窗口光效变化
    AppStorage.setOrCreate('orchestration_mode_color', (color: string) => {
      this.windowLightColor = color;
    });
    // 监听选中节点变化
    AppStorage.setOrCreate('selected_node', (node: {id: string, type: NodeType, properties: Record<string, unknown>}) => {
      this.selectedNode = node;
    });
  }

  private async setupWindow(): Promise<void> {
    try {
      this.mainWindow = await window.getLastWindow();
      await this.mainWindow.setWindowBackgroundColor('#00000000');
      
      // 设置窗口为浮动样式
      await this.mainWindow.setWindowDecorVisible(false);
      await this.mainWindow.resize(350, 600);
      
      // 监听窗口焦点变化
      this.mainWindow.on('windowFocusChange', (isFocused: boolean) => {
        this.isActive = isFocused;
        this.lightIntensity = isFocused ? 0.8 : 0.3;
      });
    } catch (error) {
      console.error('Failed to setup property panel window:', error);
    }
  }

  build() {
    Stack() {
      // 窗口边框光效
      Column()
        .width('100%')
        .height('100%')
        .backgroundColor('transparent')
        .border({
          width: 2,
          color: `${this.windowLightColor}${this.isActive ? 'FF' : '40'}`,
          style: BorderStyle.Solid
        })
        .borderRadius(16)
        .animation({
          duration: 300,
          curve: Curve.EaseInOut
        })

      // 内容层
      Column() {
        // 标题栏
        Row() {
          Text('⚙️ 属性面板')
            .fontSize(16)
            .fontColor('#FFFFFF')
            .fontWeight(FontWeight.Bold)

          if (this.selectedNode) {
            Text(this.selectedNode.type.toUpperCase())
              .fontSize(12)
              .fontColor('#FFFFFF')
              .backgroundColor(NodeColors[this.selectedNode.type])
              .borderRadius(8)
              .padding({ left: 8, right: 8, top: 4, bottom: 4 })
          }
        }
        .width('100%')
        .justifyContent(FlexAlign.SpaceBetween)
        .padding(16)

        // 节点属性编辑
        if (this.selectedNode) {
          Column() {
            Text(`节点ID: ${this.selectedNode.id}`)
              .fontSize(14)
              .fontColor('#FFFFFF')
              .margin({ bottom: 12 })

            // LLM节点属性
            if (this.selectedNode.type === NodeType.LLM) {
              this.buildLLMProperties()
            }

            // 工具节点属性
            if (this.selectedNode.type === NodeType.TOOL) {
              this.buildToolProperties()
            }

            // 条件节点属性
            if (this.selectedNode.type === NodeType.CONDITION) {
              this.buildConditionProperties()
            }
          }
          .width('100%')
          .padding(16)
          .backgroundColor('rgba(255,255,255,0.05)')
          .borderRadius(12)
          .margin({ bottom: 16 })
        }

        // 模式切换
        Column() {
          Text('编排模式')
            .fontSize(14)
            .fontColor('#FFFFFF')
            .fontWeight(FontWeight.Bold)
            .margin({ bottom: 12 })

          Row() {
            ForEach([OrchestrationMode.LLM, OrchestrationMode.WORKFLOW, OrchestrationMode.A2A, OrchestrationMode.OPENCLAW], (mode: OrchestrationMode) => {
              Button() {
                Text(mode.toUpperCase())
                  .fontSize(11)
                  .fontColor(this.currentMode === mode ? '#FFFFFF' : '#888888')
              }
              .type(ButtonType.Capsule)
              .backgroundColor(this.currentMode === mode ? this.windowLightColor : 'rgba(255,255,255,0.1)')
              .height(28)
              .margin({ left: 4, right: 4 })
              .onClick(() => {
                this.currentMode = mode;
                AppStorage.setOrCreate('orchestration_mode', mode);
              })
            })
          }
          .width('100%')
          .justifyContent(FlexAlign.SpaceAround)
        }
        .width('100%')
        .padding(16)
        .backgroundColor('rgba(255,255,255,0.05)')
        .borderRadius(12)
      }
      .width('100%')
      .height('100%')
      .padding(2) // 为边框光效留出空间
    }
    .width('100%')
    .height('100%')
    .backgroundColor('rgba(15,15,35,0.95)')
    .borderRadius(16)
    .shadow({
      radius: 30,
      color: `${this.windowLightColor}${this.isActive ? '40' : '15'}`,
      offsetX: 0,
      offsetY: 0
    })
    .animation({
      duration: 300,
      curve: Curve.EaseInOut
    })
  }

  @Builder
  buildLLMProperties(): void {
    Column() {
      Text('模型配置')
        .fontSize(13)
        .fontColor('#AAAAAA')
        .margin({ bottom: 8 })

      TextInput({ placeholder: '模型名称', text: 'qwen-max' })
        .width('100%')
        .height(36)
        .backgroundColor('rgba(255,255,255,0.1)')
        .fontColor('#FFFFFF')
        .borderRadius(8)
        .margin({ bottom: 8 })

      Text('Temperature')
        .fontSize(12)
        .fontColor('#AAAAAA')

      Slider({ value: 0.7, min: 0, max: 1, step: 0.1 })
        .width('100%')
        .margin({ bottom: 8 })

      Text('System Prompt')
        .fontSize(12)
        .fontColor('#AAAAAA')

      TextArea({ placeholder: '输入系统提示词...' })
        .width('100%')
        .height(80)
        .backgroundColor('rgba(255,255,255,0.1)')
        .fontColor('#FFFFFF')
        .borderRadius(8)
    }
    .width('100%')
  }

  @Builder
  buildToolProperties(): void {
    Column() {
      Text('工具配置')
        .fontSize(13)
        .fontColor('#AAAAAA')
        .margin({ bottom: 8 })

      TextInput({ placeholder: '工具名称', text: '' })
        .width('100%')
        .height(36)
        .backgroundColor('rgba(255,255,255,0.1)')
        .fontColor('#FFFFFF')
        .borderRadius(8)
        .margin({ bottom: 8 })

      Text('参数配置')
        .fontSize(12)
        .fontColor('#AAAAAA')

      TextArea({ placeholder: '输入JSON格式参数...' })
        .width('100%')
        .height(80)
        .backgroundColor('rgba(255,255,255,0.1)')
        .fontColor('#FFFFFF')
        .borderRadius(8)
    }
    .width('100%')
  }

  @Builder
  buildConditionProperties(): void {
    Column() {
      Text('条件配置')
        .fontSize(13)
        .fontColor('#AAAAAA')
        .margin({ bottom: 8 })

      TextInput({ placeholder: '条件表达式', text: '' })
        .width('100%')
        .height(36)
        .backgroundColor('rgba(255,255,255,0.1)')
        .fontColor('#FFFFFF')
        .borderRadius(8)
        .margin({ bottom: 8 })

      Text('True分支')
        .fontSize(12)
        .fontColor('#AAAAAA')

      TextInput({ placeholder: 'True分支目标节点', text: '' })
        .width('100%')
        .height(36)
        .backgroundColor('rgba(255,255,255,0.1)')
        .fontColor('#FFFFFF')
        .borderRadius(8)
        .margin({ bottom: 8 })

      Text('False分支')
        .fontSize(12)
        .fontColor('#AAAAAA')

      TextInput({ placeholder: 'False分支目标节点', text: '' })
        .width('100%')
        .height(36)
        .backgroundColor('rgba(255,255,255,0.1)')
        .fontColor('#FFFFFF')
        .borderRadius(8)
    }
    .width('100%')
  }
}

5.7 多窗口光效同步管理器(WindowLightSync.ets)

代码亮点:管理主窗口与浮动属性面板窗口、预览窗口、调试控制台窗口之间的光效联动。当编排模式变化时,所有窗口同步切换主题色;当窗口焦点变化时,自动调整光效强度,形成层次分明的视觉体验。

typescript 复制代码
// entry/src/main/ets/managers/WindowLightSync.ets
import { window } from '@kit.ArkUI';
import { OrchestrationMode } from '../services/OrchestrationEngine';

// 窗口类型
export enum WindowType {
  MAIN = 'main',
  PROPERTY_PANEL = 'property_panel',
  PREVIEW = 'preview',
  DEBUG_CONSOLE = 'debug_console'
}

// 光效主题
export interface LightTheme {
  primaryColor: string;
  secondaryColor: string;
  intensity: number;
  pulseSpeed: number;
  glowRadius: number;
}

export class WindowLightSync {
  private static instance: WindowLightSync;
  private windows: Map<<WindowType, window.Window> = new Map();
  private currentTheme: LightTheme = {
    primaryColor: '#4A90D9',
    secondaryColor: '#6BB6FF',
    intensity: 0.6,
    pulseSpeed: 2000,
    glowRadius: 100
  };
  private focusWindow: WindowType = WindowType.MAIN;

  private constructor() {}

  static getInstance(): WindowLightSync {
    if (!WindowLightSync.instance) {
      WindowLightSync.instance = new WindowLightSync();
    }
    return WindowLightSync.instance;
  }

  registerWindow(type: WindowType, win: window.Window): void {
    this.windows.set(type, win);
    
    // 监听窗口焦点
    win.on('windowFocusChange', (isFocused: boolean) => {
      if (isFocused) {
        this.focusWindow = type;
        this.updateFocusLightEffect();
      }
    });
  }

  // 同步所有窗口光效
  async syncLightEffect(theme: LightTheme): Promise<void> {
    this.currentTheme = theme;
    
    for (const [type, win] of this.windows.entries()) {
      try {
        const isFocused = type === this.focusWindow;
        const intensity = isFocused ? theme.intensity : theme.intensity * 0.4;
        
        // 设置窗口背景光效
        await win.setWindowBackgroundColor(`#00000000`);
        
        // 同步到AppStorage供各窗口组件读取
        AppStorage.setOrCreate(`window_${type}_color`, theme.primaryColor);
        AppStorage.setOrCreate(`window_${type}_intensity`, intensity);
        AppStorage.setOrCreate(`window_${type}_focused`, isFocused);
        
      } catch (error) {
        console.error(`Failed to sync light effect for ${type}:`, error);
      }
    }
  }

  // 根据编排模式更新主题
  updateThemeByMode(mode: OrchestrationMode): void {
    const themes: Record<OrchestrationMode, LightTheme> = {
      [OrchestrationMode.LLM]: {
        primaryColor: '#9B59B6',
        secondaryColor: '#C39BD3',
        intensity: 0.6,
        pulseSpeed: 3000,
        glowRadius: 100
      },
      [OrchestrationMode.WORKFLOW]: {
        primaryColor: '#4A90D9',
        secondaryColor: '#6BB6FF',
        intensity: 0.6,
        pulseSpeed: 2500,
        glowRadius: 100
      },
      [OrchestrationMode.A2A]: {
        primaryColor: '#1ABC9C',
        secondaryColor: '#76D7C4',
        intensity: 0.6,
        pulseSpeed: 2800,
        glowRadius: 100
      },
      [OrchestrationMode.OPENCLAW]: {
        primaryColor: '#FF69B4',
        secondaryColor: '#FFB6C1',
        intensity: 0.6,
        pulseSpeed: 3200,
        glowRadius: 100
      }
    };

    const theme = themes[mode] || themes[OrchestrationMode.WORKFLOW];
    this.syncLightEffect(theme);
  }

  private updateFocusLightEffect(): void {
    // 重新应用当前主题,根据新的焦点窗口调整强度
    this.syncLightEffect(this.currentTheme);
  }

  // 创建浮动窗口
  async createFloatWindow(type: WindowType, width: number, height: number, x: number, y: number): Promise<<window.Window> {
    try {
      const floatWindow = await window.createWindow({
        name: type,
        windowType: window.WindowType.TYPE_FLOAT,
        ctx: getContext()
      });

      await floatWindow.moveWindowTo(x, y);
      await floatWindow.resize(width, height);
      await floatWindow.setWindowBackgroundColor('#00000000');
      await floatWindow.showWindow();

      this.registerWindow(type, floatWindow);
      return floatWindow;
    } catch (error) {
      console.error(`Failed to create float window ${type}:`, error);
      throw error;
    }
  }
}

5.8 主页面集成(Index.ets)

typescript 复制代码
// entry/src/main/ets/pages/Index.ets
import { OrchestrationCanvas } from '../components/OrchestrationCanvas';
import { OrchestrationEngine, OrchestrationMode } from '../services/OrchestrationEngine';
import { WindowLightSync, WindowType } from '../managers/WindowLightSync';
import { PropertyPanelWindow } from '../windows/PropertyPanelWindow';

@Entry
@Component
struct Index {
  private engine: OrchestrationEngine = OrchestrationEngine.getInstance();
  private lightSync: WindowLightSync = WindowLightSync.getInstance();

  aboutToAppear(): void {
    this.initializeWindows();
    this.initializeEngine();
  }

  private async initializeEngine(): Promise<void> {
    await this.engine.initialize();
    await this.engine.switchMode(OrchestrationMode.WORKFLOW);
  }

  private async initializeWindows(): Promise<void> {
    try {
      const mainWindow = await window.getLastWindow();
      this.lightSync.registerWindow(WindowType.MAIN, mainWindow);

      // 创建浮动属性面板(PC端特有)
      if (deviceInfo.deviceType === '2in1' || deviceInfo.deviceType === 'tablet') {
        await this.lightSync.createFloatWindow(
          WindowType.PROPERTY_PANEL,
          350, 600,
          100, 100
        );
      }
    } catch (error) {
      console.error('Failed to initialize windows:', error);
    }
  }

  build() {
    Stack() {
      // 动态环境光背景
      Column() {
        Column()
          .width(400)
          .height(400)
          .backgroundColor(AppStorage.get<string>('orchestration_mode_color') || '#4A90D9')
          .blur(150)
          .opacity(0.4)
          .position({ x: '50%', y: '30%' })
          .anchor('50%')
          .animation({
            duration: 3000,
            curve: Curve.EaseInOut,
            iterations: -1,
            playMode: PlayMode.Alternate
          })
      }
      .width('100%')
      .height('100%')
      .backgroundColor('#0a0a0f')

      // 内容层
      Column() {
        // 编排画布
        OrchestrationCanvas()
          .layoutWeight(1)
      }
      .width('100%')
      .height('100%')
    }
    .width('100%')
    .height('100%')
  }
}

六、关键技术总结

6.1 HMAF可视化编排开发清单

技术点 API/方法 应用场景
智能体会话创建 hmaf.createAgentSession({ mode: MULTI_AGENT }) 多智能体协作编排
意图解析 intents.createIntentEngine({ supportedDomains }) 用户拖拽意图理解
任务分发 hmafSession.sendTask({ targetAgent, taskType }) 智能体间编排任务调度
状态监听 AppStorage全局状态回调 跨组件编排状态同步
分布式协同 enableDistributed: true 多设备编排协作
四种编排模式 LLM/Workflow/A2A/OpenClaw 不同场景模式切换

6.2 沉浸光感实现清单

技术点 API/方法 应用场景
系统材质效果 systemMaterialEffect: SystemMaterialEffect.IMMERSIVE HdsNavigation标题栏
背景模糊 backgroundBlurStyle(BlurStyle.REGULAR) 悬浮导航玻璃拟态
背景滤镜 backdropFilter($r('sys.blur.20')) 精细模糊控制
安全区扩展 expandSafeArea([SafeAreaType.SYSTEM], [...]) 全屏沉浸布局
窗口沉浸 setWindowLayoutFullScreen(true) 无边框模式
光效动画 animation({ duration, iterations: -1 }) 呼吸灯背景
动态透明度 backgroundOpacity 焦点感知降级

6.3 节点类型光效映射

节点类型 光效颜色 脉冲速度 光晕半径 视觉语义
LLM节点 #9B59B6 3000ms 100px 智慧紫光,AI推理
工具节点 #4A90D9 2500ms 90px 功能蓝光,工具调用
条件节点 #F5A623 2000ms 110px 决策黄光,逻辑判断
循环节点 #2ECC71 3500ms 95px 循环绿光,迭代执行
输出节点 #E67E22 2800ms 105px 成果橙光,结果输出

6.4 编排模式光效映射

编排模式 光效颜色 脉冲速度 光晕半径 视觉语义
LLM模式 #9B59B6 3000ms 100px 智慧紫光,自主决策
工作流模式 #4A90D9 2500ms 100px 流程蓝光,规则执行
A2A模式 #1ABC9C 2800ms 100px 通信青光,Agent协同
OpenClaw模式 #FF69B4 3200ms 100px 轻量粉光,快速定制

6.5 PC端多窗口光效协同

  • 主窗口:全屏沉浸,编排模式光效延伸至所有安全区边缘
  • 浮动属性面板窗口:置顶、圆角、阴影,激活时边缘发光增强
  • 光效同步 :通过WindowLightSync管理器实现跨窗口主题色联动
  • 焦点感知:窗口激活时边缘发光增强,失活时自动降低光效强度
  • 模式一致性:同一编排模式在所有窗口中保持相同色彩标识

七、调试与适配建议

  1. HMAF会话管理:多智能体并发时注意会话资源释放,避免内存泄漏
  2. 光效功耗优化:夜间模式降低光效刷新率,延长OLED屏幕寿命
  3. 意图识别校准:不同编排场景需训练专用意图模型,提升解析准确率
  4. 分布式设备测试:测试跨设备编排协作时的网络延迟与状态同步
  5. 无障碍支持:为视障用户提供语音播报编排状态,光效切换时播放提示音
  6. 性能优化:复杂画布(100+节点)时启用虚拟渲染,仅渲染可视区域节点

八、总结与展望

本文基于HarmonyOS 6(API 23)的悬浮导航沉浸光感HMAF智能体框架特性,完整实战了一款面向 PC端的"智流工坊"低代码可视化智能体编排平台。核心创新点总结:

  1. HMAF四种编排模式:基于Agent Framework Kit支持LLM模式(单Agent自主决策)、工作流模式(可视化画布编排)、A2A模式(Agent间通信)、OpenClaw模式(轻量个性化),实现一套引擎四种范式的无缝切换

  2. 节点类型光效系统:每个节点类型拥有专属光效人格(LLM节点智慧紫、工具节点功能蓝、条件节点决策黄、循环节点循环绿、输出节点成果橙),根据运行状态动态切换脉冲节奏与光晕强度,实现"节点直觉感知"

  3. 悬浮编排导航:底部悬浮页签不仅承载页面切换,更实时显示编排模式徽章(LLM紫光、工作流蓝光、A2A青光、OpenClaw粉光)和运行状态脉冲,玻璃拟态设计+三档透明度调节

  4. PC级多窗口协作开发 :主画布窗口 + 浮动属性面板 + 浮动预览窗口 + 浮动调试控制台窗口的四层架构,通过WindowLightSync实现跨窗口光效联动与焦点感知

  5. 可视化拖拽编排 :基于CanvasGesture实现节点拖拽创建、连线连接、属性编辑,支持拓扑排序执行和实时状态反馈

未来扩展方向

  • 接入分布式软总线4.0,实现PC编排+手机测试+平板预览的多设备协作
  • AI智能体市场:支持第三方开发者发布自定义节点,通过光效标识区分能力类型
  • 数字孪生集成:接入IoT设备数据,编排流程自动感知物理世界状态并调整执行策略
  • VR/AR融合:支持VR头显接入,实现完全沉浸式的3D智能体编排空间
  • 自然语言编排:通过语音指令直接生成编排流程,"说即所得"

转载自:https://blog.csdn.net/u014727709/article/details/161166078

欢迎 👍点赞✍评论⭐收藏,欢迎指正

相关推荐
richard_yuu2 小时前
鸿蒙ArkUI组件化实战|公共组件封装、复用解耦与上架级UI规范落地
ui·华为·harmonyos
AI周红伟2 小时前
Token工厂落地:移动,电信,华为,阿里,从流量到Token,All in Token
大数据·人工智能·百度·华为·copilot·openclaw
KKei16382 小时前
Flutter for OpenHarmony 学习专注模式APP技术文章
学习·flutter·华为·harmonyos
想你依然心痛2 小时前
HarmonyOS 6(API 23)实战:基于悬浮导航、沉浸光感与HMAF的“数字孪生工坊“——工业制造AI智能体协同平台
人工智能·制造·harmonyos
UnicornDev2 小时前
【Flutter x HarmonyOS 6】挑战功能的业务逻辑实现
flutter·华为·harmonyos·鸿蒙·鸿蒙系统
不爱吃糖的程序媛3 小时前
Harmonybrew:让Homebrew落地OpenHarmony,补齐鸿蒙命令行包管理能力
华为·harmonyos
低代码布道师12 小时前
微搭低代码MBA 培训管理系统实战 41——审批中心
低代码
踩着两条虫12 小时前
「AI + 低代码」的可视化设计器
开发语言·前端·低代码·设计模式·架构
nashane17 小时前
HarmonyOS 6学习:AI攻略长截图“防抖”与像素级拼接术
学习·华为·harmonyos