1use std::sync::Arc;
2
3use amico_core::{
4 Agent,
5 types::{Chat, ChatMessage},
6};
7use tokio::sync::Mutex;
8use tokio_with_wasm::alias as tokio;
9use wasm_bindgen::prelude::*;
10use wasm_bindgen_futures::spawn_local;
11
12mod agent;
13mod log;
14mod service;
15
16use agent::{AppStrategy, ChatHandler, create_agent};
17
18#[wasm_bindgen]
20#[derive(Clone, Debug)]
21pub struct Message {
22 content: String,
23 role: String,
24}
25
26#[wasm_bindgen]
27impl Message {
28 #[wasm_bindgen(constructor)]
29 pub fn new(content: String, role: String) -> Message {
30 Message { content, role }
31 }
32
33 #[wasm_bindgen(getter)]
34 pub fn content(&self) -> String {
35 self.content.clone()
36 }
37
38 #[wasm_bindgen(getter)]
39 pub fn role(&self) -> String {
40 self.role.clone()
41 }
42
43 #[wasm_bindgen(setter)]
44 pub fn set_content(&mut self, content: String) {
45 self.content = content;
46 }
47
48 #[wasm_bindgen(setter)]
49 pub fn set_role(&mut self, role: String) {
50 self.role = role;
51 }
52}
53
54impl From<Message> for ChatMessage {
55 fn from(message: Message) -> Self {
56 ChatMessage {
57 content: message.content,
58 role: message.role,
59 }
60 }
61}
62
63#[wasm_bindgen]
65pub struct AgentWasmRuntime {
66 agent: Option<Agent<AppStrategy>>,
67 chat_handler: Arc<Mutex<ChatHandler>>,
68 running: bool,
69}
70
71#[wasm_bindgen]
72impl AgentWasmRuntime {
73 #[wasm_bindgen(constructor)]
74 pub fn new(jwt: String) -> AgentWasmRuntime {
75 let (agent, chat_handler) = create_agent(jwt);
76
77 AgentWasmRuntime {
78 agent: Some(agent),
79 chat_handler: Arc::new(Mutex::new(chat_handler)),
80 running: false,
81 }
82 }
83
84 #[wasm_bindgen]
85 pub fn start(&mut self) {
86 if self.running {
87 tracing::warn!("Agent is already running");
88 return;
89 }
90
91 if let Some(mut agent) = self.agent.take() {
92 let _chat_handler = self.chat_handler.clone();
93 spawn_local(async move {
94 tracing::info!("Starting agent runtime");
95 agent.run().await;
96 });
97 self.running = true;
98 tracing::info!("Agent runtime started");
99 }
100 }
101
102 #[wasm_bindgen]
103 pub async fn chat(&self, messages: Vec<Message>) -> Result<String, JsValue> {
104 if !self.running {
105 return Err(JsValue::from_str(
106 "Agent is not running. Call start() first.",
107 ));
108 }
109
110 let chat_messages: Vec<ChatMessage> = messages.into_iter().map(|msg| msg.into()).collect();
112
113 let chat = Chat {
114 messages: chat_messages,
115
116 session_id: 0,
118 };
119
120 let mut handler = self.chat_handler.lock().await;
121 match handler.chat(chat).await {
122 Ok(response) => Ok(response),
123 Err(e) => Err(JsValue::from_str(&format!("Chat error: {}", e))),
124 }
125 }
126
127 #[wasm_bindgen]
128 pub fn is_running(&self) -> bool {
129 self.running
130 }
131}
132
133#[wasm_bindgen(start)]
135pub fn start() {
136 log::init();
137 tracing::info!("WASM module initialized");
138}