mirror of
https://github.com/RightNow-AI/openfang.git
synced 2026-04-25 17:25:11 +02:00
community fixes
This commit is contained in:
@@ -922,7 +922,23 @@
|
||||
</select>
|
||||
</div>
|
||||
<div class="detail-row" x-show="detailAgent.profile"><span class="detail-label">Profile</span><span class="detail-value" style="text-transform:capitalize" x-text="detailAgent.profile || '-'"></span></div>
|
||||
<div class="detail-row"><span class="detail-label">Provider</span><span class="detail-value" x-text="detailAgent.model_provider"></span></div>
|
||||
<div class="detail-row"><span class="detail-label">Provider</span>
|
||||
<template x-if="!editingProvider">
|
||||
<span>
|
||||
<span class="detail-value" x-text="detailAgent.model_provider"></span>
|
||||
<button class="btn btn-ghost btn-sm" style="margin-left:8px;padding:2px 8px;font-size:11px" @click="editingProvider = true; newProviderValue = detailAgent.model_provider">Change</button>
|
||||
</span>
|
||||
</template>
|
||||
<template x-if="editingProvider">
|
||||
<span class="flex gap-1" style="align-items:center">
|
||||
<input class="form-input" style="width:160px;font-size:12px" x-model="newProviderValue" placeholder="provider" @keydown.enter="changeProvider()" @keydown.escape="editingProvider = false">
|
||||
<button class="btn btn-primary btn-sm" @click="changeProvider()" :disabled="modelSaving" style="padding:2px 10px">
|
||||
<span x-show="!modelSaving">Save</span><span x-show="modelSaving">...</span>
|
||||
</button>
|
||||
<button class="btn btn-ghost btn-sm" @click="editingProvider = false" style="padding:2px 8px">Cancel</button>
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
<div class="detail-row"><span class="detail-label">Model</span>
|
||||
<template x-if="!editingModel">
|
||||
<span>
|
||||
|
||||
@@ -77,6 +77,8 @@ function agentsPage() {
|
||||
// -- Model switch --
|
||||
editingModel: false,
|
||||
newModelValue: '',
|
||||
editingProvider: false,
|
||||
newProviderValue: '',
|
||||
modelSaving: false,
|
||||
// -- Fallback chain --
|
||||
editingFallback: false,
|
||||
@@ -638,6 +640,26 @@ function agentsPage() {
|
||||
this.modelSaving = false;
|
||||
},
|
||||
|
||||
// ── Provider switch ──
|
||||
async changeProvider() {
|
||||
if (!this.detailAgent || !this.newProviderValue.trim()) return;
|
||||
this.modelSaving = true;
|
||||
try {
|
||||
var combined = this.newProviderValue.trim() + '/' + this.detailAgent.model_name;
|
||||
var resp = await OpenFangAPI.put('/api/agents/' + this.detailAgent.id + '/model', { model: combined });
|
||||
OpenFangToast.success('Provider changed to ' + (resp && resp.provider ? resp.provider : this.newProviderValue.trim()));
|
||||
this.editingProvider = false;
|
||||
await Alpine.store('app').refreshAgents();
|
||||
var agents = Alpine.store('app').agents;
|
||||
for (var i = 0; i < agents.length; i++) {
|
||||
if (agents[i].id === this.detailAgent.id) { this.detailAgent = agents[i]; break; }
|
||||
}
|
||||
} catch(e) {
|
||||
OpenFangToast.error('Failed to change provider: ' + e.message);
|
||||
}
|
||||
this.modelSaving = false;
|
||||
},
|
||||
|
||||
// ── Fallback model chain ──
|
||||
async addFallback() {
|
||||
if (!this.detailAgent || !this.newFallbackValue.trim()) return;
|
||||
|
||||
@@ -5318,6 +5318,12 @@ fn infer_provider_from_model(model: &str) -> Option<String> {
|
||||
(lower.as_str(), false)
|
||||
};
|
||||
if has_delim {
|
||||
// Two or more slashes (e.g. "mlx-lm-lg/mlx-community/Qwen3-4B") means
|
||||
// the first segment is explicitly a provider prefix — HuggingFace repo
|
||||
// IDs only have one slash, so extra slashes are unambiguous.
|
||||
if lower.chars().filter(|&c| c == '/').count() >= 2 {
|
||||
return Some(prefix.to_string());
|
||||
}
|
||||
match prefix {
|
||||
"minimax" | "gemini" | "anthropic" | "openai" | "groq" | "deepseek" | "mistral"
|
||||
| "cohere" | "xai" | "ollama" | "together" | "fireworks" | "perplexity"
|
||||
|
||||
@@ -124,7 +124,9 @@ async function startConnection() {
|
||||
if (msg.key.fromMe) continue;
|
||||
if (msg.key.remoteJid === 'status@broadcast') continue;
|
||||
|
||||
const sender = msg.key.remoteJid || '';
|
||||
const remoteJid = msg.key.remoteJid || '';
|
||||
const isGroup = remoteJid.endsWith('@g.us');
|
||||
|
||||
let text = msg.message?.conversation
|
||||
|| msg.message?.extendedTextMessage?.text
|
||||
|| msg.message?.imageMessage?.caption
|
||||
@@ -141,19 +143,32 @@ async function startConnection() {
|
||||
else continue; // Only skip truly empty messages
|
||||
}
|
||||
|
||||
// Extract phone number from JID (e.g. "1234567890@s.whatsapp.net" → "+1234567890")
|
||||
const phone = '+' + sender.replace(/@.*$/, '');
|
||||
// For groups: real sender is in participant; for DMs: it's remoteJid
|
||||
const senderJid = isGroup ? (msg.key.participant || '') : remoteJid;
|
||||
const phone = '+' + senderJid.replace(/@.*$/, '');
|
||||
const pushName = msg.pushName || phone;
|
||||
|
||||
const metadata = {
|
||||
channel: 'whatsapp',
|
||||
sender: phone,
|
||||
sender_name: pushName,
|
||||
};
|
||||
if (isGroup) {
|
||||
metadata.group_jid = remoteJid;
|
||||
metadata.is_group = true;
|
||||
console.log(`[gateway] Group msg from ${pushName} (${phone}) in ${remoteJid}: ${text.substring(0, 80)}`);
|
||||
} else {
|
||||
console.log(`[gateway] Incoming from ${pushName} (${phone}): ${text.substring(0, 80)}`);
|
||||
}
|
||||
|
||||
// Forward to OpenFang agent
|
||||
try {
|
||||
const response = await forwardToOpenFang(text, phone, pushName);
|
||||
const response = await forwardToOpenFang(text, phone, pushName, metadata);
|
||||
if (response && sock) {
|
||||
// Send agent response back to WhatsApp
|
||||
await sock.sendMessage(sender, { text: response });
|
||||
console.log(`[gateway] Replied to ${pushName}`);
|
||||
// Reply in the same context: group → group, DM → DM
|
||||
const replyJid = isGroup ? remoteJid : senderJid.replace(/@.*$/, '') + '@s.whatsapp.net';
|
||||
await sock.sendMessage(replyJid, { text: response });
|
||||
console.log(`[gateway] Replied to ${pushName}${isGroup ? ' in group ' + remoteJid : ''}`);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`[gateway] Forward/reply failed:`, err.message);
|
||||
@@ -165,11 +180,11 @@ async function startConnection() {
|
||||
// ---------------------------------------------------------------------------
|
||||
// Forward incoming message to OpenFang API, return agent response
|
||||
// ---------------------------------------------------------------------------
|
||||
function forwardToOpenFang(text, phone, pushName) {
|
||||
function forwardToOpenFang(text, phone, pushName, metadata) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const payload = JSON.stringify({
|
||||
message: text,
|
||||
metadata: {
|
||||
metadata: metadata || {
|
||||
channel: 'whatsapp',
|
||||
sender: phone,
|
||||
sender_name: pushName,
|
||||
@@ -223,8 +238,8 @@ async function sendMessage(to, text) {
|
||||
throw new Error('WhatsApp not connected');
|
||||
}
|
||||
|
||||
// Normalize phone → JID: "+1234567890" → "1234567890@s.whatsapp.net"
|
||||
const jid = to.replace(/^\+/, '').replace(/@.*$/, '') + '@s.whatsapp.net';
|
||||
// If already a full JID (group or user), use as-is; otherwise normalize phone → JID
|
||||
const jid = to.includes('@') ? to : to.replace(/^\+/, '') + '@s.whatsapp.net';
|
||||
|
||||
await sock.sendMessage(jid, { text });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user