
关于
MolyKit 分子工具包开发指南。
name: molykit description: | 关键:用于 MolyKit AI 聊天工具包。触发条件: BotClient、OpenAI、SSE 流式传输、AI 聊天、molykit、 PlatformSend、spawn()、ThreadToken、跨平台异步、 聊天组件、Messages、PromptInput、Avatar、LLM risk: unknown source: community
MolyKit 技能
使用 MolyKit 构建 AI 聊天界面的最佳实践 - 一个用于跨平台 AI 聊天应用的工具包。
源代码库:/Users/zhangalex/Work/Projects/FW/robius/moly/moly-kit
使用时机
在以下情况使用本技能:
- 使用 Makepad 构建 AI 聊天界面
- 集成 OpenAI 或其他 LLM API
- 实现原生和 WASM 的跨平台异步
- 创建聊天组件(消息、提示输入、头像)
- 处理 SSE 流式响应
- 关键词:molykit、moly-kit、ai chat、bot client、openai makepad、chat widget、sse streaming
概述
MolyKit 提供:
- 跨平台异步工具(PlatformSend、spawn()、ThreadToken)
- 即用型聊天组件(Chat、Messages、PromptInput、Avatar)
- 用于 AI 提供商集成的 BotClient trait
- 兼容 OpenAI 的客户端(支持 SSE 流式传输)
- 消息、机器人和工具调用的协议类型
- MCP(模型上下文协议)支持
跨平台异步模式
PlatformSend - 仅在原生平台发送
/// Implies Send only on native platforms, not on WASM
/// - On native: implemented by types that implement Send
/// - On WASM: implemented by ALL types
pub trait PlatformSend: PlatformSendInner {}
/// Boxed future type for cross-platform use
pub type BoxPlatformSendFuture<'a, T> = Pin<Box<dyn PlatformSendFuture<Output = T> + 'a>>;
/// Boxed stream type for cross-platform use
pub type BoxPlatformSendStream<'a, T> = Pin<Box<dyn PlatformSendStream<Item = T> + 'a>>;
平台无关的任务生成
/// Runs a future independently
/// - Uses tokio on native (requires Send)
/// - Uses wasm-bindgen-futures on WASM (no Send required)
pub fn spawn(fut: impl PlatformSendFuture<Output = ()> + 'static);
// Usage
spawn(async move {
let result = fetch_data().await;
Cx::post_action(DataReady(result));
SignalToUI::set_ui_signal();
});
使用 AbortOnDropHandle 取消任务
/// Handle that aborts its future when dropped
pub struct AbortOnDropHandle(AbortHandle);
// Usage - task cancelled when widget dropped
#[rust]
task_handle: Option<AbortOnDropHandle>,
fn start_task(&mut self) {
let (future, handle) = abort_on_drop(async move {
// async work...
});
self.task_handle = Some(handle);
spawn(async move { let _ = future.await; });
}
用于 WASM 上非 Send 类型的 ThreadToken
/// Store non-Send value in thread-local, access via token
pub struct ThreadToken<T: 'static>;
impl<T> ThreadToken<T> {
pub fn new(value: T) -> Self;
pub fn peek<R>(&self, f: impl FnOnce(&T) -> R) -> R;
pub fn peek_mut<R>(&self, f: impl FnOnce(&mut T) -> R) -> R;
}
// Usage - wrap non-Send type for use across Send boundaries
let token = ThreadToken::new(non_send_value);
spawn(async move {
token.peek(|value| {
// use value...
});
});
BotClient Trait
实现 AI 提供商集成
pub trait BotClient: Send {
/// Send message with streamed response
fn send(
&mut self,
bot_id: &BotId,
messages: &[Message],
tools: &[Tool],
) -> BoxPlatformSendStream<'static, ClientResult<MessageContent>>;
/// Get available bots/models
fn bots(&self) -> BoxPlatformSendFuture<'static, ClientResult<Vec<Bot>>>;
/// Clone for passing around
fn clone_box(&self) -> Box<dyn BotClient>;
}
// Usage
let client = OpenAIClient::new("https://api.openai.com/v1".into());
client.set_key("sk-...")?;
let context = BotContext::from(client);
BotContext - 可共享的包装器
/// Sharable wrapper with loaded bots for sync UI access
pub struct BotContext(Arc<Mutex<InnerBotContext>>);
impl BotContext {
pub fn load(&mut self) -> BoxPlatformSendFuture<ClientResult<()>>;
pub fn bots(&self) -> Vec<Bot>;
pub fn get_bot(&self, id: &BotId) -> Option<Bot>;
pub fn client(&self) -> Box<dyn BotClient>;
}
// Usage
let mut context = BotContext::from(client);
spawn(async move {
if let Err(errors) = context.load().await.into_result() {
// handle errors
}
Cx::post_action(BotsLoaded);
});
协议类型
消息结构
pub struct Message {
pub from: EntityId, // User, System, Bot(BotId), App
pub metadata: MessageMetadata,
pub content: MessageContent,
}
pub struct MessageContent {
pub text: String, // Main content (markdown)
pub reasoning: String, // AI reasoning/thinking
pub citations: Vec<String>, // Source URLs
pub attachments: Vec<Attachment>,
pub tool_calls: Vec<ToolCall>,
pub tool_results: Vec<ToolResult>,
}
pub struct MessageMetadata {
pub is_writing: bool, // Still being streamed
兼容工具
Claude CodeCursor
标签
AI与机器学习