18. Orchestrazione di agenti
MALDA: The AI-First Programming Language include il supporto nativo e di prima classe all'orchestrazione di agenti come funzionalità del linguaggio. Queste capacità sono integrate direttamente nel linguaggio e rendono MALDA il modo più semplice per costruire agenti AI e workflow di automazione.
18.1 ⚠️ Avvertenza critica su sicurezza e rischi
I sistemi di agenti autonomi con accesso ai tool comportano rischi significativi di sicurezza, safety e operatività. Prima di mettere in produzione agenti con tool, devi comprendere e mitigare questi rischi.
Rischi fondamentali
- Azioni non intenzionali: Gli agenti possono eseguire i tool in modi che non avevi previsto, causando perdita di dati, corruzione del sistema o violazioni di sicurezza.
- Uso improprio dei tool: Gli agenti possono combinare i tool in modi inattesi, aggirando potenzialmente le protezioni o le restrizioni previste.
- Allucinazione dell'LLM: I modelli linguistici possono interpretare male le istruzioni, generare parametri di tool errati o prendere decisioni basate su un ragionamento fallace.
- Esecuzione autonoma: Una volta avviati, gli agenti possono compiere molte azioni senza supervisione umana, amplificando l'impatto di un singolo errore.
- Limitazioni di contesto: Gli agenti operano con un contesto limitato e possono non cogliere le implicazioni complete delle loro azioni.
- Prompt injection: Input malevoli o malformati possono far comportare gli agenti in modi non previsti, fino a eseguire operazioni pericolose.
Scenari di rischio reali
1. Perdita di dati e danni al file system
- Scenario: Un agente incaricato di «pulire i file vecchi» interpreta male l'ambito e cancella file di sistema critici, file di configurazione o intere directory di progetto.
- Esempio: L'agente riceve l'istruzione di «rimuovere i file temporanei» ma cancella
node_modules,.gito i file del codice sorgente, causando una perdita di dati irreversibile. - Impatto: Corruzione del progetto, perdita del lavoro, instabilità del sistema, impossibilità di recuperare senza backup.
2. Esecuzione di codice non autorizzata
- Scenario: Un agente con accesso al tool
run_commandesegue comandi shell malevoli o distruttivi. - Esempio: L'agente interpreta una richiesta dell'utente di «ottimizzare il sistema» ed esegue
rm -rf /(o equivalente),format C:o altri comandi distruttivi. - Impatto: Distruzione completa del sistema, perdita di dati, compromissione della sicurezza, accesso non autorizzato ad altri sistemi.
3. Corruzione del repository Git
- Scenario: Un GitAgent con permessi di push fa accidentalmente un force-push su main/master, sovrascrivendo il codice di produzione o cancellando i branch.
- Esempio: L'agente tenta di «risolvere i conflitti di merge» con un force-push, distruggendo la cronologia dei commit e causando un'interruzione per tutto il team.
- Impatto: Perdita della cronologia delle versioni, deployment interrotti, calo di produttività del team, possibile perdita di dati se i backup non bastano.
4. Accesso non autorizzato e divulgazione di informazioni
- Scenario: Un agente con accesso in lettura ai file legge file sensibili (API key, password, dati personali) e li include nelle risposte o nei log.
- Esempio: L'agente legge file
.env, file di configurazione che contengono secret o dati privati degli utenti e li espone nella cronologia della conversazione o nei messaggi di errore. - Impatto: Violazione di sicurezza, violazioni della privacy, problemi di conformità normativa, responsabilità finanziaria.
5. Loop infiniti ed esaurimento delle risorse
- Scenario: Un agente entra in un loop infinito di tool call, consumando risorse di sistema a tempo indeterminato.
- Esempio: L'agente legge e scrive ripetutamente lo stesso file, crea strutture di directory ricorsive o effettua chiamate API senza fine, esaurendo CPU, memoria o quote API.
- Impatto: Crash del sistema, indisponibilità del servizio, costi imprevisti (uso delle API), denial of service.
6. Fallimenti a cascata nei sistemi multi-agente
- Scenario: L'errore di un agente innesca una reazione a catena di fallimenti tra più agenti in un sistema gerarchico.
- Esempio: Un agente orchestratore delega un task che porta un subagente a corrompere dei file, e questo fa fallire altri agenti, con danni estesi al sistema.
- Impatto: Danno amplificato, cause radice difficili da tracciare, scenari di recovery complessi.
7. Modifica di sistemi di produzione
- Scenario: Un agente pensato per ambienti di sviluppo viene eseguito per errore contro sistemi di produzione.
- Esempio: L'agente modifica configurazioni del database di produzione, cambia endpoint API live o aggiorna codice di infrastruttura critica senza test adeguati.
- Impatto: Interruzioni di servizio, corruzione dei dati, impatto sui clienti, perdite finanziarie, danno reputazionale.
8. Iniezione di codice malevolo
- Scenario: Un agente scrive codice che include payload malevoli, backdoor o vulnerabilità di sicurezza.
- Esempio: L'agente genera codice con credenziali hardcoded, esegue comandi arbitrari dall'input utente o introduce vulnerabilità di SQL injection.
- Impatto: Vulnerabilità di sicurezza, accesso non autorizzato, data breach, violazioni di conformità.
Strategie di mitigazione
- Sandboxing: Esegui sempre gli agenti in ambienti isolati, con accesso al file system e permessi di rete ristretti.
- Restrizioni sulla directory di lavoro: Usa i parametri di directory di lavoro per limitare le operazioni sui file a directory specifiche e non critiche.
- Human-in-the-loop: Richiedi un'approvazione esplicita per le operazioni distruttive (delete, git push, esecuzione di comandi).
- Filtro dei tool: Fornisci agli agenti solo il set minimo di tool necessario per il task specifico.
- Validazione dell'input: Valida e sanitizza tutti gli input utente prima di passarli agli agenti.
- Rate limiting: Imposta limiti sulla frequenza delle tool call e sul numero totale di operazioni per sessione dell'agente.
- Monitoraggio e logging: Registra tutte le tool call e le decisioni dell'agente per audit trail e debugging.
- Backup e recovery: Mantieni backup regolari e testa le procedure di recovery prima di mettere in produzione gli agenti.
- Testing: Testa a fondo gli agenti in ambienti sicuri e isolati prima dell'uso in produzione.
- Principio del privilegio minimo: Concedi agli agenti solo i permessi minimi richiesti dai loro task.
- Timeout: Imposta tempi massimi di esecuzione per evitare loop infiniti ed esaurimento delle risorse.
- Code review: Revisiona tutto il codice generato dagli agenti prima del deployment, soprattutto per le operazioni sensibili dal punto di vista della sicurezza.
Buone pratiche
- Parti in piccolo: Inizia con operazioni in sola lettura e aggiungi gradualmente le capacità di scrittura solo dopo test approfonditi.
- Usa agenti specializzati: Preferisci agenti specializzati (CodingAgent, GitAgent) con protezioni built-in rispetto a classi Agent generiche con tool senza restrizioni.
- Istruzioni esplicite: Fornisci agli agenti istruzioni chiare e specifiche; evita direttive ambigue o troppo ampie.
- Controllo di versione: Usa sempre il controllo di versione e non consentire mai agli agenti di fare force-push o di modificare branch protetti senza approvazione esplicita.
- Separazione degli ambienti: Mantieni una separazione rigorosa tra ambienti di sviluppo, staging e produzione.
- Audit regolari: Revisiona periodicamente il comportamento degli agenti, i pattern di uso dei tool e le modifiche al sistema.
Usando le funzionalità di orchestrazione di agenti di MALDA, riconosci di comprendere questi rischi e di essere l'unico responsabile delle azioni compiute dagli agenti che crei e metti in produzione. Gli sviluppatori di MALDA e di questo manuale di riferimento non forniscono alcuna garanzia sulla safety, sulla sicurezza o sull'affidabilità dei sistemi di agenti autonomi.
18.2 LLM Client
La classe LLMClient offre un'interfaccia verso API LLM compatibili con OpenAI (OpenAI, OpenRouter, LMStudio, OLLAMA, ecc.).
Costruttore
var client = new LLMClient(apiUrl, apiKey, model);
Metodi
chat(messages, tools)→object: Invia la conversazione all'LLM con definizioni di tool opzionalicomplete(prompt)→string: Invia un singolo prompt e ottiene il completionsetTemperature(temp): Imposta il parametro temperature (da 0.0 a 2.0)setMaxTokens(tokens): Imposta il numero massimo di token nella risposta
Esempio
var apiKey = getEnv("OPENAI_API_KEY");
var client = new LLMClient(
"https://api.openai.com/v1/chat/completions",
apiKey,
"gpt-3.5-turbo"
);
var response = client.complete("Explain quantum computing in one sentence.");
print(response);
18.3 OpenRouterClient
Per OpenRouter in particolare esiste una classe specializzata OpenRouterClient che semplifica la configurazione.
Costruttore
// With default model (deepseek/deepseek-v4-flash)
var client = new OpenRouterClient();
// With custom model
var client = new OpenRouterClient("openai/gpt-4");
OPENROUTER_API_KEY e usa l'endpoint OpenRouter corretto.
Attribuzione dell'app (analytics OpenRouter)
Imposta queste proprietà così OpenRouter può attribuire l'uso dei token a ciascuna delle tue app
(App Attribution). Usa un URL
httpReferer distinto per applicazione. Le analytics appaiono su
https://openrouter.ai/apps?url=<your-url>.
var client = new OpenRouterClient();
client.httpReferer = "https://example.com/secondbrain"; // HTTP-Referer (required for attribution)
client.appTitle = "Second Brain ASK"; // X-OpenRouter-Title
client.appCategories = "cli-agent"; // optional X-OpenRouter-Categories
18.3.1 LLM locale di default (quando non si passa un client)
Quando crei un agente, un prompt o usi built-in come decomposeTask senza passare un client LLM, MALDA usa un LLM locale di default: Qwen/Qwen2.5-0.5B-Instruct, scaricato come build GGUF qwen2.5-0.5b-instruct-q4_k_m.gguf da Hugging Face al primo uso. Il modello viene messo in cache nel profilo utente (es. %LOCALAPPDATA%\MaldaLang\Models\default su Windows). Dopo il primo download non servono API key né rete. Per usare invece un modello remoto, passa esplicitamente un OpenRouterClient, un LLMClient o un LlamaCppClient.
Puoi sovrascrivere il modello di default con la variabile d'ambiente MALDA_DEFAULT_LOCAL_MODEL. Impostala a modelId/fileName.gguf (es. org/repo/MyModel-Q4_K_M.gguf) per usare un altro modello GGUF di Hugging Face; quel modello verrà scaricato e messo in cache in una sottocartella con il nome del model ID. Se non è impostata, si usa la build GGUF built-in di default Qwen/Qwen2.5-0.5B-Instruct.
18.4 LlamaCppClient
La classe LlamaCppClient abilita l'inferenza LLM locale usando LLAMA.cpp con modelli in formato GGUF. Non servono API key né connessione di rete. Se ometti modelPath, MALDA usa il modello GGUF locale di default Qwen/Qwen2.5-0.5B-Instruct e lo scarica automaticamente al primo uso.
Costruttore
var client = new LlamaCppClient(modelPath); // Custom GGUF file
var client = new LlamaCppClient(); // Default auto-downloaded local model
Esempio
var client = new LlamaCppClient();
client.setTemperature(0.7);
client.setMaxTokens(2000);
client.setGpuLayerCount(35); // Offload layers to GPU (optional)
var conversation = new Conversation(client, "You are a helpful assistant.");
conversation.addUserMessage("Explain quantum computing.");
var response = conversation.send();
print(response.content);
18.5 Gestione delle conversazioni
La classe Conversation gestisce conversazioni multi-turno con gli LLM, inclusa la gestione automatica delle tool call.
Costruttore
var conversation = new Conversation(client, systemPrompt);
Metodi
addUserMessage(content): Aggiunge un messaggio utenteaddAssistantMessage(content): Aggiunge un messaggio dell'assistenteaddTool(tool): Aggiunge una definizione di tool per il function callingsend()→object: Invia la conversazione e ottiene la risposta (gestisce automaticamente le tool call)getMessages()→array: Ottiene tutti i messaggiclear(): Svuota la cronologia della conversazione
Esempio
var conversation = new Conversation(client, "You are a helpful assistant.");
conversation.addUserMessage("What is 2+2?");
var response = conversation.send();
print(response.content);
Tool call in sola lettura in parallelo
Quando l'LLM restituisce più tool call in sola lettura in una singola risposta, Conversation le esegue in parallelo di default. Vale per tutti gli agenti (Agent, DevAgent, loop Ralph Wiggum, chat dell'IDE) perché condividono lo stesso runtime.
Tool built-in sicuri in parallelo: read_file, grep, list_directory, get_symbols, get_parse_errors, web_search, recall_progress e i tool git in sola lettura (git_status, git_log, git_diff, git_branch).
Sempre sequenziali: scritture su file, mutazioni git, run_command, ask_user, remember_progress, tool MCP, wrapper agente-come-tool e handler @Tool personalizzati. Un tool che muta in mezzo a un batch spezza l'esecuzione così l'ordine resta sicuro.
I messaggi di risultato dei tool vengono accodati nello stesso ordine dell'array originale tool_calls prima della richiesta LLM successiva.
Configurazione: l'esecuzione in parallelo è attiva quando MALDA_PARALLEL_TOOL_CALLS non è impostata. Imposta MALDA_PARALLEL_TOOL_CALLS=false (oppure 0, off) per disabilitarla. Con il logging verbose (MALDA_RALPH_VERBOSE o MALDA_AGENT_VERBOSE), i batch paralleli vengono registrati esplicitamente.
Logging verbose, feedback di thinking e streaming LLM
Durante agent.think() (e qualsiasi percorso di codice che usa Conversation.send()), il runtime può stampare i progressi in tempo reale sulla console:
[llm] round N— ogni round di richiesta/risposta LLM (riepilogo delle tool call o dimensione della risposta finale)[think]— testo di ragionamento o pianificazione nativo del modello prima delle tool call[tool]— esecuzioni dei tool (compatte di default)
I client LLM HTTP (LLMClient, OpenRouterClient) usano lo streaming SSE in stile OpenAI (stream: true) di default. Quando logging verbose e output di thinking sono abilitati, il testo [think] viene scritto token per token man mano che arrivano i delta. Il JSON delle tool call viene accumulato in silenzio durante lo stream; i nomi dei tool vengono registrati a stream completato.
Oggi non in streaming: LlamaCppClient, backend bridge e richieste con response_format strutturato (in quei casi si torna a una singola risposta bloccante).
| Variabile | Predefinito | Scopo |
|---|---|---|
MALDA_AGENT_VERBOSE | false (Ralph: true) | Abilita il logging [llm] / [tool] |
MALDA_RALPH_VERBOSE | — | Alias di MALDA_AGENT_VERBOSE |
MALDA_AGENT_RICH | true | Output colorato Spectre.Console (si disattiva automaticamente se reindirizzato) |
MALDA_AGENT_TOOL_DETAIL | compact | Log dei tool compact o full |
MALDA_AGENT_LLM_THINKING | compact | Output [think]: off, compact o full |
MALDA_AGENT_LLM_STREAM | true | Streaming SSE OpenAI per i client HTTP; [think] in tempo reale quando il thinking è abilitato |
MALDA_AGENT_LLM_PREVIEW | compact | Anteprima della risposta finale quando streaming/thinking sono disattivati |
MALDA_AGENT_STATUS_EVERY | 4 | Ripete il banner di stato ogni N round LLM (Ralph) |
MALDA_RALPH_* | — | Alias delle impostazioni agente sopra nelle esecuzioni Ralph |
Le stesse diagnostiche si possono attivare dal codice. Questi helper cambiano solo la presentazione e non modificano mai il risultato di un agente:
enableAgentVerboseLogging(enabled?)— attiva o disattiva il logging verbose della conversazione. Chiamato senza argomenti abilita il logging e restituiscetrue.setAgentVerbosePhase(phase)— etichetta la fase mostrata accanto all'output verbose, per esempio"planning"o"review".setAgentStatusBanner(banner)— imposta il testo del banner visualizzato sopra l'output di progresso dell'agente.
enableAgentVerboseLogging();
setAgentStatusBanner("Nightly refactor run");
setAgentVerbosePhase("planning");
18.6 Sistema di tool
I tool consentono agli LLM di chiamare funzioni durante le conversazioni. Si definiscono con la classe Tool e seguono il formato di function calling di OpenAI.
Funzioni di creazione dei tool built-in
createReadFileTool(workingDirectory?)→ToolcreateWriteFileTool(workingDirectory?)→ToolcreateReplaceInFileTool(workingDirectory?)→Tool- Sostituzione singolacreateEditFileTool(workingDirectory?)→Tool- Sostituzioni multiplecreateInsertAtLineTool(workingDirectory?)→ToolcreateGrepTool(workingDirectory?)→ToolcreateListDirectoryTool(workingDirectory?)→ToolcreateAskUserTool()→ToolcreateGitStatusTool(workingDirectory?)→ToolcreateGitAddTool(workingDirectory?)→ToolcreateGitCommitTool(workingDirectory?)→ToolcreateGitLogTool(workingDirectory?)→ToolcreateGitDiffTool(workingDirectory?)→ToolcreateGitBranchTool(workingDirectory?)→ToolcreateGitCheckoutTool(workingDirectory?)→ToolcreateGitPushTool(workingDirectory?)→ToolcreateGitPullTool(workingDirectory?)→ToolcreateRunCommandTool(workingDirectory?)→Tool- Esegue comandi shell (es.dotnet,npm,python) con controlli di safety. Parametri:command(string),args(array di string, opzionale),workingDirectory(opzionale),timeoutMs(opzionale). Restituisce un oggetto conexitCode,stdoutestderr.createRunMALDATool(workingDirectory?)→Tool- Esegue codice MALDA da un path di file o da una stringa sorgente. Parametri:sourceOrFilePath(string),input(string opzionale per stdin). Restituisce un oggetto consuccess(boolean),output(string),error(string per errori di parse) e, opzionale,runtimeError(string).createCompileMALDATool(workingDirectory?)→Tool- Compila il codice sorgente MALDA in un eseguibile. Parametri:sourcePath(string),outputPath(string opzionale),mode(opzionale:"interpreter"|"transpile"). Restituisce un oggetto consuccess(boolean),outputPath(string o null),error(string) eerrors(array di oggetti errore).createGetSymbolsTool(workingDirectory?)→Tool- Estrae classi, funzioni, actor e prompt da un filecreateGetParseErrorsTool(workingDirectory?)→Tool- Valida la sintassi senza eseguire il filecreateWebSearchTool()→Tool- Brave Search API (nessuna directory di lavoro)createGlobTool(workingDirectory?)→Tool- Ricerca di path basata su pattern. Solo sull'interprete; non disponibile negli eseguibili transpilecreateCreateMcpAgentScriptTool(workingDirectory?)→Tool- Genera script di agenti MCPcreateSubmitPlanTool()→Tool- Invia un piano strutturato (step conid,description,dependsOnopzionale). Parametri:plan(oggetto consteps) oppuresteps(array),taskSummaryopzionale. Restituisce{ accepted: true, planId, stepCount }oppure{ accepted: false, error }. Nessuna directory di lavoro.
Tutte queste factory accettano una workingDirectory opzionale, tranne createSubmitPlanTool, createAskUserTool e createWebSearchTool. Quando una directory è impostata, le operazioni su file e path restano al suo interno e nelle sue sottodirectory.
Esempio
var workingDir = ".";
var readTool = createReadFileTool(workingDir);
var writeTool = createWriteFileTool(workingDir);
conversation.addTool(readTool);
conversation.addTool(writeTool);
conversation.addUserMessage("Read example.txt and summarize it.");
var response = conversation.send(); // LLM will call read_file tool automatically
18.7 Classe Agent
La classe Agent rappresenta un agente autonomo con un ruolo e delle istruzioni specifici.
Costruttore
// With default local LLM (auto-download from Hugging Face)
var agent = new Agent(name, role, instructions);
// With a custom client
var agent = new Agent(name, role, instructions, client);
Metodi
think(prompt)→object: Elabora un prompt e restituisce la risposta (gestisce automaticamente le tool call)addTool(tool)oppureaddTool(toolName): Aggiunge un tool che l'agente può usareaddToolByName(toolName): Aggiunge un tool registrato per nomeaddAllTools(): Aggiunge all'agente tutti i tool registratiaddSubAgent(subAgent, toolDescription): Aggiunge un altro agente come tool, con una descrizione semplificatagetAvailableTools()→array: Ottiene l'elenco dei nomi dei tool disponibiligetConversation()→Conversation: Ottiene l'oggetto conversazione dell'agentereset(): Azzera la cronologia della conversazione dell'agente (i tool restano)enableMemory(),enableMemory(path),useMemory(memory),saveMemory(path?),remember(fact, context?),getMemory(): Integrazione GraphMemory (vedi 19. GraphMemory).enableMemory(path)condivide una sola istanza GraphMemory tra gli agenti che usano lo stesso path.setMemoryScope(scope),setMemoryScopeParent(parentScope),setMemoryScopeHierarchy(scopes): Controllano la visibilità gerarchica della memoria durantethink()(es.chat:123→project:foo→org:acme→global). UsasetMemoryScopeHierarchyper una configurazione a più livelli; altrimenti lo scope padre torna aMALDA_MEMORY_SCOPE_PARENT.setMemoryRerank(enabled, mode?, modelPath?, topK?): Abilita il rerank di GraphMemory durante le query di memoria inthink()(rerankMode:llm,crossoonnx). Fallback da env:MALDA_MEMORY_RERANK,MALDA_MEMORY_RERANK_MODE,MALDA_MEMORY_RERANK_MODEL_PATH.setAutoRememberOnThink(enabled): Quando ètrue, ognithink()memorizza il prompt e la risposta completi (defaulttrue)addMemoryProgressTools(): Aggiunge i toolremember_progresserecall_progressper note esplicite controllate dall'LLM
Esempio
var client = new OpenRouterClient();
var agent = new Agent(
"CodeMaster",
"senior software engineer",
"You write clean, efficient code. Always include comments and error handling.",
client
);
agent.addTool(createReadFileTool("."));
agent.addTool(createWriteFileTool("."));
var response = agent.think("Read example.txt and add a comment to the add function.");
print(response.content);
18.8 Tool personalizzati con il decoratore @Tool
schema e validate() prima degli effetti collaterali. Marca gli helper di normalize/derive con @pure() e gli handler impuri con @effects(...). Golden offline: Examples/Agents/agent_governance_golden.malda (vedi anche 9.7 Decoratori).
MALDA consente di definire tool personalizzati per gli LLM usando il decoratore @Tool sulle funzioni.
Sintassi del decoratore
@Tool(name, description, schema?)
Esempio
@Tool("calculate_sum", "Adds two numbers together")
function calculateSum(a, b) {
return int(a) + int(b);
}
var agent = new Agent("Assistant", "Helper", "You are helpful", client);
agent.addTool("calculate_sum");
var response = agent.think("What is 15 + 27?");
print(response.content);
Costruire un tool con new Tool
Puoi anche costruire un'istanza Tool a runtime e passarle una funzione handler. Il pattern usuale è un singolo parametro args (l'oggetto argomenti dell'LLM). Chiama tool.execute(args) per invocare l'handler direttamente, oppure agent.addTool(tool) per i loop dell'agente.
function echoHandler(args) {
return "got " + string(args.message);
}
var echoTool = new Tool(
"echo_message",
"Echoes a message back",
{
"type": "object",
"properties": {
"message": { "type": "string", "description": "Text to echo" }
},
"required": ["message"]
},
echoHandler
);
print(echoTool.execute({ "message": "hello" })); // got hello
agent.addTool(echoTool);
Vedi Examples/Agents/secondbrain_semantic.malda (find_related_notes) per un esempio basato su GraphMemory usato in ASK quando i tool sono abilitati.
18.9 CodingAgent
La classe CodingAgent è un agente specializzato per i task di coding che include automaticamente tutti i tool di operazione sui file.
Tool inclusi
CodingAgent include automaticamente i seguenti tool di operazione sui file e il tool di esecuzione comandi:
read_file- Legge il contenuto dei filewrite_file- Scrive contenuto sui filereplace_in_file- Sostituisce testo nei file (sostituzione singola)edit_file- Applica più modifiche a un file (sostituzioni multiple)insert_at_line- Inserisce contenuto a numeri di riga specificigrep- Cerca pattern nei filelist_directory- Elenca il contenuto delle directoryrun_command- Esegue comandi shell (es.dotnet,npm,python) con controlli di safety per impedire comandi pericolosi
Costruttore
// Simplest form - uses default local LLM (auto-download from Hugging Face)
var agent = new CodingAgent(name, role, instructions);
// With custom working directory
var agent = new CodingAgent(name, role, instructions, workingDirectory);
// With custom client
var agent = new CodingAgent(name, role, instructions, client);
// With custom client and working directory
var agent = new CodingAgent(name, role, instructions, client, workingDirectory);
Esempio
var coderAgent = new CodingAgent(
"CodeMaster",
"senior software engineer",
"You write clean, efficient code."
);
// Agent already has all file tools - ready to use!
var response = coderAgent.think("Read example.txt and add error handling.");
print(response.content);
18.10 GitAgent
La classe GitAgent è un agente specializzato per le operazioni git che include automaticamente tutti i tool git.
Tool inclusi
GitAgent include automaticamente i seguenti tool di operazione git:
git_status- Controlla lo stato del repositorygit_add- Mette in stage i filegit_commit- Crea i commitgit_log- Visualizza la cronologia dei commitgit_diff- Visualizza le modifichegit_branch- Gestisce i branch (solo elenco/creazione - la cancellazione è disabilitata per safety)git_checkout- Cambia branchgit_push- Fa push sul remotegit_pull- Fa pull dal remote
Costruttore
// Simplest form - uses default local LLM (auto-download from Hugging Face)
var agent = new GitAgent(name, role, instructions);
// With custom working directory
var agent = new GitAgent(name, role, instructions, workingDirectory);
// With custom client
var agent = new GitAgent(name, role, instructions, client);
// With custom client and working directory
var agent = new GitAgent(name, role, instructions, client, workingDirectory);
Esempio
var gitAgent = new GitAgent(
"GitHelper",
"git assistant",
"You help manage git repositories."
);
// Agent already has all git tools - ready to use!
var response = gitAgent.think("Check git status, stage all changes, and commit with message 'Update code'");
print(response.content);
18.11 HumanAgent
La classe HumanAgent è un agente specializzato per l'interazione umana che include automaticamente il tool ask_user. Così è semplice creare agenti che devono interagire con le persone per chiarimenti, conferme o informazioni aggiuntive.
Tool inclusi
HumanAgent include automaticamente il seguente tool di interazione con l'utente:
ask_user- Pone domande all'utente per chiarimenti, conferme o informazioni aggiuntive
Costruttore
// Simplest form - uses default local LLM (auto-download from Hugging Face)
var agent = new HumanAgent(name, role, instructions);
// With custom working directory
var agent = new HumanAgent(name, role, instructions, workingDirectory);
// With custom client
var agent = new HumanAgent(name, role, instructions, client);
// With custom client and working directory
var agent = new HumanAgent(name, role, instructions, client, workingDirectory);
Esempio
// Simplest usage - HumanAgent uses default local LLM
var humanAgent = new HumanAgent(
"Assistant",
"helpful assistant",
"You help users by asking clarifying questions when needed."
);
// Agent already has ask_user tool - ready to use!
var response = humanAgent.think("Ask the user what their favorite programming language is, then provide a brief explanation of that language.");
print(response.content);
Usare HumanAgent come subagente (pattern human-in-the-loop)
Uno dei casi d'uso principali di HumanAgent è come subagente in workflow multi-agente complessi. Questo abilita i pattern human-in-the-loop, in cui gli agenti orchestratori possono delegare i task di interazione umana a un HumanAgent specializzato.
var client = new OpenRouterClient();
// Create a HumanAgent for user interaction
var humanAgent = new HumanAgent(
"HumanInterface",
"user interaction specialist",
"You handle all interactions with human users. " +
"Ask clear, concise questions when clarification is needed. " +
"Request approval before making destructive changes.",
client
);
// Create an orchestrator that can delegate to specialists
var orchestrator = new CodingAgent(
"Orchestrator",
"project coordinator",
"You coordinate code changes. " +
"When you need user approval or clarification, use the HumanInterface tool. " +
"Always ask for confirmation before deleting files or making breaking changes.",
client
);
// Add HumanAgent as a subagent
orchestrator.addSubAgent(
humanAgent,
"Handles user interaction, clarification requests, and approval confirmations. " +
"Use this when you need to ask the user a question or get their approval."
);
// Now orchestrator can automatically request human input when needed
var response = orchestrator.think(
"Refactor the codebase to use dependency injection. " +
"Ask the user which design pattern they prefer before proceeding."
);
Vantaggi del pattern human-in-the-loop:
- Safety: Gli orchestratori possono chiedere approvazione prima delle operazioni distruttive
- Chiarimento: Gli agenti possono chiedere le informazioni mancanti invece di indovinare
- Flessibilità: I workflow complessi possono mettersi in pausa per una decisione umana
- Separazione delle responsabilità: La logica di interazione umana è isolata nel HumanAgent
- Riuso: Lo stesso HumanAgent può essere usato da più orchestratori
18.12 DevAgent
La classe DevAgent è un agente specializzato per i workflow di sviluppo completi che include automaticamente tutti i tool di operazione sui file, i tool git, i tool di esecuzione comandi e, in opzione, i tool di analisi del codice.
Tool inclusi
DevAgent include automaticamente i seguenti tool:
- Tool sui file:
read_file,write_file,replace_in_file,insert_at_line,edit_file,grep,list_directory - Tool git:
git_status,git_add,git_commit,git_log,git_diff,git_branch,git_checkout,git_push,git_pull - Tool di esecuzione:
run_command - Tool di interazione:
ask_user - Pianificazione strutturata dei task:
submit_plan- Gli agenti possono inviare un piano (step conid,description,dependsOnopzionale) prima o durante l'esecuzione. - Analisi opzionale:
get_symbols(quandoincludeSymbolsè true)
Costruttore
// Simplest form - uses default local LLM (auto-download from Hugging Face)
var agent = new DevAgent(name, role, instructions);
// With custom working directory
var agent = new DevAgent(name, role, instructions, workingDirectory);
// With custom client
var agent = new DevAgent(name, role, instructions, client);
// With custom client and working directory
var agent = new DevAgent(name, role, instructions, client, workingDirectory);
// With includeSymbols enabled (for code analysis)
var agent = new DevAgent(name, role, instructions, client, workingDirectory, true);
Esempio
// Simplest usage - DevAgent uses default local LLM
var devAgent = new DevAgent(
"DevMaster",
"senior developer",
"You write, test, compile, and commit code."
);
// Agent already has all development tools - ready to use!
// Can handle full workflow: edit, test, commit
var response = devAgent.think("Read example.txt, add error handling, and commit the changes");
print(response.content);
Esempio con analisi del codice
// DevAgent with getSymbols enabled for better code understanding
var devAgent = new DevAgent(
"CodeAnalyzer",
"code refactoring expert",
"You analyze code structure and make targeted improvements.",
null, // default client
".", // working directory
true // includeSymbols - enables get_symbols tool
);
// Agent can now analyze code structure before making edits
var response = devAgent.think("Analyze the codebase structure and refactor the main function");
print(response.content);
Esempio con client personalizzato
var client = new OpenRouterClient("openai/gpt-4");
var devAgent = new DevAgent(
"FullStackDev",
"full-stack developer",
"You develop complete features: code, test, compile, and commit.",
client,
"./project",
false // includeSymbols
);
// Agent can handle complete development workflow
var response = devAgent.think("Implement a new feature: add a user authentication system");
print(response.content);
18.13 Pianificazione strutturata dei task
MALDA consente di scomporre i task complessi in step ordinati e di eseguirli tramite un agente. Un piano è un oggetto { steps: [{ id, description, dependsOn? }, ...], planId?, taskSummary? }. Ogni step ha un id univoco (string), una description (string) e un dependsOn opzionale (array di id di step che devono completarsi prima).
- decomposeTask(instruction, client?) – Usa un LLM per trasformare un'istruzione di alto livello in un piano. Il secondo argomento opzionale è un client LLM; se omesso, si usa l'LLM locale di default (Qwen/Qwen2.5-0.5B-Instruct, scaricato automaticamente come build GGUF da Hugging Face). Restituisce un oggetto piano oppure
{ error }in caso di fallimento. - executePlan(plan, agent) – Valida il piano, ordina topologicamente gli step in base a
dependsOn, poi esegueagent.think(step.description)per ogni step in ordine. Restituisce{ planId, completed, failed, results }. - tool submit_plan – Gli agenti possono chiamare questo tool per inviare un piano (es. dopo un primo "think" che produce il piano). DevAgent include questo tool di default. Parametri:
plan(oggetto consteps) oppuresteps(array),taskSummaryopzionale. Restituisce{ accepted: true, planId, stepCount }oppure{ accepted: false, error }. - Metadati PromptInstance – Quando chiami
agent.think(promptInstance), i campi opzionalimodel,temperature,maxTokensetools(array di nomi di tool) valgono per quella singola richiesta LLM. - Memoria del codice di DevAgent –
devAgent.enableCodeMemory(path?, scope?)carica GraphMemory in.dev-agent-memorysotto la workdir (di default), imposta lo scopecode:<workdir-name>e registra i toolindex_code_file/find_code_relationships.devAgent.indexCodebase(extensions?)indicizza in blocco i file sorgente (default:.cs,.malda,.js,.ts,.py,.html,.css,.json,.md).
// Decompose then execute from script
var plan = decomposeTask("Add unit tests for getSymbols and run the test suite");
var agent = new DevAgent("Dev", "developer", "You are a developer.", null, ".");
var result = executePlan(plan, agent);
print(result.completed);
print(result.results);
18.14 MALDACodingAgent
La classe MALDACodingAgent è un agente specializzato per lo sviluppo di script MALDA e le operazioni della toolchain che include automaticamente tutti i tool di operazione sui file e i tool di esecuzione/compilazione MALDA.
Tool inclusi
MALDACodingAgent include automaticamente i seguenti tool:
- Tool sui file:
read_file,write_file,replace_in_file,insert_at_line,edit_file,grep,list_directory - Tool MALDA:
run_malda,compile_malda
Costruttore
// Simplest form - uses default local LLM (auto-download from Hugging Face)
var agent = new MALDACodingAgent(name, role, instructions);
// With custom working directory
var agent = new MALDACodingAgent(name, role, instructions, workingDirectory);
// With custom client
var agent = new MALDACodingAgent(name, role, instructions, client);
// With custom client and working directory
var agent = new MALDACodingAgent(name, role, instructions, client, workingDirectory);
Esempio
// Simplest usage - MALDACodingAgent uses default local LLM
var maldaAgent = new MALDACodingAgent(
"MALDADeveloper",
"MALDA script developer",
"You write, test, and compile MALDA scripts. Always verify your changes work by running the code."
);
// Agent already has all MALDA development tools - ready to use!
// Can handle MALDA workflow: edit, run, compile, test
var response = maldaAgent.think("Read example.malda, add error handling, test it with run_malda, and compile it");
print(response.content);
Esempio con client personalizzato
var client = new OpenRouterClient("openai/gpt-4");
var maldaAgent = new MALDACodingAgent(
"MALDAMaster",
"MALDA expert",
"You develop MALDA scripts with best practices and thorough testing.",
client
);
// Agent can handle MALDA development workflow
var response = maldaAgent.think("Create a new MALDA script that calculates fibonacci numbers, test it, and compile it");
Esempio con directory di lavoro
var client = new OpenRouterClient("openai/gpt-4");
var maldaAgent = new MALDACodingAgent(
"MALDAHelper",
"MALDA assistant",
"You help develop and test MALDA scripts.",
client,
"./malda-scripts" // Restrict operations to ./malda-scripts directory
);
// Agent can only access files within ./malda-scripts
var response = maldaAgent.think("List all MALDA files and improve error handling in each one");
Quando usare MALDACodingAgent, DevAgent o CodingAgent
- Usa
MALDACodingAgentquando ti serve lo sviluppo specifico MALDA: operazioni sui file + esecuzione/compilazione MALDA (focalizzato sullo sviluppo di script MALDA) - Usa
DevAgentquando ti serve un workflow di sviluppo completo: operazioni sui file, operazioni git, esecuzione di comandi e interazione con l'utente - Usa
CodingAgentquando ti servono solo operazioni sui file ed esecuzione di comandi (più leggero, meno tool, per task di coding generali) - Usa
GitAgentquando ti servono solo le operazioni git
18.15 Dashboard degli agenti
Gli agenti MALDA segnalano automaticamente le proprie attività a una dashboard centrale senza richiedere alcuna modifica agli script MALDA. Questo abilita monitoraggio e osservabilità su tutti gli agenti, anche quando girano in eseguibili o processi diversi.
Panoramica
La funzionalità dashboard degli agenti offre:
- Segnalazione automatica: Tutti gli agenti segnalano automaticamente eventi di lifecycle, chiamate think() ed esecuzioni di tool
- Zero configurazione: Funziona subito con la dashboard localhost di default
- Supporto cross-process: Gli agenti di eseguibili diversi si distinguono per process ID
- Tolleranza agli errori: I fallimenti della dashboard non influenzano mai l'esecuzione dell'agente
- Non bloccante: Tutta la segnalazione è asincrona e fire-and-forget
Configurazione
L'URL della dashboard si configura con la variabile d'ambiente SPL_AGENT_DASHBOARD_URL:
# Set custom dashboard URL
export SPL_AGENT_DASHBOARD_URL="http://my-dashboard.example.com/api/agent/status"
# If not set, defaults to:
# http://localhost:8080/api/agent/status
Nota: Se la variabile d'ambiente è impostata ma non termina con /api/agent/status, il path dell'endpoint viene accodato automaticamente.
Eventi segnalati
Gli agenti segnalano automaticamente i seguenti eventi:
- Agente creato (
agent_created)- Segnalato quando un agente viene inizializzato
- Include: nome dell'agente, ruolo, process ID, timestamp
- Operazione think (
think)- Segnalata quando viene chiamato
agent.think() - Include: nome dell'agente, prompt (troncato a 500 caratteri), lunghezza del prompt, process ID, timestamp
- Segnalata quando viene chiamato
- Tool call (
tool_call)- Segnalata quando i tool vengono eseguiti
- Include: nome dell'agente, nome del tool, stato di successo, messaggio di errore (se fallita), process ID, timestamp
- Reset dell'agente (
agent_reset)- Segnalato quando viene chiamato
agent.reset() - Include: nome dell'agente, process ID, timestamp
- Segnalato quando viene chiamato
Formato del payload della dashboard
Tutti gli eventi vengono inviati come richieste HTTP POST con payload JSON:
{
"agentId": "MyAgent",
"processId": 12345,
"eventType": "think",
"timestamp": "2026-01-15T10:30:00.123Z",
"data": {
"prompt": "Analyze this code...",
"promptLength": 20
}
}
Campi del payload:
agentId(string): Il nome dell'agenteprocessId(integer): Process ID per distinguere gli agenti di eseguibili diversieventType(string): Tipo di evento (agent_created,think,tool_call,agent_reset)timestamp(string): Timestamp UTC in formato ISO 8601data(object): Dati specifici dell'evento
Dati specifici dell'evento:
- agent_created:
{ "role": "..." } - think:
{ "prompt": "...", "promptLength": 123 } - tool_call:
{ "toolName": "...", "success": true/false, "errorMessage": "..." } - agent_reset:
{}
Requisiti dell'endpoint della dashboard
Il server della dashboard deve implementare un endpoint POST che accetta payload JSON:
- URL: Configurato tramite
SPL_AGENT_DASHBOARD_URL(default:http://localhost:8080/api/agent/status) - Method: POST
- Content-Type:
application/json - Body: Oggetto JSON con le informazioni di stato dell'agente (vedi il formato del payload sopra)
Esempio di server dashboard (MALDA)
var server = new HttpServer(8080);
var agentStatuses = {};
@POST("/api/agent/status")
function receiveAgentStatus(body) {
var agentId = body.agentId;
var processId = body.processId;
var eventType = body.eventType;
var timestamp = body.timestamp;
var data = body.data;
// Store or process agent status
if (agentStatuses[agentId] == null) {
agentStatuses[agentId] = {};
}
agentStatuses[agentId][eventType] = {
"processId": processId,
"timestamp": timestamp,
"data": data
};
return {"status": 200, "message": "Status received"};
}
@GET("/api/agents")
function getAllAgents() {
return {"status": 200, "agents": agentStatuses};
}
@PAGE("/")
function dashboardPage() {
// Generate HTML dashboard showing all agents
return generateDashboardHTML(agentStatuses);
}
server.start();
print("Agent Dashboard running at http://localhost:8080");
Utilizzo
Nessuna modifica agli script MALDA richiesta!
Gli agenti segnalano automaticamente alla dashboard. Crea gli agenti come al solito:
var client = new OpenRouterClient();
var agent = new Agent(
"MyAgent",
"coder",
"You write code.",
client
);
// Agent automatically reports:
// 1. agent_created event when initialized
// 2. think event when think() is called
// 3. tool_call events when tools are executed
// 4. agent_reset event when reset() is called
var response = agent.think("Write a hello world function");
// Dashboard receives think and tool_call events automatically
Gestione degli errori
Il sistema di segnalazione alla dashboard è progettato per essere del tutto non invasivo:
- Fallimenti di rete: Se la dashboard non è raggiungibile, gli agenti continuano a lavorare normalmente
- Protezione da timeout: Le richieste HTTP scadono dopo 2 secondi per evitare di restare in attesa
- Fallimenti silenziosi: Tutti gli errori della dashboard vengono catturati e ignorati: non influenzano mai l'esecuzione dell'agente
- Fire-and-forget: Tutta la segnalazione è asincrona e non bloccante
Vantaggi
- Osservabilità: Monitora tutti gli agenti del sistema in tempo reale
- Debugging: Traccia le attività degli agenti e i pattern di uso dei tool
- Analytics: Raccogli metriche su prestazioni degli agenti e uso dei tool
- Supporto multi-processo: Traccia gli agenti che girano in eseguibili diversi tramite process ID
- Zero overhead: Nessun impatto sulle prestazioni dell'esecuzione dell'agente
18.16 Orchestrazione multi-agente
Più agenti possono lavorare insieme, ciascuno con ruoli e tool specializzati.
Workflow di agenti in parallelo
Gli agenti possono lavorare in modo indipendente su task diversi:
var readerAgent = new Agent("Reader", "file reader", "You read and analyze files.", client);
readerAgent.addTool(createReadFileTool("."));
var editorAgent = new Agent("Editor", "code editor", "You edit code files.", client);
editorAgent.addTool(createReadFileTool("."));
editorAgent.addTool(createReplaceInFileTool("."));
var code = readerAgent.think("Read main.MALDA and summarize it.");
var edited = editorAgent.think("Read main.MALDA and add error handling.");
Sistemi di agenti gerarchici con addSubAgent
Il metodo addSubAgent consente di creare sistemi di agenti gerarchici in cui un agente orchestratore può delegare i task a subagenti specializzati. È utile quando vuoi separare le istruzioni interne dettagliate dalla descrizione del tool mostrata all'orchestratore.
addSubAgent usa una descrizione semplificata e orientata al tool, non le istruzioni interne complete dell'agente, così il contesto dell'orchestratore resta pulito e focalizzato.
Sintassi
orchestrator.addSubAgent(subAgent, toolDescription);
subAgent: Un'istanzaAgentda usare come tooltoolDescription: Una descrizione concisa di ciò che fa il subagente (mostrata all'orchestratore)
Esempio
var client = new OpenRouterClient();
// Create specialized subagents with detailed internal instructions
var codeReviewer = new Agent(
"CodeReviewer",
"code review specialist",
"You are an expert code reviewer. When reviewing code, you should:\n" +
"1. Check for bugs and logical errors\n" +
"2. Review code style and best practices\n" +
"3. Suggest improvements\n" +
"4. Consider performance implications\n" +
"5. Check for security vulnerabilities\n" +
"Provide detailed feedback with line numbers and specific suggestions.",
client
);
var tester = new Agent(
"Tester",
"testing specialist",
"You are an expert in software testing. When asked to write tests:\n" +
"1. Analyze the code to understand what needs to be tested\n" +
"2. Write comprehensive test cases covering edge cases\n" +
"3. Include both positive and negative test cases\n" +
"4. Ensure tests are clear and maintainable\n" +
"5. Consider boundary conditions and error handling",
client
);
// Create orchestrator agent
var orchestrator = new Agent(
"Orchestrator",
"project coordinator",
"You coordinate tasks between specialized agents. " +
"When you need code reviewed, use the CodeReviewer tool. " +
"When you need tests written, use the Tester tool. " +
"Delegate work to the appropriate specialist agent.",
client
);
// Add subagents with simplified, tool-focused descriptions
orchestrator.addSubAgent(
codeReviewer,
"Reviews code for bugs, style issues, and improvements. Provide the code to review as the prompt."
);
orchestrator.addSubAgent(
tester,
"Writes comprehensive test cases for code. Provide the code to test as the prompt."
);
// Orchestrator can now delegate to subagents
var code = "function add(a, b) {\n return a + b;\n}";
var response = orchestrator.think(
"I have this code: " + code + "\n\n" +
"Please have it reviewed and then write tests for it."
);
print(response.content);
Quando l'orchestratore chiama un tool subagente, passa un parametro prompt e il metodo think() del subagente viene chiamato automaticamente. La risposta del subagente torna all'orchestratore.
Vedi anche
- 9. Funzioni - sintassi del decoratore @Tool
- 10. Prompt - Template di prompt e
agent.think - 20. Server MCP - Tool STDIO lanciati dall'host
- 12. Input/Output — i tool sui file consumano
io.*e i token di capability
18.17 Usare gli agenti con gli actor
Agenti e actor sono funzionalità complementari in MALDA. Gli agenti sono classi pensate per interazioni AI sincrone, mentre gli actor offrono elaborazione concorrente basata su messaggi. Combinarli abilita pattern potenti per i sistemi AI distribuiti.
- L'uso più comune degli agenti è sincrono e lineare
- L'esecuzione dei tool è naturalmente sincrona
- Gli agenti si possono memorizzare facilmente nello stato di un actor quando serve la concorrenza
- Così si ha flessibilità senza imporre la complessità degli actor nei casi semplici
Agente come stato dell'actor
Il pattern più comune è memorizzare un'istanza di agente come campo di un actor. Così l'actor può usare le capacità AI mantenendo stato isolato ed elaborazione concorrente:
actor AIAssistant {
var agent;
var conversationHistory = [];
function AIAssistant(client) {
// Create an agent and store it in actor state
agent = new Agent(
"Assistant",
"helpful assistant",
"You help users with their questions.",
client
);
}
on ask(question) {
// Use the agent to process questions
var response = agent.think(question);
append(conversationHistory, question);
append(conversationHistory, response.content);
print(response.content);
}
on getHistory() {
print(conversationHistory);
}
}
// Spawn multiple AI assistants with isolated state
var client = new OpenRouterClient();
var assistant1 = spawn AIAssistant(client);
var assistant2 = spawn AIAssistant(client);
send assistant1.ask("What is 2+2?");
send assistant2.ask("What is the weather?");
Orchestrazione concorrente di agenti
Gli actor abilitano l'elaborazione davvero concorrente di più agenti. Gli agenti sono sincroni, ma avvolgerli in actor consente l'esecuzione in parallelo:
actor CodingAgentActor {
var agent;
var taskQueue = [];
function CodingAgentActor(client, workingDir) {
agent = new CodingAgent(
"Coder",
"software engineer",
"You write clean, efficient code.",
client,
workingDir
);
}
on processTask(task) {
var result = agent.think(task);
print($"Task completed: {result.content}");
}
}
// Spawn multiple coding agents for parallel processing
var client = new OpenRouterClient();
var agent1 = spawn CodingAgentActor(client, "./project1");
var agent2 = spawn CodingAgentActor(client, "./project2");
var agent3 = spawn CodingAgentActor(client, "./project3");
// Send tasks concurrently - all process in parallel
send agent1.processTask("Refactor the user authentication module");
send agent2.processTask("Add error handling to the API");
send agent3.processTask("Write unit tests for the database layer");
Sistema di actor multi-agente
Puoi orchestrare più agenti specializzati all'interno di un singolo actor per creare workflow complessi:
actor AgentOrchestrator {
var coderAgent;
var reviewerAgent;
var testerAgent;
function AgentOrchestrator(client) {
coderAgent = new CodingAgent("Coder", "developer", "Write clean code.", client);
reviewerAgent = new Agent("Reviewer", "code reviewer", "Review code for quality.", client);
testerAgent = new Agent("Tester", "QA engineer", "Write comprehensive tests.", client);
}
on develop(feature) {
// Step 1: Code
var code = coderAgent.think($"Write code for: {feature}");
// Step 2: Review
var review = reviewerAgent.think($"Review this code: {code.content}");
// Step 3: Test
var tests = testerAgent.think($"Write tests for: {code.content}");
return {
"code": code.content,
"review": review.content,
"tests": tests.content
};
}
}
var client = new OpenRouterClient();
var orchestrator = spawn AgentOrchestrator(client);
send orchestrator.develop("User authentication system");
Persistenza dello stato dell'agente tramite actor
Gli actor possono gestire e persistere lo stato della conversazione dell'agente, abilitando sessioni di agente di lunga durata:
actor AgentStateManager {
var agents = {}; // Dictionary of agent instances
var conversations = {}; // Conversation history per agent
on createAgent(name, role, instructions, client) {
var agent = new Agent(name, role, instructions, client);
agents[name] = agent;
conversations[name] = [];
}
on queryAgent(agentName, question) {
if (has(agents, agentName)) {
var agent = agents[agentName];
var response = agent.think(question);
append(conversations[agentName], {
"question": question,
"answer": response.content
});
return response.content;
}
return "Agent not found";
}
on getHistory(agentName) {
return conversations[agentName];
}
}
var client = new OpenRouterClient();
var stateManager = spawn AgentStateManager();
send stateManager.createAgent("Helper", "assistant", "You help users", client);
send stateManager.queryAgent("Helper", "What is MALDA?");
Vantaggi nel combinare agenti e actor
- Concorrenza: Più agenti possono elaborare i task in parallelo senza bloccarsi
- Isolamento dello stato: Ogni actor mantiene la propria istanza di agente e la cronologia della conversazione
- Scalabilità: Puoi fare spawn di molti actor-agente per l'elaborazione AI distribuita
- Tolleranza ai guasti: Se un actor-agente fallisce, gli altri continuano in modo indipendente
- Coordinamento basato su messaggi: Usa il messaging degli actor per coordinare i workflow degli agenti
- Sessioni di lunga durata: Gli actor possono mantenere lo stato dell'agente attraverso più interazioni
Vedi anche
- 17. Actor - Modello ad actor e message passing
- 17.5 Isolamento dello stato degli actor - Capire lo stato degli actor
18.18 Ralph Wiggum (loop autonomo guidato da PRD)
Il repository include Examples/RalphWiggum/RalphWiggum.malda, un loop autonomo pronto per la produzione per lo sviluppo guidato da PRD. Usa DevAgent, un PRD a checklist (PRD.md), validazione post-iterazione, stato di resume e GraphMemory per la continuità tra le iterazioni quando la cronologia della conversazione viene azzerata a ogni round. Vedi Examples/RalphWiggum/README.md per i prerequisiti e la demo Snake.
Esecuzione
dotnet run --project MaldaLang -- Examples/RalphWiggum/RalphWiggum.malda
# Or from a project directory with PRD.md:
# set MALDA_RALPH_WORKDIR=Examples/RalphWiggum/snake-demo
# Examples\RalphWiggum\snake-demo\run-ralph.bat
Artefatti persistiti (nella workdir)
.ralph-state.json— cronologia delle iterazioni, note di validazione, checkpoint di resume (lastSuccessfulIteration,failedIterations, totali dei token quando disponibili).ralph-memory.graph.json,.ralph-memory.metadata.json,.ralph-memory.vectordb.bin— persistenza GraphMemoryralph-run-report.json/ralph-run-report.html— riepilogo dell'esecuzione quandoMALDA_RALPH_REPORTè abilitatoPRD.md— checklist delle funzionalità con[ ],[TODO],[DONE], priorità[P0]opzionale,(depends: …)e righeAcceptance:
Modello di memoria
Ralph collega una GraphMemory condivisa all'agente tramite setupRalphGraphMemory() e:
- Inizializza con
MALDA_MEMORY_EMBED(hash,bowollama) e carica.ralph-memory.*dalla workdir - Definisce lo scope della memoria con
agent.setMemoryScope("ralph:{project}")(override tramiteMALDA_RALPH_MEMORY_SCOPE) - Reindicizza
PRD.mdall'avvio e semina i fatti da.ralph-interview-brief.jsonquando è presente - Esegue
maintainRalphMemory()dopo ogni iterazione:consolidate/reflect,prune,enforceLimits(attivo di default quandoMAX_ITER > 5) - Disabilita di default l'auto-remember del prompt completo (
setAutoRememberOnThink(false)); impostaMALDA_RALPH_AUTO_REMEMBER=trueper ripristinare il comportamento legacy - Registra
remember_progress/recall_progresstramiteaddMemoryProgressTools() - Dopo ogni iterazione, salva un riepilogo strutturato (fase, validazione, file, conteggio tool) con metadati
- Indicizza i file modificati con
memory.analyzeFile()dove applicabile agent.think()inietta memoria ibrida (vettoriale + lessicale + synapse + MMR). Blocco opzionale con scope di fase:MALDA_RALPH_MEMORY_PHASE_QUERY=true- Include
memory.stats()inralph-run-report.jsonquando il reporting è abilitato
Ispeziona la memoria di Ralph dalla workdir: malda memory stats --path .ralph-memory. Vedi Examples/RalphWiggum/README.md per le variabili MALDA_RALPH_MEMORY_*.
Variabili d'ambiente principali
MALDA_RALPH_WORKDIR,MALDA_RALPH_WORKTREE,MALDA_RALPH_PROJECT_REL,MALDA_RALPH_PRD,MALDA_RALPH_MAX_ITER,MALDA_RALPH_TASKMALDA_RALPH_RESET_EACH—true,falseophase(azzera la conversazione quando cambia la fase del PRD; defaulttrue)MALDA_RALPH_RESUME,MALDA_RALPH_RESUME_POLICY(all|success-only),MALDA_RALPH_VALIDATE,MALDA_RALPH_VALIDATE_DEPTH,MALDA_RALPH_VALIDATE_CMDMALDA_RALPH_PRD_STRICT,MALDA_RALPH_REQUIRE_SIGNAL,MALDA_RALPH_PLAN_ONLY,MALDA_RALPH_PREFLIGHTMALDA_RALPH_REPORT,MALDA_RALPH_NOTIFY,MALDA_RALPH_MAX_PHASE_RETRIES,MALDA_RALPH_ABORT_ON_STALLMALDA_RALPH_GIT_COMMIT,MALDA_RALPH_AUTO_REMEMBER(defaultfalse)MALDA_AGENT_THINK_TIMEOUT_MS/MALDA_RALPH_ITER_TIMEOUT_MS— scadenza think per iterazione- CLI verbose:
MALDA_AGENT_VERBOSE(defaulttruein Ralph),MALDA_AGENT_RICH,MALDA_AGENT_LLM_THINKING,MALDA_AGENT_LLM_STREAM— vedi 18.5 logging verbose OPENROUTER_API_KEYoppureproviders.openrouterin~/.malda/config.json
Moduli di implementazione: Examples/RalphWiggum/ralph/*.malda (vedi ralph/ARCHITECTURE.md). Elenco completo delle variabili d'ambiente e workflow git-worktree: Examples/RalphWiggum/README.md.
Segnali di completamento
Ralph accetta TASK_COMPLETE (senza distinzione di maiuscole/minuscole), una riga dedicata RALPH_DONE, JSON {"ralph":"done"}, oppure il completamento automatico quando ogni voce del PRD è [DONE] e la validazione passa (a meno che MALDA_RALPH_REQUIRE_SIGNAL=true).
Hook di validazione personalizzati
Dopo i controlli strutturali, Ralph può eseguire MALDA_RALPH_VALIDATE_CMD, oppure uno script locale del progetto .ralph-validate.sh / .ralph-validate.bat / (o .ralph-validate.malda) nella workdir.
Strategia di esecuzione
Ralph chiede all'agente di completare una voce della checklist PRD per iterazione nel minor numero possibile di round LLM: esplorazione in sola lettura in batch (list_directory, grep, read_file) in una sola risposta, poi modifiche e verifica in batch. Questo si abbina all'esecuzione parallela dei tool in sola lettura (18.5) e al feedback [think] in streaming durante le esecuzioni verbose.
Vedi anche 19. GraphMemory per i metadati di remember, getRecent e le opzioni ibride di query.
reportRalphStatus(agentName, phase, iteration, maxIter, prdPercent, validationOk?, elapsedMs?, promptTokens?, completionTokens?, costUsd?) pubblica una iterazione di progresso sulla dashboard degli agenti. I primi cinque argomenti sono obbligatori; gli altri hanno default false, 0, 0, 0 e 0.0.
reportRalphStatus("Ralph", "implement", 3, 10, 45, true, 12000, 1800, 640, 0.02);