32. Assistente personale e CLI
MALDA fornisce un assistente personale built-in e un insieme di comandi CLI per configurazione, attività pianificate e stato. Queste funzionalità usano una directory di config standard ~/.malda e un file di config opzionale, così puoi eseguire un assistente AI dalla riga di comando senza scrivere uno script.
32.1 Avvio rapido
- Esegui
malda onboard(oppuremalda onboard --download-rerank --download-local-llama) per creare~/.malda,skills/,memory/e unconfig.jsoniniziale conagents.memory,channels.telegrame i placeholder dei provider. - Imposta
OPENROUTER_API_KEYoppure aggiungiproviders.openrouter.apiKeyin~/.malda/config.json. - Opzionale:
malda memory download-rerankinstalla il cross-encoder ONNX in~/.malda/models/cross-encoderperagents.memory.rerankMode: onnx. - Esegui
malda agentper la chat interattiva, oppuremalda agent -m "Your question"per una risposta one-shot.
32.2 Comandi
32.2.1 malda agent
Esegue lo script dell'assistente di default in modalità interattiva o one-shot.
malda agent— Avvia un loop interattivo: chiede conYou:, legge il messaggio, chiama l'agente e stampa la risposta. Digitaexitoquit(oppure una riga vuota) per uscire.malda agent -m "message"omalda agent --message "message"— Invia il messaggio una volta all'assistente, stampa la risposta ed esce.
Lo script dell'assistente viene risolto in questo ordine:
- Path nella variabile d'ambiente
MALDA_AGENT_SCRIPT(se il file esiste). ~/.malda/assistant.malda.Examples/Assistant/assistant.maldarelativo alla directory corrente o all'eseguibile (es. quando lo esegui dal repo).
Se non viene trovato nessuno script, la CLI stampa un errore ed esce.
32.2.2 malda onboard
Inizializza la directory di config MALDA e una config iniziale guidata.
- Crea
~/.malda,~/.malda/skills/e~/.malda/memory/se non esistono. - Crea
~/.malda/config.jsonconproviders,channels.telegram,agents.defaults,agents.memory(embed, path ONNX del rerank) etools.web.searchse il file non esiste. --download-rerank— scaricamodel.onnxevocab.txtin~/.malda/models/cross-encoder.--download-local-llama— scarica il modello GGUF di default e impostaproviders.local_llama.modelPathquando è vuoto.
Eseguilo una volta prima di usare l'assistente, il gateway o cron. Il comando stampa i passi successivi (API key, Telegram, rerank ONNX, malda doctor).
32.2.3 malda status
Stampa il setup corrente dell'assistente e lo stato di salute del runtime. Usa malda status --json per un output machine-readable (config, canali, skill, gateway, memoria, job cron).
- Home MALDA e path della config; se esiste
~/.malda/config.json. - Se è impostata un'API key OpenRouter (ambiente o config), modello di default, backend e path del modello llama locale.
- Canale Telegram configurato (
TELEGRAM_BOT_TOKENochannels.telegram.botToken). - Conteggio delle skill in
~/.malda/skills/. - Stato del processo gateway (
~/.malda/gateway.pid; i pid file obsoleti vengono rimossi). - Statistiche GraphMemory quando esiste
~/.malda/memory/assistant(nodi, archi, ultimo reflect). - Job cron da
~/.malda/cron.json(id, name, scope, message, espressione cron).
32.2.4 malda gateway
Processo di lunga durata per Telegram e, in opzione, lo scheduling cron in-process.
malda gateway— Avvia il long polling Telegram con lo script dell'assistente di default. Scrive~/.malda/gateway.pide rifiuta di avviarsi se un altro gateway è già in esecuzione.malda gateway stop— Ferma un processo gateway in esecuzione e rimuove~/.malda/gateway.pid(pulisce anche i pid file obsoleti).malda gateway -c telegram— Come sopra (Telegram è l'unico canale supportato oggi).malda gateway --no-cron— Disabilita lo scheduler cron built-in (usa invece Task Scheduler di sistema tramitemalda cron install).
Il gateway esegue lo stesso assistant.malda di malda agent -c telegram, ma inoltre interroga ~/.malda/cron.json ogni minuto e avvia malda agent -m "..." per i job in scadenza (con scope di memoria per job). Richiede un token del bot Telegram in config o in TELEGRAM_BOT_TOKEN.
Alert del gateway: imposta channels.telegram.notifyChatId (oppure MALDA_GATEWAY_NOTIFY_CHAT_ID) per ricevere messaggi Telegram su fallimenti cron, crash del gateway e riavvii dopo un crash. Gli eventi vengono anche accodati in ~/.malda/gateway-alerts.log. malda doctor riporta lo stato del gateway e i crash precedenti tramite ~/.malda/gateway-crash.json.
32.2.5 malda cron
Gestisce i job pianificati memorizzati in ~/.malda/cron.json. I job possono girare tramite lo scheduler del gateway, malda cron install (Windows Task Scheduler) o il cron di sistema.
malda cron add --name <name> --message <message> --cron <cron-expr> [--scope <scope>]— Aggiunge un job. Lo scope di default ècron:<name>, così i turni pianificati usano fatti GraphMemory isolati.malda cron list— Elenca tutti i job (id, name, scope, message, cron).malda cron remove <job-id>— Rimuove il job con l'id dato.malda cron install— Su Windows, sincronizza i job con Task Scheduler conMALDA_MEMORY_SCOPEimpostato per job.
32.3 File di config (~/.malda/config.json)
Opzionale. L'assistente e alcuni built-in leggono la config prima dalla directory corrente (./.malda/config.json), poi dalla directory utente (~/.malda/config.json).
Struttura minima (solo OpenRouter):
{
"providers": { "openrouter": { "apiKey": "sk-..." } },
"agents": { "defaults": { "model": "anthropic/claude-sonnet" } },
"tools": { "web": { "search": { "apiKey": "BSA-..." } } }
}
providers.openrouter.apiKey— Usata dall'assistente di default quandoOPENROUTER_API_KEYnon è impostata.agents.defaults.model— Modello LLM di default per l'assistente (es.anthropic/claude-sonnet).tools.web.search.apiKey— API key di Brave Search, così l'assistente può usare il tool di ricerca web quando lo aggiungi.
Negli script MALDA, usa getMaldaConfig() per leggere questa config come oggetto (oppure null se il file manca). Vedi Funzioni built-in per getMaldaHome() e getMaldaConfig().
32.3.1 Schema agents.memory
L'assistente legge agents.memory per il comportamento di GraphMemory (embedding, reflection, indicizzazione KB e retention).
{
"agents": {
"memory": {
"embed": "hash",
"modelPath": "",
"pruneEpisodicAfterDays": 30,
"consolidateMinEpisodic": 3,
"maxNodes": 5000,
"reflectEnabled": false,
"reflectMinEpisodic": 3,
"reflectEveryNSaves": 1,
"reflectModel": "",
"reflectMinConfidence": 0.7,
"kbDir": "",
"kbPattern": "**/*.md",
"scopeParent": "project:myapp",
"scopeHierarchy": ["project:myapp", "org:acme", "global"],
"rerankMode": "onnx",
"rerankModelPath": "~/.malda/models/cross-encoder"
}
}
}
scopeParent- Un unico scope padre nella gerarchia di memoria (es.chat:123→project:myapp→global). Applicato tramiteagent.setMemoryScopeParent()quandoscopeHierarchynon è impostato.scopeHierarchy- Scope a più livelli tra lo scope attivo eglobal, es.["project:myapp", "org:acme", "global"]. L'assistente antepone a runtime lo scope attivo (chat:{id}su Telegram). SovrascrivescopeParent. Alternativa da env:MALDA_MEMORY_SCOPE_HIERARCHY(elenco separato da virgole o array JSON).rerankEnabled,rerankMode,rerankModelPath,rerankTopK- Applicati a ogni query di memoria dithink()tramiteagent.setMemoryRerank(). UsarerankMode: onnxcon una directory che contienemodel.onnxevocab.txt, oppurecrossper un rerank euristico locale.embed-hash(default),bowollama.modelPath- Path del modello di embedding usato quandoembed = "llama".pruneEpisodicAfterDays,consolidateMinEpisodic,maxNodes- Limiti di manutenzione per la retention episodica e la crescita della memoria.reflectEnabled,reflectMinEpisodic,reflectEveryNSaves,reflectModel,reflectMinConfidence- Pianificazione della reflection e controlli di qualità.kbDir,kbPattern- Directory/pattern opzionali della knowledge base, reindicizzati conreindexDocuments(..., { changedOnly: true }).MALDA_MEMORY_REFLECT=1forza la modalità reflection;MALDA_MEMORY_REFLECT_MIN_CONFIDENCEsovrascrivereflectMinConfidence.
32.4 Scegliere OpenRouter vs llama.cpp locale
L'assistente di default può usare OpenRouter (remoto) oppure un modello locale basato su llama.cpp. Il backend è controllato da agents.defaults.backend in config.json e può essere sovrascritto per esecuzione con MALDA_AGENT_BACKEND o un flag CLI.
Struttura estesa:
{
"providers": {
"openrouter": {
"apiKey": "sk-...",
"model": "anthropic/claude-sonnet"
},
"local_llama": {
"modelPath": "C:/Users/YourName/AppData/Local/MaldaLang/Models/default/qwen2.5-0.5b-instruct-q4_k_m.gguf",
"contextLength": 4096,
"gpuLayers": 0,
"temperature": 0.7,
"maxTokens": 2000
}
},
"agents": {
"defaults": {
"backend": "openrouter", // or "local-llama"
"model": "anthropic/claude-sonnet"
}
},
"tools": { "web": { "search": { "apiKey": "BSA-..." } } }
}
agents.defaults.backend—"openrouter"(default) o"local-llama". Controlla quale client LLM usa l'assistente di default.providers.openrouter.model— Override opzionale per il nome del modello OpenRouter. Se impostato, prevale suagents.defaults.modelper l'assistente di default.providers.local_llama.modelPath— Path a un file di modello GGUF locale usato daLlamaCppClient. Obbligatorio quandobackend = "local-llama".providers.local_llama.contextLength— Dimensione opzionale della context window passata aLlamaCppClient.providers.local_llama.temperature,maxTokens,gpuLayers— Parametri di tuning opzionali applicati tramitesetTemperature(),setMaxTokens()esetGpuLayerCount()sul client locale.MALDA_AGENT_BACKEND— Variabile d'ambiente che sovrascriveagents.defaults.backendper il processo corrente (es.MALDA_AGENT_BACKEND=local-llama).
32.5 Comportamento dell'assistente di default
Lo script dell'assistente di default (es. Examples/Assistant/assistant.malda) fa quanto segue:
- Legge API key e modello di default da
getMaldaConfig()o daOPENROUTER_API_KEY. - Crea un
OpenRouterCliente unAgentcon un system prompt fisso. - Aggiunge il tool di ricerca web (
createWebSearchTool()) se è presente un'API key Brave Search in config o inBRAVE_SEARCH_API_KEY. - Crea un
GraphMemoryconembedHash(384 dimensioni) di default, oppureembedBagOfWords/LlamaEmbedderquando configurato. Inizializza prima diload()così la funzione di embedding sopravvive al reload. Carica da~/.malda/memory/assistantquando presente, collega la memoria conagent.useMemory(memory)e salva dopo ogni turno. - Modalità di embedding:
MALDA_MEMORY_EMBEDoconfig.agents.memory.embed—hash(default),bowollama(richiedeconfig.agents.memory.modelPathoproviders.local_llama.embedModelPath). - Scope di memoria: Telegram imposta
MALDA_CHAT_IDper messaggio; l'agente delimita letture/scritture achat:{id}. Override conMALDA_MEMORY_SCOPEoagent.setMemoryScope(). ImpostaMALDA_MEMORY_SCOPE_PARENT=project:foocosì le query ereditano i fatti a livello di progetto tramitescopeHierarchy. - Manutenzione della memoria a ogni turno:
consolidate()oreflect()(quandoreflectEnabled/MALDA_MEMORY_REFLECT=1),prune()degli episodici consolidati vecchi eenforceLimits()(default 5000 nodi). ConreflectAsync(attivo di default viaMALDA_MEMORY_REFLECT_ASYNC),reflectAsync()gira doposave()così la risposta non viene bloccata. - Backup rotanti su
save()quandoMALDA_MEMORY_BACKUP=trueoconfig.agents.memory.backupEnabled(default 5 snapshot viamaxBackups). - Health check:
memory.validate()omalda memory validate. - Quando è impostato
config.agents.memory.kbDir, l'assistente eseguereindexDocumentsa ogni save e avviamemory.startKbWatch()al lancio (disabilita conMALDA_MEMORY_KB_WATCH=false). - Gli script possono usare
getAssistantMemory()invece del setup manuale diGraphMemoryper il path di default~/.malda/memory/assistant(embed hash/bow viaMALDA_MEMORY_EMBED). - Il retrieval dell'agente usa
hybridLexicalinsieme alla similarity search vettoriale e al re-ranking delle sinapsi per match migliori su nomi, path e ID. - Se è impostato
MALDA_AGENT_MESSAGE(es. damalda agent -m "..."), esegue one-shot e stampa la risposta; altrimenti esegue un loop interattivo.
Puoi sovrascrivere lo script impostando MALDA_AGENT_SCRIPT sul path del tuo file .malda oppure mettendo assistant.malda in ~/.malda/.
32.6 Scheduling su Windows (Task Scheduler)
malda cron add/list/remove memorizzano le definizioni dei job in %USERPROFILE%\.malda\cron.json. MALDA non li esegue da solo, ma su Windows puoi usare malda cron install per creare le attività automaticamente, oppure configurare Task Scheduler a mano.
32.5.0 Installazione automatica (malda cron install)
Per sincronizzare tutti i job da %USERPROFILE%\.malda\cron.json in Windows Task Scheduler, esegui:
malda cron install
Questo comando:
- Legge tutti i job da
%USERPROFILE%\.malda\cron.json. - Rimuove le attività esistenti i cui nomi iniziano con
MALDA_cron_(installazioni precedenti). - Crea un'attività di Task Scheduler per ogni job usando
schtasks, con il trigger daily o weekday appropriato.
Solo un sottoinsieme ridotto di espressioni cron è supportato per il mapping automatico:
| Espressione cron | Significato | Trigger di Task Scheduler |
|---|---|---|
0 9 * * * | 9:00 ogni giorno | /SC DAILY /ST 09:00 |
0 18 * * * | 18:00 ogni giorno | /SC DAILY /ST 18:00 |
0 9 * * 1-5 | 9:00 lun–ven | /SC WEEKLY /D MON,TUE,WED,THU,FRI /ST 09:00 |
Lo scheduler in-process di malda gateway supporta anche intervalli di minuti */N, ore separate da virgola (0 9,18 * * *), mensile (0 9 1 * *) ed espressioni multi-giorno (0 9 * * 1,3,5).
32.5.1 Aggiungere il job in MALDA
Registra il messaggio e la pianificazione così da poter riusare il messaggio quando crei l'attività:
malda cron add --name "daily" --message "Good morning! What's on my calendar today?" --cron "0 9 * * *"
Annota l'id del job e il messaggio esatto; userai lo stesso messaggio nell'attività pianificata.
32.5.2 Trovare malda.exe
Task Scheduler ha bisogno del path completo dell'eseguibile MALDA. Se esegui dal repo con dotnet run, l'eseguibile è sotto l'output del progetto, es.:
MaldaLang\bin\Debug\net8.0\malda.exeoMaldaLang\bin\Release\net8.0\malda.exe(relativo alla root della solution).
Da PowerShell puoi eseguire where.exe malda se malda è nel PATH; altrimenti usa il path sopra. Usa questo path completo come programma nell'attività.
32.5.3 Creare l'attività pianificata (GUI)
- Premi Win + R, digita
taskschd.msc, premi Invio. - Fai clic su Create Task (non “Create Basic Task”, così puoi impostare un trigger giornaliero a un orario preciso).
- Scheda General: dai un nome all'attività (es. “MALDA daily assistant”). Scegli “Run whether user is logged on or not” o “Run only when user is logged on” secondo necessità.
- Scheda Triggers → New: imposta Daily e l'orario (es. 9:00 per il cron
0 9 * * *). - Scheda Actions → New:
- Program/script: path completo a
malda.exe(es.C:\Users\You\Documents\maldalang\MaldaLang\bin\Debug\net8.0\malda.exe). - Add arguments:
agent -m "Good morning! What's on my calendar today?"(usa il messaggio esatto damalda cron add; fai l'escape o usa apici singoli se il messaggio contiene virgolette doppie).
- Program/script: path completo a
- Start in (opzionale): imposta la cartella in cui MALDA può trovare lo script dell'assistente (es. la root del repo così viene trovato
Examples/Assistant/assistant.malda). - Fai clic su OK per salvare. Crea un'attività per ogni messaggio pianificato (es. una per le 9:00, una per le 18:00).
32.5.4 Creare l'attività pianificata (riga di comando)
Usando schtasks per creare un'attività giornaliera alle 9:00:
schtasks /Create /TN "MALDA daily" /TR "\"C:\Path\To\malda.exe\" agent -m \"Good morning! What's on my calendar today?\"" /SC DAILY /ST 09:00 /RU "%USERNAME%"
Sostituisci C:\Path\To\malda.exe con il path reale di malda.exe e il messaggio con quello che hai memorizzato in malda cron add. /RU %USERNAME% esegue l'attività come il tuo utente, così può leggere %USERPROFILE%\.malda e la tua config.
32.5.5 Ambiente e API key
L'attività gira in un ambiente pulito. L'assistente ha bisogno di uno tra:
- File di config: esegui
malda onboarde mettiproviders.openrouter.apiKeyin%USERPROFILE%\.malda\config.json(nessuna variabile d'ambiente necessaria per l'attività), oppure - Variabile d'ambiente: imposta
OPENROUTER_API_KEYnelle variabili d'ambiente utente o di sistema (Proprietà di sistema → Variabili d'ambiente) così l'attività la vede quando gira come il tuo utente.
32.5.6 Mapping delle espressioni cron su Task Scheduler
MALDA memorizza le espressioni cron in %USERPROFILE%\.malda\cron.json e non le esegue direttamente. Puoi lasciare che malda cron install mappi automaticamente i pattern supportati sui trigger di Task Scheduler (vedi sopra), oppure tradurli a mano quando crei le attività tu stesso:
| Espressione cron | Significato | Task Scheduler |
|---|---|---|
0 9 * * * | 9:00 ogni giorno | Trigger: Daily, 9:00 AM |
0 18 * * * | 18:00 ogni giorno | Trigger: Daily, 18:00 |
0 9 * * 1-5 | 9:00 lun–ven | Trigger: Daily, 9:00 AM, repeat weekly Mon–Fri (oppure usa “Weekdays”) |
Usa malda cron add per definire ed elencare i job, poi esegui malda cron install (Windows) oppure configura lo scheduler di sistema per eseguire malda agent -m "message" agli orari corrispondenti.
32.7 Skill
Le skill sono file MALDA in ~/.malda/skills/ che esportano tool (e opzionalmente un agent) per l'assistente. Puoi caricarle in due modi.
Import statico
Usa using Alias = skills.skillname per caricare ~/.malda/skills/skillname.malda e importarne i global sotto l'alias. Per esempio:
using GithubSkill = skills.github;
// Then: GithubSkill.tools, GithubSkill.agent (if the skill exports them)
Caricamento dinamico
Usa loadSkillsFromDir() per scansionare ~/.malda/skills/*.malda in una sola chiamata, oppure getSkillNames() + loadSkill(name) per un controllo esplicito. Ogni skill caricata è un oggetto con i global del modulo più un campo name; i caricamenti falliti includono una stringa error. L'assistente di default usa loadSkillsFromDir(), aggiunge l'array tools di ogni skill all'agente e registra l'agent di ogni skill tramite addSubAgent quando è presente.
var skills = loadSkillsFromDir();
for (var i = 0; i < skills.length; i++) {
var s = skills[i];
if (s.error != null && s.error != "") continue;
if (s.tools != null) {
for (var j = 0; j < s.tools.length; j++) agent.addTool(s.tools[j]);
}
if (s.agent != null) {
var desc = s.agentDescription != null && s.agentDescription != ""
? s.agentDescription : "Delegates to the " + s.name + " skill specialist.";
agent.addSubAgent(s.agent, desc);
}
}
Convenzione del file skill
Un file skill dovrebbe esportare almeno un array tools. Opzionalmente esporta agent (un'istanza Agent) e agentDescription (descrizione del tool mostrata all'orchestratore). malda onboard installa un template funzionante in ~/.malda/skills/greeting.malda (tool + sub-agent). Esempio:
// ~/.malda/skills/greeting.malda (installed by malda onboard)
@Tool("greet_user", "Greets someone by name", "...")
function greetUserTool(args) { ... }
var tools = ["greet_user"];
var agentDescription = "Greets users by name.";
var agent = new Agent("GreetingSkill", "specialist", "...", skillClient);
agent.addTool("greet_user");
Metti altri file .malda in ~/.malda/skills/. L'assistente li scopre e li carica automaticamente quando usi lo script di default. Esegui malda doctor per validare la sintassi delle skill.
32.8 Canali / Telegram
Puoi eseguire l'assistente su un canale così comunica con gli utenti tramite un trasporto esterno. Si usa lo stesso script dell'assistente; l'host inietta un canale che fornisce l'input (es. da Telegram) e rimanda l'output di print() su quel canale.
Eseguire su Telegram
Per eseguire l'assistente come bot Telegram:
- Crea un bot con BotFather e ottieni il token del bot.
- Imposta il token tramite
TELEGRAM_BOT_TOKENoppure in~/.malda/config.jsonsottochannels.telegram.botToken. - Esegui
malda agent -c telegramomalda agent --channel telegram.
Il processo resta in esecuzione e usa il long polling per ricevere i messaggi. Ogni messaggio che invii al bot viene passato all'assistente come input(); la risposta dell'assistente (da print()) viene rimandata alla stessa chat. Si usano lo stesso script (assistant.malda) e la stessa config (API key, modello, tool, memoria) della console; cambiano solo la fonte dell'input e la destinazione dell'output.
Esempio di config
{
"providers": { "openrouter": { "apiKey": "sk-..." } },
"agents": { "defaults": { "model": "anthropic/claude-sonnet" } },
"channels": { "telegram": { "botToken": "123456:ABC-DEF..." } }
}
Se il token manca quando esegui malda agent -c telegram o malda gateway, la CLI stampa un errore ed esce. Ogni chat Telegram ottiene il proprio scope di memoria (chat:{id}); le memorie globali (senza scope) restano visibili in ogni chat. Per un bot persistente con job pianificati, preferisci malda gateway a malda agent -c telegram.
Vedi anche
- 13. Funzioni built-in —
getMaldaHome(),getMaldaConfig(),ensureDir(),webSearch() - Orchestrazione di agenti — Agenti, tool e GraphMemory
- Appendice — Riepilogo del riferimento a riga di comando
- 32.7 sopra — Canali / Telegram per
malda agent -c telegram