Skip to main content Instalar con Codex o Claude Copia este prompt, pégalo en Codex, Claude u otro asistente, y deja que revise la página de la skill y la instale por ti.
Un comando directo omite el prompt de revisión. Revisa el origen antes de ejecutarlo.
npx skills add https://github.com/Anhvu1107/all-agent-skill --skill molykitEl comando permanece en una sola línea. Desplázate horizontalmente para revisarlo antes de copiarlo.
¿Prefieres una copia local? Descarga los archivos que SkillsMP tiene disponibles ahora.
ALWAYS use this when the user mentions 10 Andruia Skill Smith, asks to build, debug, review, document, automate, test, configure, migrate, or make decisions in this domain, or the task clearly depends on 10 Andruia Skill Smith; scope: Ingeniero de Sistemas de Andru.ia. Apply the bundled workflow, references, scripts, Senior Master standard, and Codex strict review gate before final output.
Ocupaciones relacionadasSOC
Basado en la clasificación ocupacional SOC
Explorador de archivos
7 archivos| name | molykit |
| description | ALWAYS use this when the request matches Molykit: CRITICAL: Use for MolyKit AI chat toolkit. |
MolyKit Skill
Selective Reading Rule
Start with:
references/senior-master-standard.md
references/usage-routing.md
references/quality-checklist.md
Then load only the inherited docs, scripts, assets, or examples that match the user's actual task.
Best practices for building AI chat interfaces with Makepad using MolyKit - a toolkit for cross-platform AI chat applications.
Source codebase: /Users/zhangalex/Work/Projects/FW/robius/moly/moly-kit
When to Use
Use this skill when:
- Building AI chat interfaces with Makepad
- Integrating OpenAI or other LLM APIs
- Implementing cross-platform async for native and WASM
- Creating chat widgets (messages, prompts, avatars)
- Handling SSE streaming responses
- Keywords: molykit, moly-kit, ai chat, bot client, openai makepad, chat widget, sse streaming
Overview
MolyKit provides:
- Cross-platform async utilities (PlatformSend, spawn(), ThreadToken)
- Ready-to-use chat widgets (Chat, Messages, PromptInput, Avatar)
- BotClient trait for AI provider integration
- OpenAI-compatible client with SSE streaming
- Protocol types for messages, bots, and tool calls
- MCP (Model Context Protocol) support
Cross-Platform Async Patterns
PlatformSend - Send Only on Native
: PlatformSendInner {}
<, T> = Pin<< PlatformSendFuture<Output = T> + >>;
<, T> = Pin<< PlatformSendStream<Item = T> + >>;
pub
trait
PlatformSend
pub
type
BoxPlatformSendFuture
'a
Box
dyn
'a
pub
type
BoxPlatformSendStream
'a
Box
dyn
'a
Platform-Agnostic Spawning
pub fn spawn(fut: impl PlatformSendFuture<Output = ()> + 'static);
spawn(async move {
let result = fetch_data().await;
Cx::post_action(DataReady(result));
SignalToUI::set_ui_signal();
});
Task Cancellation with AbortOnDropHandle
pub struct AbortOnDropHandle(AbortHandle);
#[rust]
task_handle: Option<AbortOnDropHandle>,
fn start_task(&mut self) {
let (future, handle) = abort_on_drop(async move {
});
self.task_handle = Some(handle);
spawn(async move { let _ = future.await; });
}
ThreadToken for Non-Send Types on WASM
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;
}
let token = ThreadToken::new(non_send_value);
spawn(async move {
token.peek(|value| {
});
});
BotClient Trait
Implementing AI Provider Integration
pub trait BotClient: Send {
fn send(
&mut self,
bot_id: &BotId,
messages: &[Message],
tools: &[Tool],
) -> BoxPlatformSendStream<'static, ClientResult<MessageContent>>;
fn bots(&self) -> BoxPlatformSendFuture<'static, ClientResult<Vec<Bot>>>;
fn clone_box(&self) -> Box<dyn BotClient>;
}
let client = OpenAIClient::new("https://api.openai.com/v1".into());
client.set_key("sk-...")?;
let context = BotContext::from(client);
BotContext - Sharable Wrapper
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>;
}
let mut context = BotContext::from(client);
spawn(async move {
if let Err(errors) = context.load().await.into_result() {
}
Cx::post_action(BotsLoaded);
});
Protocol Types
Message Structure
pub struct Message {
pub from: EntityId,
pub metadata: MessageMetadata,
pub content: MessageContent,
}
pub struct MessageContent {
pub text: String,
pub reasoning: String,
pub citations: Vec<String>,
pub attachments: Vec<Attachment>,
pub tool_calls: Vec<ToolCall>,
pub tool_results: Vec<ToolResult>,
}
pub struct MessageMetadata {
pub is_writing: bool,
pub created_at: DateTime<Utc>,
}
Bot Identification
pub struct BotId(Arc<str>);
impl BotId {
pub fn new(id: &str, provider: &str) -> Self;
pub fn id(&self) -> &str;
pub fn provider(&self) -> &str;
}
Widget Patterns
Slot Widget - Runtime Content Replacement
live_design! {
pub Slot = {{Slot}} {
width: Fill, height: Fit,
slot = <View> {}
}
}
let mut slot = widget.slot(id!(content));
if let Some(custom) = client.content_widget(cx, ...) {
slot.replace(custom);
} else {
slot.restore();
slot.default().as_standard_message_content().set_content(cx, &content);
}
Avatar Widget - Text/Image Toggle
live_design! {
pub Avatar = {{Avatar}} <View> {
grapheme = <RoundedView> {
visible: false,
label = <Label> { text: "P" }
}
dependency = <RoundedView> {
visible: false,
image = <Image> {}
}
}
}
impl Widget for Avatar {
fn draw_walk(&mut self, cx: &mut Cx2d, ...) -> DrawStep {
if let Some(avatar) = &self.avatar {
match avatar {
Picture::Grapheme(g) => {
self.view(id!(grapheme)).set_visible(cx, true);
self.view(id!(dependency)).set_visible(cx, false);
self.label(id!(label)).set_text(cx, &g);
}
Picture::Dependency(d) => {
self.view(id!(dependency)).set_visible(cx, true);
self.view(id!(grapheme)).set_visible(cx, false);
self.image(id!(image)).load_image_dep_by_path(cx, d.as_str());
}
}
}
self.deref.draw_walk(cx, scope, walk)
}
}
PromptInput Widget
#[derive(Live, Widget)]
pub struct PromptInput {
#[deref] deref: CommandTextInput,
#[live] pub send_icon: LiveValue,
#[live] pub stop_icon: LiveValue,
#[rust] pub task: Task,
#[rust] pub interactivity: Interactivity,
}
impl PromptInput {
pub fn submitted(&self, actions: &Actions) -> bool;
pub fn reset(&mut self, cx: &mut Cx);
pub fn set_send(&mut self);
pub fn set_stop(&mut self);
pub fn enable(&mut self);
pub fn disable(&mut self);
}
Messages Widget - Conversation View
#[derive(Live, Widget)]
pub struct Messages {
#[deref] deref: View,
#[rust] pub messages: Vec<Message>,
#[rust] pub bot_context: Option<BotContext>,
}
impl Messages {
pub fn set_messages(&mut self, messages: Vec<Message>, scroll_to_bottom: bool);
pub fn scroll_to_bottom(&mut self, cx: &mut Cx, triggered_by_stream: bool);
pub fn is_at_bottom(&self) -> bool;
}
UiRunner Pattern for Async-to-UI
impl Widget for PromptInput {
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
self.deref.handle_event(cx, event, scope);
self.ui_runner().handle(cx, event, scope, self);
if self.button(id!(attach)).clicked(event.actions()) {
let ui = self.ui_runner();
Attachment::pick_multiple(move |result| match result {
Ok(attachments) => {
ui.defer_with_redraw(move |me, cx, _| {
me.attachment_list_ref().write().attachments.extend(attachments);
});
}
Err(_) => {}
});
}
}
}
SSE Streaming
pub fn parse_sse<S, B, E>(s: S) -> impl Stream<Item = Result<String, E>>
where
S: Stream<Item = Result<B, E>>,
B: AsRef<[u8]>,
{
}
fn send(&mut self, ...) -> BoxPlatformSendStream<...> {
let stream = stream! {
let response = client.post(url).send().await?;
let events = parse_sse(response.bytes_stream());
for await event in events {
let completion: Completion = serde_json::from_str(&event)?;
content.text.push_str(&completion.delta.content);
yield ClientResult::new_ok(content.clone());
}
};
Box::pin(stream)
}
Best Practices
- Use PlatformSend for cross-platform: Same code works on native and WASM
- Use spawn() not tokio::spawn: Platform-agnostic task spawning
- Use AbortOnDropHandle: Cancel tasks when widget drops
- Use ThreadToken for non-Send on WASM: Thread-local storage with token access
- Use Slot for custom content: Allow BotClient to provide custom widgets
- Use read()/write() pattern: Safe borrow access via WidgetRef
- Use UiRunner::defer_with_redraw: Update widget from async context
- Handle ClientResult partial success: May have value AND errors
Reference Files
llms.txt - Complete MolyKit API reference
Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.