mirror of
https://github.com/RightNow-AI/openfang.git
synced 2026-07-30 23:05:08 +00:00
community fixes
This commit is contained in:
Generated
+14
-14
@@ -3792,7 +3792,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-api"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
@@ -3832,7 +3832,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-channels"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
@@ -3864,7 +3864,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-cli"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"clap_complete",
|
||||
@@ -3891,7 +3891,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-desktop"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"axum",
|
||||
"open",
|
||||
@@ -3917,7 +3917,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-extensions"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"argon2",
|
||||
@@ -3945,7 +3945,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-hands"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dashmap",
|
||||
@@ -3962,7 +3962,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-kernel"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -3999,7 +3999,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-memory"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -4018,7 +4018,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-migrate"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"dirs 6.0.0",
|
||||
@@ -4037,7 +4037,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-runtime"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
@@ -4071,7 +4071,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-skills"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
@@ -4094,7 +4094,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-types"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -4113,7 +4113,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openfang-wire"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
@@ -8776,7 +8776,7 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.4.1"
|
||||
version = "0.4.2"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
|
||||
+4
-1
@@ -18,7 +18,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
edition = "2021"
|
||||
license = "Apache-2.0 OR MIT"
|
||||
repository = "https://github.com/RightNow-AI/openfang"
|
||||
@@ -138,6 +138,9 @@ imap = "2"
|
||||
native-tls = "0.2"
|
||||
mailparse = "0.15"
|
||||
|
||||
# OpenSSL (vendored = statically compiled, no runtime libssl dependency on Linux)
|
||||
openssl = { version = "0.10", features = ["vendored"] }
|
||||
|
||||
# Testing
|
||||
tokio-test = "0.4"
|
||||
tempfile = "3"
|
||||
|
||||
@@ -322,7 +322,7 @@ pub async fn chat_completions(
|
||||
let kernel_handle: Arc<dyn KernelHandle> = state.kernel.clone() as Arc<dyn KernelHandle>;
|
||||
match state
|
||||
.kernel
|
||||
.send_message_with_handle(agent_id, &last_user_msg, Some(kernel_handle))
|
||||
.send_message_with_handle(agent_id, &last_user_msg, Some(kernel_handle), None, None)
|
||||
.await
|
||||
{
|
||||
Ok(result) => {
|
||||
@@ -378,7 +378,7 @@ async fn stream_response(
|
||||
|
||||
let (mut rx, _handle) = state
|
||||
.kernel
|
||||
.send_message_streaming(agent_id, message, Some(kernel_handle))
|
||||
.send_message_streaming(agent_id, message, Some(kernel_handle), None, None)
|
||||
.map_err(|e| format!("Streaming setup failed: {e}"))?;
|
||||
|
||||
let (tx, stream_rx) = tokio::sync::mpsc::channel::<Result<SseEvent, Infallible>>(64);
|
||||
|
||||
@@ -364,16 +364,10 @@ pub async fn send_message(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(#597): Thread req.sender_id / req.sender_name into PromptContext
|
||||
// so the agent loop can see who sent the message. Requires extending
|
||||
// send_message_with_handle to accept optional sender metadata.
|
||||
let _sender_id = req.sender_id;
|
||||
let _sender_name = req.sender_name;
|
||||
|
||||
let kernel_handle: Arc<dyn KernelHandle> = state.kernel.clone() as Arc<dyn KernelHandle>;
|
||||
match state
|
||||
.kernel
|
||||
.send_message_with_handle(agent_id, &req.message, Some(kernel_handle))
|
||||
.send_message_with_handle(agent_id, &req.message, Some(kernel_handle), req.sender_id, req.sender_name)
|
||||
.await
|
||||
{
|
||||
Ok(result) => {
|
||||
@@ -1349,15 +1343,11 @@ pub async fn send_message_stream(
|
||||
.into_response();
|
||||
}
|
||||
|
||||
// TODO(#597): Thread req.sender_id / req.sender_name into PromptContext
|
||||
let _sender_id = req.sender_id;
|
||||
let _sender_name = req.sender_name;
|
||||
|
||||
let kernel_handle: Arc<dyn KernelHandle> = state.kernel.clone() as Arc<dyn KernelHandle>;
|
||||
let (rx, _handle) =
|
||||
match state
|
||||
.kernel
|
||||
.send_message_streaming(agent_id, &req.message, Some(kernel_handle))
|
||||
.send_message_streaming(agent_id, &req.message, Some(kernel_handle), req.sender_id, req.sender_name)
|
||||
{
|
||||
Ok(pair) => pair,
|
||||
Err(e) => {
|
||||
@@ -3990,7 +3980,9 @@ pub async fn install_hand_deps(
|
||||
let combined = format!("{stdout}{stderr}");
|
||||
let likely_ok = combined.contains("already installed")
|
||||
|| combined.contains("No applicable update")
|
||||
|| combined.contains("No available upgrade");
|
||||
|| combined.contains("No available upgrade")
|
||||
|| combined.contains("already an App at")
|
||||
|| combined.contains("is already installed");
|
||||
results.push(serde_json::json!({
|
||||
"key": req.key,
|
||||
"status": if likely_ok { "installed" } else { "error" },
|
||||
@@ -8189,7 +8181,7 @@ pub async fn run_schedule(
|
||||
);
|
||||
|
||||
let kernel_handle: Arc<dyn KernelHandle> = state.kernel.clone() as Arc<dyn KernelHandle>;
|
||||
match state.kernel.send_message_with_handle(target_agent, &run_message, Some(kernel_handle)).await {
|
||||
match state.kernel.send_message_with_handle(target_agent, &run_message, Some(kernel_handle), None, None).await {
|
||||
Ok(result) => (
|
||||
StatusCode::OK,
|
||||
Json(serde_json::json!({
|
||||
|
||||
@@ -504,7 +504,7 @@ async fn handle_text_message(
|
||||
state.kernel.clone() as Arc<dyn KernelHandle>;
|
||||
match state
|
||||
.kernel
|
||||
.send_message_streaming(agent_id, &content, Some(kernel_handle))
|
||||
.send_message_streaming(agent_id, &content, Some(kernel_handle), None, None)
|
||||
{
|
||||
Ok((mut rx, handle)) => {
|
||||
// Forward stream events to WebSocket with debouncing
|
||||
|
||||
@@ -27,6 +27,8 @@ function renderMarkdown(text) {
|
||||
var html = marked.parse(text);
|
||||
// Add copy buttons to code blocks
|
||||
html = html.replace(/<pre><code/g, '<pre><button class="copy-btn" onclick="copyCode(this)">Copy</button><code');
|
||||
// Open external links in new tab
|
||||
html = html.replace(/<a\s+href="(https?:\/\/[^"]*)"(?![^>]*target=)([^>]*)>/gi, '<a href="$1" target="_blank" rel="noopener"$2>');
|
||||
return html;
|
||||
}
|
||||
return escapeHtml(text);
|
||||
|
||||
@@ -401,8 +401,12 @@ function settingsPage() {
|
||||
var key = this.providerKeyInputs[provider.id];
|
||||
if (!key || !key.trim()) { OpenFangToast.error('Please enter an API key'); return; }
|
||||
try {
|
||||
await OpenFangAPI.post('/api/providers/' + encodeURIComponent(provider.id) + '/key', { key: key.trim() });
|
||||
OpenFangToast.success('API key saved for ' + provider.display_name);
|
||||
var resp = await OpenFangAPI.post('/api/providers/' + encodeURIComponent(provider.id) + '/key', { key: key.trim() });
|
||||
if (resp && resp.switched_default) {
|
||||
OpenFangToast.warning(resp.message || 'Default provider was switched to ' + provider.display_name);
|
||||
} else {
|
||||
OpenFangToast.success('API key saved for ' + provider.display_name);
|
||||
}
|
||||
this.providerKeyInputs[provider.id] = '';
|
||||
await this.loadProviders();
|
||||
await this.loadModels();
|
||||
|
||||
@@ -303,7 +303,7 @@ pub fn spawn_inprocess_stream(
|
||||
// send_message_streaming() finds the reactor.
|
||||
let _guard = rt.enter();
|
||||
|
||||
match kernel.send_message_streaming(agent_id, &message, None) {
|
||||
match kernel.send_message_streaming(agent_id, &message, None, None, None) {
|
||||
Ok((mut rx, handle)) => {
|
||||
rt.block_on(async {
|
||||
while let Some(ev) = rx.recv().await {
|
||||
|
||||
@@ -1389,7 +1389,7 @@ impl OpenFangKernel {
|
||||
.get()
|
||||
.and_then(|w| w.upgrade())
|
||||
.map(|arc| arc as Arc<dyn KernelHandle>);
|
||||
self.send_message_with_handle(agent_id, message, handle)
|
||||
self.send_message_with_handle(agent_id, message, handle, None, None)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -1408,7 +1408,7 @@ impl OpenFangKernel {
|
||||
.get()
|
||||
.and_then(|w| w.upgrade())
|
||||
.map(|arc| arc as Arc<dyn KernelHandle>);
|
||||
self.send_message_with_handle_and_blocks(agent_id, message, handle, Some(blocks))
|
||||
self.send_message_with_handle_and_blocks(agent_id, message, handle, Some(blocks), None, None)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -1418,8 +1418,10 @@ impl OpenFangKernel {
|
||||
agent_id: AgentId,
|
||||
message: &str,
|
||||
kernel_handle: Option<Arc<dyn KernelHandle>>,
|
||||
sender_id: Option<String>,
|
||||
sender_name: Option<String>,
|
||||
) -> KernelResult<AgentLoopResult> {
|
||||
self.send_message_with_handle_and_blocks(agent_id, message, kernel_handle, None)
|
||||
self.send_message_with_handle_and_blocks(agent_id, message, kernel_handle, None, sender_id, sender_name)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -1438,6 +1440,8 @@ impl OpenFangKernel {
|
||||
message: &str,
|
||||
kernel_handle: Option<Arc<dyn KernelHandle>>,
|
||||
content_blocks: Option<Vec<openfang_types::message::ContentBlock>>,
|
||||
sender_id: Option<String>,
|
||||
sender_name: Option<String>,
|
||||
) -> KernelResult<AgentLoopResult> {
|
||||
// Acquire per-agent lock to serialize concurrent messages for the same agent.
|
||||
// This prevents session corruption when multiple messages arrive in quick
|
||||
@@ -1467,7 +1471,7 @@ impl OpenFangKernel {
|
||||
self.execute_python_agent(&entry, agent_id, message).await
|
||||
} else {
|
||||
// Default: LLM agent loop (builtin:chat or any unrecognized module)
|
||||
self.execute_llm_agent(&entry, agent_id, message, kernel_handle, content_blocks)
|
||||
self.execute_llm_agent(&entry, agent_id, message, kernel_handle, content_blocks, sender_id, sender_name)
|
||||
.await
|
||||
};
|
||||
|
||||
@@ -1522,6 +1526,8 @@ impl OpenFangKernel {
|
||||
agent_id: AgentId,
|
||||
message: &str,
|
||||
kernel_handle: Option<Arc<dyn KernelHandle>>,
|
||||
sender_id: Option<String>,
|
||||
sender_name: Option<String>,
|
||||
) -> KernelResult<(
|
||||
tokio::sync::mpsc::Receiver<StreamEvent>,
|
||||
tokio::task::JoinHandle<KernelResult<AgentLoopResult>>,
|
||||
@@ -1759,8 +1765,8 @@ impl OpenFangKernel {
|
||||
},
|
||||
peer_agents,
|
||||
current_date: Some(chrono::Local::now().format("%A, %B %d, %Y (%Y-%m-%d %H:%M %Z)").to_string()),
|
||||
sender_id: None,
|
||||
sender_name: None,
|
||||
sender_id,
|
||||
sender_name,
|
||||
};
|
||||
manifest.model.system_prompt =
|
||||
openfang_runtime::prompt_builder::build_system_prompt(&prompt_ctx);
|
||||
@@ -2087,6 +2093,7 @@ impl OpenFangKernel {
|
||||
}
|
||||
|
||||
/// Execute the default LLM-based agent loop.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn execute_llm_agent(
|
||||
&self,
|
||||
entry: &AgentEntry,
|
||||
@@ -2094,6 +2101,8 @@ impl OpenFangKernel {
|
||||
message: &str,
|
||||
kernel_handle: Option<Arc<dyn KernelHandle>>,
|
||||
content_blocks: Option<Vec<openfang_types::message::ContentBlock>>,
|
||||
sender_id: Option<String>,
|
||||
sender_name: Option<String>,
|
||||
) -> KernelResult<AgentLoopResult> {
|
||||
// Check metering quota before starting
|
||||
self.metering
|
||||
@@ -2268,8 +2277,8 @@ impl OpenFangKernel {
|
||||
},
|
||||
peer_agents,
|
||||
current_date: Some(chrono::Local::now().format("%A, %B %d, %Y (%Y-%m-%d %H:%M %Z)").to_string()),
|
||||
sender_id: None,
|
||||
sender_name: None,
|
||||
sender_id,
|
||||
sender_name,
|
||||
};
|
||||
manifest.model.system_prompt =
|
||||
openfang_runtime::prompt_builder::build_system_prompt(&prompt_ctx);
|
||||
@@ -3924,7 +3933,7 @@ impl OpenFangKernel {
|
||||
let kh: std::sync::Arc<dyn openfang_runtime::kernel_handle::KernelHandle> = kernel.clone();
|
||||
match tokio::time::timeout(
|
||||
timeout,
|
||||
kernel.send_message_with_handle(agent_id, message, Some(kh)),
|
||||
kernel.send_message_with_handle(agent_id, message, Some(kh), None, None),
|
||||
)
|
||||
.await
|
||||
{
|
||||
|
||||
@@ -303,7 +303,7 @@ async fn test_wasm_agent_streaming_fallback() {
|
||||
let agent_id = kernel.spawn_agent(manifest).unwrap();
|
||||
|
||||
let (mut rx, handle) = kernel
|
||||
.send_message_streaming(agent_id, "Hi!", None)
|
||||
.send_message_streaming(agent_id, "Hi!", None, None, None)
|
||||
.expect("Streaming should start");
|
||||
|
||||
// Collect all stream events
|
||||
|
||||
@@ -865,6 +865,10 @@ fn builtin_aliases() -> HashMap<String, String> {
|
||||
("qwen-coder", "qwen-code/qwen3-coder"),
|
||||
("qwen-coder-plus", "qwen-code/qwen-coder-plus"),
|
||||
("qwq", "qwen-code/qwq-32b"),
|
||||
// OpenRouter free-tier aliases
|
||||
("openrouter/free", "openrouter/meta-llama/llama-3.1-8b-instruct:free"),
|
||||
("free", "openrouter/meta-llama/llama-3.1-8b-instruct:free"),
|
||||
("free-reasoning", "openrouter/deepseek/deepseek-r1:free"),
|
||||
];
|
||||
pairs
|
||||
.into_iter()
|
||||
|
||||
@@ -37,7 +37,8 @@ pub const GITHUB_COPILOT_BASE_URL: &str = "https://api.githubcopilot.com";
|
||||
|
||||
// ── Chinese providers ─────────────────────────────────────────────
|
||||
pub const QWEN_BASE_URL: &str = "https://dashscope.aliyuncs.com/compatible-mode/v1";
|
||||
pub const MINIMAX_BASE_URL: &str = "https://api.minimaxi.chat/v1";
|
||||
/// Global endpoint. For China mainland, override via `[provider_urls] minimax = "https://api.minimaxi.com/v1"`.
|
||||
pub const MINIMAX_BASE_URL: &str = "https://api.minimax.io/v1";
|
||||
pub const ZHIPU_BASE_URL: &str = "https://open.bigmodel.cn/api/paas/v4";
|
||||
pub const ZHIPU_CODING_BASE_URL: &str = "https://open.bigmodel.cn/api/coding/paas/v4";
|
||||
/// Z.AI domain aliases (same API, different domain).
|
||||
|
||||
@@ -125,12 +125,21 @@ async function startConnection() {
|
||||
if (msg.key.remoteJid === 'status@broadcast') continue;
|
||||
|
||||
const sender = msg.key.remoteJid || '';
|
||||
const text = msg.message?.conversation
|
||||
let text = msg.message?.conversation
|
||||
|| msg.message?.extendedTextMessage?.text
|
||||
|| msg.message?.imageMessage?.caption
|
||||
|| '';
|
||||
|
||||
if (!text) continue;
|
||||
// Detect media type if no text
|
||||
if (!text) {
|
||||
const m = msg.message;
|
||||
if (m?.imageMessage) text = '[Image received]' + (m.imageMessage.caption ? ': ' + m.imageMessage.caption : '');
|
||||
else if (m?.audioMessage) text = '[Voice note received]';
|
||||
else if (m?.videoMessage) text = '[Video received]' + (m.videoMessage.caption ? ': ' + m.videoMessage.caption : '');
|
||||
else if (m?.documentMessage) text = '[Document received: ' + (m.documentMessage.fileName || 'file') + ']';
|
||||
else if (m?.stickerMessage) text = '[Sticker received]';
|
||||
else continue; // Only skip truly empty messages
|
||||
}
|
||||
|
||||
// Extract phone number from JID (e.g. "1234567890@s.whatsapp.net" → "+1234567890")
|
||||
const phone = '+' + sender.replace(/@.*$/, '');
|
||||
|
||||
Reference in New Issue
Block a user