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;
15mod note;
16
17use agent::{AppStrategy, ChatHandler, create_agent};
18use note::Note;
19
20use crate::agent::ChatContext;
21
22#[wasm_bindgen]
24#[derive(Clone, Debug)]
25pub struct Message {
26 content: String,
27 role: String,
28}
29
30#[wasm_bindgen]
31impl Message {
32 #[wasm_bindgen(constructor)]
33 pub fn new(content: String, role: String) -> Message {
34 Message { content, role }
35 }
36
37 #[wasm_bindgen(getter)]
38 pub fn content(&self) -> String {
39 self.content.clone()
40 }
41
42 #[wasm_bindgen(getter)]
43 pub fn role(&self) -> String {
44 self.role.clone()
45 }
46
47 #[wasm_bindgen(setter)]
48 pub fn set_content(&mut self, content: String) {
49 self.content = content;
50 }
51
52 #[wasm_bindgen(setter)]
53 pub fn set_role(&mut self, role: String) {
54 self.role = role;
55 }
56}
57
58impl From<Message> for ChatMessage {
59 fn from(message: Message) -> Self {
60 ChatMessage {
61 content: message.content,
62 role: message.role,
63 }
64 }
65}
66
67#[wasm_bindgen]
69pub struct AgentWasmRuntime {
70 agent: Option<Agent<AppStrategy>>,
71 chat_handler: Arc<Mutex<ChatHandler>>,
72 running: bool,
73}
74
75#[wasm_bindgen]
76impl AgentWasmRuntime {
77 #[wasm_bindgen(constructor)]
78 pub fn new(jwt: String) -> AgentWasmRuntime {
79 let (agent, chat_handler) = create_agent(jwt);
80
81 AgentWasmRuntime {
82 agent: Some(agent),
83 chat_handler: Arc::new(Mutex::new(chat_handler)),
84 running: false,
85 }
86 }
87
88 #[wasm_bindgen]
89 pub fn start(&mut self) {
90 if self.running {
91 tracing::warn!("Agent is already running");
92 return;
93 }
94
95 if let Some(mut agent) = self.agent.take() {
96 let _chat_handler = self.chat_handler.clone();
97 spawn_local(async move {
98 tracing::info!("Starting agent runtime");
99 agent.run().await;
100 });
101 self.running = true;
102 tracing::info!("Agent runtime started");
103 }
104 }
105
106 #[wasm_bindgen]
107 pub async fn chat(&self, messages: Vec<Message>, cursor_position: usize, note: JsValue) -> Result<JsValue, JsValue> {
108 if !self.running {
109 return Err(JsValue::from_str(
110 "Agent is not running. Call start() first.",
111 ));
112 }
113
114 let note: Note = serde_wasm_bindgen::from_value(note)?;
116
117 let chat_messages: Vec<ChatMessage> = messages.into_iter().map(|msg| msg.into()).collect();
119
120 let chat = Chat {
121 messages: chat_messages,
122
123 session_id: 0,
125 };
126
127 let mut handler = self.chat_handler.lock().await;
128 match handler.chat(chat, &ChatContext {
129 note,
130 cursor_position,
131 }).await {
132 Ok(action) => Ok(serde_wasm_bindgen::to_value(&action)?),
133 Err(e) => Err(JsValue::from_str(&format!("Chat error: {}", e))),
134 }
135 }
136
137 #[wasm_bindgen]
138 pub fn is_running(&self) -> bool {
139 self.running
140 }
141}
142
143#[wasm_bindgen(start)]
145pub fn start() {
146 log::init();
147 tracing::info!("WASM module initialized");
148}