Pyragogy AI Village - Orchestrierungsmeister (Tiefenarchitektur V2)
Dies ist ein Engineering, AI-Bereich Automatisierungsworkflow mit 35 Nodes. Hauptsächlich werden If, Wait, Merge, Slack, Start und andere Nodes verwendet, kombiniert mit KI-Technologie für intelligente Automatisierung. Mit GPT-4o Multi-Agent Orchestrierung und manueller Prüfung Handbücher für die Zusammenarbeit erstellen
- •Slack Bot Token oder Webhook URL
- •GitHub Personal Access Token
- •OpenAI API Key
- •HTTP Webhook-Endpunkt (wird von n8n automatisch generiert)
- •PostgreSQL-Datenbankverbindungsdaten
Verwendete Nodes (35)
Kategorie
{
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Pyragogy AI Village - Orchestrazione Master (Architettura Profonda V2)",
"tags": [
{
"id": "pyragogy",
"name": "Pyragogy"
},
{
"id": "multi-agent",
"name": "Multi-Agent"
},
{
"id": "orchestration",
"name": "Orchestration"
},
{
"id": "human-in-loop",
"name": "Human-in-Loop"
}
],
"nodes": [
{
"name": "Start",
"type": "n8n-nodes-base.start",
"position": [
50,
300
],
"parameters": {},
"typeVersion": 1,
"id": "Start-0"
},
{
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"position": [
250,
300
],
"webhookId": "pyragogy-master-trigger",
"parameters": {
"path": "pyragogy/process",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 1,
"id": "Webhook-Trigger-1"
},
{
"name": "Datenbankverbindung prüfen",
"type": "n8n-nodes-base.postgres",
"position": [
450,
300
],
"parameters": {
"query": "SELECT 1; -- Verifica connessione DB",
"options": {},
"operation": "executeQuery"
},
"credentials": {
"postgres": {
"id": "pyragogy-postgres",
"name": "Postgres Pyragogy DB"
}
},
"typeVersion": 1,
"id": "Datenbankverbindung-pr-fen-2"
},
{
"name": "Meta-Orchestrator",
"type": "n8n-nodes-base.openAi",
"position": [
650,
300
],
"parameters": {
"model": "gpt-4o",
"options": {
"response_format": {
"type": "json_object"
}
},
"messages": [
{
"role": "system",
"content": "You are the Meta-orchestrator of the Pyragogy AI Village. Your task is to analyze the input and determine the optimal agent sequence for processing. Consider the input type, complexity, and goals. Available agents: Summarizer, Synthesizer, Peer Reviewer, Sensemaking Agent, Prompt Engineer, Onboarding/Explainer, Archivist. Return a JSON array of agent names in the order they should run, e.g., [\"Summarizer\", \"Synthesizer\", \"Peer Reviewer\", \"Archivist\"]. Include \"Archivist\" last if persistence is needed."
},
{
"role": "user",
"content": "Input Data:\n{{ JSON.stringify($json.body) }}"
}
],
"resource": "chat",
"authentication": "apiKey"
},
"credentials": {
"openAiApi": {
"id": "pyragogy-openai",
"name": "OpenAI Pyragogy"
}
},
"typeVersion": 1,
"id": "Meta-Orchestrator-3"
},
{
"name": "Orchestrierungsplan parsen",
"type": "n8n-nodes-base.function",
"position": [
850,
300
],
"parameters": {
"functionCode": "// Analizza il piano di orchestrazione e imposta per il looping\nlet rawPlan = $json.choices[0].message.content;\nlet plan;\n\ntry {\n plan = JSON.parse(rawPlan);\n} catch (e) {\n // Se il parsing fallisce, assumi che sia una stringa di array grezza\n plan = rawPlan;\n}\n\n// Estrai in modo sicuro la sequenza degli agenti:\n// Se 'plan' è un oggetto e ha una chiave 'agents', usala.\n// Altrimenti, se 'plan' è un array, usalo direttamente.\n// Altrimenti, predefinisci un array vuoto.\nconst agentSequence = Array.isArray(plan) ? plan : (plan && plan.agents && Array.isArray(plan.agents) ? plan.agents : []);\n\n// Memorizza la sequenza e l'indice corrente per il loop\n$workflow.agentSequence = agentSequence;\n$workflow.currentAgentIndex = 0;\n$workflow.redraftLoopCount = 0; // Inizializza il contatore dei cicli di rielaborazione\n\n// Passa i dati di input al primo agente, assicurandosi che $items[0].json.body esista\nconst initialInput = $items[0] && $items[0].json && $items[0].json.body ? $items[0].json.body : {};\n\nreturn [{ json: { ...initialInput, agentToRun: agentSequence[0] || null } }];"
},
"typeVersion": 1,
"id": "Orchestrierungsplan-parsen-4"
},
{
"name": "Weitere Agents auszuführen?",
"type": "n8n-nodes-base.if",
"position": [
1050,
300
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $workflow.currentAgentIndex < $workflow.agentSequence.length }}",
"value2": true
}
]
}
},
"typeVersion": 1,
"id": "Weitere-Agents-auszuf-hren--5"
},
{
"name": "Agent-Eingabe vorbereiten",
"type": "n8n-nodes-base.function",
"position": [
1250,
200
],
"parameters": {
"functionCode": "// Ottieni il nome dell'agente corrente\nconst agentName = $workflow.agentSequence[$workflow.currentAgentIndex];\n\n// Prepara i dati per l'esecuzione dell'agente\n// Passa l'output del passo precedente (o l'input iniziale).\n// Se stiamo rielaborando, l'input dell'agente dovrebbe includere il feedback di rielaborazione.\nconst previousOutput = $json.output || $json.body.input; // Assumendo che l'output dell'agente sia memorizzato nella chiave 'output'\nconst agentInput = $json.redraftInput || previousOutput; // Usa redraftInput se presente, altrimenti previousOutput\n\nreturn [{ json: { ...$json, agentToRun: agentName, agentInput: agentInput } }];"
},
"typeVersion": 1,
"id": "Agent-Eingabe-vorbereiten-6"
},
{
"name": "Agents mit Switch routen",
"type": "n8n-nodes-base.switch",
"position": [
1450,
200
],
"parameters": {
"mode": "json",
"value": "={{ $json.agentToRun }}",
"conditions": [
{
"type": "string",
"value": "Summarizer"
},
{
"type": "string",
"value": "Synthesizer"
},
{
"type": "string",
"value": "Peer Reviewer"
},
{
"type": "string",
"value": "Sensemaking Agent"
},
{
"type": "string",
"value": "Prompt Engineer"
},
{
"type": "string",
"value": "Onboarding/Explainer"
},
{
"type": "string",
"value": "Archivist"
}
]
},
"typeVersion": 1,
"id": "Agents-mit-Switch-routen-7"
},
{
"name": "Zusammenfassungs-Agent",
"type": "n8n-nodes-base.openAi",
"position": [
1650,
0
],
"parameters": {
"model": "gpt-4o",
"options": {},
"messages": [
{
"role": "system",
"content": "You are the Summarizer Agent. Summarize the provided text into 3 key points."
},
{
"role": "user",
"content": "Text to summarize:\n{{ $json.agentInput }}"
}
],
"resource": "chat",
"authentication": "apiKey"
},
"credentials": {
"openAiApi": {
"id": "pyragogy-openai",
"name": "OpenAI Pyragogy"
}
},
"typeVersion": 1,
"id": "Zusammenfassungs-Agent-8"
},
{
"name": "Synthese-Agent",
"type": "n8n-nodes-base.openAi",
"position": [
1650,
100
],
"parameters": {
"model": "gpt-4o",
"options": {},
"messages": [
{
"role": "system",
"content": "You are the Synthesizer Agent. Synthesize a creative new text from the given key points or input. If provided with 'redraft_feedback', incorporate it to refine the output."
},
{
"role": "user",
"content": "Input for synthesis:\n{{ $json.agentInput }}\n\n{{ $json.redraftFeedback ? 'Feedback per la rielaborazione: ' + $json.redraftFeedback : '' }}"
}
],
"resource": "chat",
"authentication": "apiKey"
},
"credentials": {
"openAiApi": {
"id": "pyragogy-openai",
"name": "OpenAI Pyragogy"
}
},
"typeVersion": 1,
"id": "Synthese-Agent-9"
},
{
"name": "Peer-Review-Agent",
"type": "n8n-nodes-base.openAi",
"position": [
1650,
200
],
"parameters": {
"model": "gpt-4o",
"options": {
"response_format": {
"type": "json_object"
}
},
"messages": [
{
"role": "system",
"content": "You are the Peer Reviewer Agent. Review the provided text, highlight strengths, weaknesses, and provide actionable suggestions for improvement. In your JSON output, include a 'major_issue' boolean flag (true if significant redrafting is needed, false otherwise)."
},
{
"role": "user",
"content": "Text to review:\n{{ $json.agentInput }}"
}
],
"resource": "chat",
"authentication": "apiKey"
},
"credentials": {
"openAiApi": {
"id": "pyragogy-openai",
"name": "OpenAI Pyragogy"
}
},
"typeVersion": 1,
"id": "Peer-Review-Agent-10"
},
{
"name": "Sensemaking-Agent",
"type": "n8n-nodes-base.openAi",
"position": [
1650,
300
],
"parameters": {
"model": "gpt-4o",
"options": {
"response_format": {
"type": "json_object"
}
},
"messages": [
{
"role": "system",
"content": "You are the Sensemaking Agent. Analyze the input, connect it with existing knowledge (context provided), identify patterns, gaps, and suggest new directions. In your JSON output, include a 'major_issue' boolean flag (true if significant redrafting is needed, false otherwise)."
},
{
"role": "user",
"content": "Input to analyze:\n{{ $json.agentInput }}\n\nContext from DB (if available):\n{{ $json.dbContext }}"
}
],
"resource": "chat",
"authentication": "apiKey"
},
"credentials": {
"openAiApi": {
"id": "pyragogy-openai",
"name": "OpenAI Pyragogy"
}
},
"typeVersion": 1,
"id": "Sensemaking-Agent-11"
},
{
"name": "Prompt-Engineer-Agent",
"type": "n8n-nodes-base.openAi",
"position": [
1650,
400
],
"parameters": {
"model": "gpt-4o",
"options": {
"response_format": {
"type": "json_object"
}
},
"messages": [
{
"role": "system",
"content": "You are the Prompt Engineer Agent. Analyze the current task context and the next agent in the sequence. Refine or generate an optimal prompt for the next agent. In your JSON output, include a 'major_issue' boolean flag (true if significant redrafting is needed, false otherwise)."
},
{
"role": "user",
"content": "Current context:\n{{ JSON.stringify($json) }}\nNext agent: {{ $workflow.agentSequence[$workflow.currentAgentIndex + 1] || 'None' }}"
}
],
"resource": "chat",
"authentication": "apiKey"
},
"credentials": {
"openAiApi": {
"id": "pyragogy-openai",
"name": "OpenAI Pyragogy"
}
},
"typeVersion": 1,
"id": "Prompt-Engineer-Agent-12"
},
{
"name": "Onboarding/Erklärungs-Agent",
"type": "n8n-nodes-base.openAi",
"position": [
1650,
500
],
"parameters": {
"model": "gpt-4o",
"options": {},
"messages": [
{
"role": "system",
"content": "You are the Onboarding/Explainer Agent. Explain the current process, the result achieved so far, or provide guidance based on the input."
},
{
"role": "user",
"content": "Explain the following:\n{{ $json.agentInput }}"
}
],
"resource": "chat",
"authentication": "apiKey"
},
"credentials": {
"openAiApi": {
"id": "pyragogy-openai",
"name": "OpenAI Pyragogy"
}
},
"typeVersion": 1,
"id": "Onboarding-Erkl-rungs-Agent-13"
},
{
"name": "Handbuch-Metadaten hinzufügen",
"type": "n8n-nodes-base.function",
"position": [
1650,
600
],
"parameters": {
"functionCode": "// Prepara i metadati per il contenuto dell'Handbook.\n// Assicurati che l'input originale contenga 'title' e 'tags' o imposta dei valori predefiniti.\nconst title = $json.body.title || 'Untitled Handbook Entry';\nconst tags = $json.body.tags || [];\nconst phase = $json.body.phase || 'draft'; // Fase iniziale, può essere 'final' dopo l'approvazione\nconst rhythm = $json.body.rhythm || 'on-demand'; // Ritmo cognitivo\n\nreturn [{ json: { ...$json, handbookTitle: title, handbookTags: tags, handbookPhase: phase, handbookRhythm: rhythm } }];"
},
"typeVersion": 1,
"id": "Handbuch-Metadaten-hinzuf-gen-14"
},
{
"name": "Inhalt zur Überprüfung generieren",
"type": "n8n-nodes-base.function",
"position": [
1850,
600
],
"parameters": {
"functionCode": "// Prepara il contenuto proposto dall'Archivista per la revisione umana, inclusa la formattazione YAML.\n// Assicurati che l'input dell'agente (il contenuto generato) sia disponibile.\nconst proposedContent = $json.agentInput;\nconst title = $json.handbookTitle;\nconst tags = $json.handbookTags;\nconst phase = $json.handbookPhase;\nconst rhythm = $json.handbookRhythm;\n\n// Costruisci il front-matter YAML\nconst yamlFrontMatter = `---\ntitle: \"${title.replace(/\"/g, '\\\"')}\"\ntags: [${tags.map(t => `\"${t.replace(/\"/g, '\\\"')}\"`).join(', ')}]\nphase: \"${phase}\"\nrhythm: \"${rhythm}\"\n---\n\n`;\n\nconst finalMarkdownContent = yamlFrontMatter + proposedContent;\n\nreturn [{ json: { ...$json, proposedContent: proposedContent, reviewTitle: title, reviewTags: tags, finalMarkdownContent: finalMarkdownContent } }];"
},
"typeVersion": 1,
"id": "Inhalt-zur-berpr-fung-generieren-15"
},
{
"name": "Review-ID generieren",
"type": "n8n-nodes-base.function",
"position": [
2050,
600
],
"parameters": {
"functionCode": "// Genera un ID univoco per questa richiesta di revisione.\n// Questo ID verrà usato per correlare la risposta del revisore con questa istanza del workflow.\nconst reviewId = crypto.randomUUID();\n\nreturn [{ json: { ...$json, reviewId: reviewId } }];"
},
"typeVersion": 1,
"id": "Review-ID-generieren-16"
},
{
"name": "Überprüfungsanfrage per E-Mail senden",
"type": "n8n-nodes-base.emailSend",
"position": [
2250,
600
],
"parameters": {
"html": "<h3>Revisione Contenuto Pyragogy Handbook: {{ $json.reviewTitle }}</h3>\n<p>Ciao revisore,</p>\n<p>È stato proposto un nuovo contenuto per l'Handbook:</p>\n<hr>\n<pre>{{ $json.proposedContent }}</pre>\n<hr>\n<p><strong>Titolo:</strong> {{ $json.reviewTitle }}</p>\n<p><strong>Tags:</strong> {{ $json.reviewTags.join(', ') }}</p>\n<p>Per favore, clicca su uno dei seguenti link per approvare o rifiutare:</p>\n<p><a href=\"your_n8n_url/webhook/pyragogy/review-feedback?reviewId={{ $json.reviewId }}&status=approved\">Approva</a></p>\n<p><a href=\"your_n8n_url/webhook/pyragogy/review-feedback?reviewId={{ $json.reviewId }}&status=rejected\">Rifiuta</a></p>\n<p>Grazie!</p>",
"text": "Ciao revisore,\n\nÈ stato proposto un nuovo contenuto per l'Handbook:\n\n---\n{{ $json.proposedContent }}\n---\n\nTitolo: {{ $json.reviewTitle }}\nTags: {{ $json.reviewTags.join(', ') }}\n\nPer favore, clicca su uno dei seguenti link per approvare o rifiutare:\n\nApprova: your_n8n_url/webhook/pyragogy/review-feedback?reviewId={{ $json.reviewId }}&status=approved\nRifiuta: your_n8n_url/webhook/pyragogy/review-feedback?reviewId={{ $json.reviewId }}&status=rejected\n\nGrazie!",
"options": {},
"subject": "Revisione Contenuto Pyragogy Handbook: {{ $json.reviewTitle }}",
"toEmail": "human-reviewer@example.com",
"fromEmail": "your-email@example.com"
},
"credentials": {
"emailSend": {
"id": "your-email-credential-id",
"name": "Your Email Credential Name"
}
},
"typeVersion": 1,
"id": "-berpr-fungsanfrage-per-E-Mail-senden-17"
},
{
"name": "Auf manuelle Freigabe warten",
"type": "n8n-nodes-base.wait",
"position": [
2450,
600
],
"parameters": {
"mode": "webhook",
"timeout": "1h",
"matchField": "reviewId",
"matchValue": "={{ $json.reviewId }}",
"webhookPath": "pyragogy/review-feedback"
},
"typeVersion": 1,
"id": "Auf-manuelle-Freigabe-warten-18"
},
{
"name": "Menschliche Entscheidungsverzweigung",
"type": "n8n-nodes-base.if",
"position": [
2650,
600
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.query.status === 'approved' }}",
"value2": true
}
]
}
},
"typeVersion": 1,
"id": "Menschliche-Entscheidungsverzweigung-19"
},
{
"name": "In handbook_entries speichern",
"type": "n8n-nodes-base.postgres",
"position": [
2850,
500
],
"parameters": {
"table": "handbook_entries",
"values": "={{ $json.reviewTitle || 'Untitled' }}, {{ $json.finalMarkdownContent }}, {{ $json.version || 1 }}, {{ $json.author || 'AI Village' }}, ARRAY[{{ ($json.reviewTags || []).map(t => `'${t}'`).join(',') }}], {{ $json.handbookPhase || 'final' }}, {{ $json.handbookRhythm || 'on-demand' }}",
"columns": "title, content, version, created_by, tags, phase, rhythm",
"options": {
"returning": "id"
},
"operation": "insert"
},
"credentials": {
"postgres": {
"id": "pyragogy-postgres",
"name": "Postgres Pyragogy DB"
}
},
"typeVersion": 1,
"id": "In-handbook_entries-speichern-20"
},
{
"name": "Freigegebene Beitragsdaten vorbereiten",
"type": "n8n-nodes-base.function",
"position": [
3050,
500
],
"parameters": {
"functionCode": "// Registra il contributo dell'agente dopo l'approvazione umana\nconst entryId = $json.id; // ID dall'inserimento in handbook_entries\nconst agentName = 'Archivist';\nconst contributionType = 'Archiving (Approved)';\nconst details = { input: $json.proposedContent, metadata: { title: $json.reviewTitle, version: $json.version, tags: $json.reviewTags, phase: $json.handbookPhase, rhythm: $json.handbookRhythm }, reviewStatus: 'approved' };\n\n$items[0].json.contribution = { entryId, agentName, contributionType, details };\nreturn $items;"
},
"typeVersion": 1,
"id": "Freigegebene-Beitragsdaten-vorbereiten-21"
},
{
"name": "Agentenbeitrag speichern (freigegeben)",
"type": "n8n-nodes-base.postgres",
"position": [
3250,
500
],
"parameters": {
"table": "agent_contributions",
"values": "={{ $json.contribution.entryId }}, {{ $json.contribution.agentName }}, {{ $json.contribution.contributionType }}, {{ JSON.stringify($json.contribution.details) }}",
"columns": "entry_id, agent_name, contribution_type, details",
"options": {},
"operation": "insert"
},
"credentials": {
"postgres": {
"id": "pyragogy-postgres",
"name": "Postgres Pyragogy DB"
}
},
"typeVersion": 1,
"id": "Agentenbeitrag-speichern-freigegeben--22"
},
{
"name": "GitHub Dateipfad generieren",
"type": "n8n-nodes-base.function",
"position": [
3450,
500
],
"parameters": {
"functionCode": "// Genera il percorso del file GitHub con slug e timestamp per il versioning.\nconst chapterSlug = ($json.reviewTitle || 'untitled').replace(/[^a-zA-Z0-9]/g, '-').toLowerCase();\nconst timestamp = new Date().toISOString().replace(/[:.-]/g, ''); // Rimuove caratteri non validi per i nomi di file\nconst filePathWithVersion = `content/${chapterSlug}_v${timestamp}.md`;\n\nreturn [{ json: { ...$json, githubFilePath: filePathWithVersion } }];"
},
"typeVersion": 1,
"id": "GitHub-Dateipfad-generieren-23"
},
{
"name": "GitHub aktiviert?",
"type": "n8n-nodes-base.if",
"position": [
3650,
500
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $env.GITHUB_ACCESS_TOKEN }}",
"value2": true
}
]
}
},
"typeVersion": 1,
"id": "GitHub-aktiviert--24"
},
{
"name": "In GitHub committen (freigegeben)",
"type": "n8n-nodes-base.github",
"position": [
3850,
500
],
"parameters": {
"owner": "={{ $env.GITHUB_REPOSITORY_OWNER }}",
"options": {},
"filePath": "={{ $json.githubFilePath }}",
"resource": "file",
"operation": "createUpdate",
"repository": "={{ $env.GITHUB_REPOSITORY_NAME }}",
"fileContent": "={{ $json.finalMarkdownContent }}",
"commitMessage": "={{ `[BOT] Add/Update Handbook: ${$json.reviewTitle} (Approved by Human)` }}",
"authentication": "accessToken"
},
"credentials": {
"githubApi": {
"id": "pyragogy-github",
"name": "GitHub Pyragogy"
}
},
"typeVersion": 1,
"id": "In-GitHub-committen-freigegeben--25"
},
{
"name": "Menschliche Ablehnung protokollieren",
"type": "n8n-nodes-base.function",
"position": [
2850,
700
],
"parameters": {
"functionCode": "// Registra il rifiuto umano del contenuto\nconst agentName = 'Archivist';\nconst reviewId = $json.reviewId;\nconst reviewStatus = 'rejected';\nconst reviewComments = $json.query.comments || 'Nessun commento fornito.';\nconst proposedContent = $json.proposedContent;\nconst title = $json.reviewTitle;\n\nconsole.log(`Contenuto proposto dall'Archivista (ID: ${reviewId}, Titolo: ${title}) rifiutato dall'umano. Commenti: ${reviewComments}`);\n\n// Prepara l'output per indicare il rifiuto e consentire al flusso di continuare.\nreturn [{ json: { ...$json, reviewStatus: reviewStatus, reviewComments: reviewComments, output: { message: `Archivista: Contenuto rifiutato dall'umano.`, status: 'rejected', comments: reviewComments } } }];"
},
"typeVersion": 1,
"id": "Menschliche-Ablehnung-protokollieren-26"
},
{
"name": "Archivisten-Pfade zusammenführen",
"type": "n8n-nodes-base.merge",
"position": [
4050,
600
],
"parameters": {
"mode": "mergeByPropertyName",
"propertyName": "reviewId"
},
"typeVersion": 1,
"id": "Archivisten-Pfade-zusammenf-hren-27"
},
{
"name": "Board-Konsens auswerten",
"type": "n8n-nodes-base.function",
"position": [
1850,
300
],
"parameters": {
"functionCode": "// Valuta i flag 'major_issue' dagli agenti di revisione per determinare se è necessaria una rielaborazione.\nlet majorIssueCount = 0;\nlet redraftFeedback = '';\n\n// Assumi che gli output degli agenti di revisione siano accessibili tramite $node\n// (Ad esempio, se Peer Reviewer -> Sensemaking -> Prompt Engineer sono sequenziali prima di questo nodo)\n\nif ($node[\"Peer Reviewer Agent\"] && $node[\"Peer Reviewer Agent\"].json && $node[\"Peer Reviewer Agent\"].json.choices && $node[\"Peer Reviewer Agent\"].json.choices[0] && $node[\"Peer Reviewer Agent\"].json.choices[0].message && $node[\"Peer Reviewer Agent\"].json.choices[0].message.content) {\n const peerReviewOutput = JSON.parse($node[\"Peer Reviewer Agent\"].json.choices[0].message.content);\n if (peerReviewOutput.major_issue) majorIssueCount++;\n redraftFeedback += `Peer Reviewer: ${peerReviewOutput.suggestions || ''}\\n`;\n}\n\nif ($node[\"Sensemaking Agent\"] && $node[\"Sensemaking Agent\"].json && $node[\"Sensemaking Agent\"].json.choices && $node[\"Sensemaking Agent\"].json.choices[0] && $node[\"Sensemaking Agent\"].json.choices[0].message && $node[\"Sensemaking Agent\"].json.choices[0].message.content) {\n const sensemakingOutput = JSON.parse($node[\"Sensemaking Agent\"].json.choices[0].message.content);\n if (sensemakingOutput.major_issue) majorIssueCount++;\n redraftFeedback += `Sensemaking Agent: ${sensemakingOutput.suggestions || ''}\\n`;\n}\n\nif ($node[\"Prompt Engineer Agent\"] && $node[\"Prompt Engineer Agent\"].json && $node[\"Prompt Engineer Agent\"].json.choices && $node[\"Prompt Engineer Agent\"].json.choices[0] && $node[\"Prompt Engineer Agent\"].json.choices[0].message && $node[\"Prompt Engineer Agent\"].json.choices[0].message.content) {\n const promptEngineerOutput = JSON.parse($node[\"Prompt Engineer Agent\"].json.choices[0].message.content);\n if (promptEngineerOutput.major_issue) majorIssueCount++;\n redraftFeedback += `Prompt Engineer: ${promptEngineerOutput.suggestions || ''}\\n`;\n}\n\nconst redraftNeeded = majorIssueCount >= 2; // Voto a maggioranza\n\nreturn [{ json: { ...$json, redraftNeeded: redraftNeeded, redraftFeedback: redraftFeedback } }];"
},
"typeVersion": 1,
"id": "Board-Konsens-auswerten-28"
},
{
"name": "Überarbeitungsbedarf prüfen",
"type": "n8n-nodes-base.if",
"position": [
2050,
300
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.redraftNeeded && $workflow.redraftLoopCount < 2 }}",
"value2": true
}
]
}
},
"typeVersion": 1,
"id": "-berarbeitungsbedarf-pr-fen-29"
},
{
"name": "Überarbeitung bearbeiten",
"type": "n8n-nodes-base.function",
"position": [
2250,
200
],
"parameters": {
"functionCode": "// Gestisce la logica di rielaborazione: incrementa il contatore e reindirizza al Synthesizer.\n\n$workflow.redraftLoopCount += 1; // Incrementa il contatore del ciclo di rielaborazione\n\n// Trova l'indice del Synthesizer nella sequenza degli agenti\nconst synthesizerIndex = $workflow.agentSequence.indexOf(\"Synthesizer\");\n\n// Se il Synthesizer non è il prossimo agente, imposta l'indice corrente per farlo ripartire dal Synthesizer.\n// Questo garantisce che il Synthesizer venga eseguito successivamente per la rielaborazione.\nif ($workflow.currentAgentIndex !== synthesizerIndex) {\n $workflow.currentAgentIndex = synthesizerIndex;\n} else {\n // Se siamo già sul Synthesizer (es. dopo il primo passaggio del loop), assicurati che l'indice vada avanti normalmente nel prossimo ciclo.\n // Questo è un caso limite, di solito il Prepare Agent Input lo gestirà.\n}\n\n// Passa il feedback di rielaborazione come input per il Synthesizer.\n// Il nodo 'Prepare Agent Input' utilizzerà questo campo per aggiornare 'agentInput'.\nreturn [{ json: { ...$json, redraftInput: $json.output + \"\\n\\nFeedback per la rielaborazione dal Peer Review Board:\\n\" + $json.redraftFeedback } }];"
},
"typeVersion": 1,
"id": "-berarbeitung-bearbeiten-30"
},
{
"name": "Agenten-Ausgabe verarbeiten",
"type": "n8n-nodes-base.function",
"position": [
2050,
200
],
"parameters": {
"functionCode": "// Ottieni il nome dell'agente appena eseguito\nconst agentName = $json.agentToRun;\nlet agentOutput = '';\n\n// Costruisci dinamicamente il nome del nodo per il recupero dell'output\nlet actualNodeName;\n\n// Gestione speciale per l'Archivista dopo la revisione umana\nif (agentName === 'Archivist') {\n if ($json.query && $json.query.status === 'approved') {\n agentOutput = { message: 'Contenuto archiviato con successo dopo l'approvazione umana.', entryId: $json.id || 'N/A', handbookMetadata: { title: $json.reviewTitle, tags: $json.reviewTags, phase: $json.handbookPhase, rhythm: $json.handbookRhythm } };\n } else if ($json.query && $json.query.status === 'rejected') {\n agentOutput = { message: 'Archiviazione rifiutata dall'umano.', reviewComments: $json.query.comments || 'Nessun commento' };\n } else if ($json.reviewStatus === 'rejected') {\n // Caso in cui la revisione umana è stata rifiutata e si proviene dal ramo di rifiuto\n agentOutput = { message: 'Archiviazione rifiutata dall'umano (tramite ramo di rifiuto).', reviewComments: $json.reviewComments || 'Nessun commento' };\n } else {\n agentOutput = { message: 'Processo Archivista: Attesa revisione umana o stato inatteso.', status: 'pending_review' };\n }\n} else {\n // Logica originale per gli altri agenti OpenAI\n if (agentName === 'Onboarding/Explainer') {\n actualNodeName = 'Onboarding/Explainer Agent';\n } else {\n actualNodeName = agentName + ' Agent';\n }\n\n // Tenta in modo sicuro di recuperare l'output dal nodo determinato dinamicamente\n // Tenta anche di analizzare il JSON se l'output dell'agente è un oggetto JSON (come per gli agenti di revisione)\n let rawContent = '';\n if ($node[actualNodeName] && $node[actualNodeName].json && $node[actualNodeName].json.choices && $node[actualNodeName].json.choices[0] && $node[actualNodeName].json.choices[0].message && $node[actualNodeName].json.choices[0].message.content) {\n rawContent = $node[actualNodeName].json.choices[0].message.content;\n } else {\n console.warn(`Impossibile trovare l'output chat OpenAI standard per il nodo: ${actualNodeName}. Ritorno al JSON grezzo.`);\n agentOutput = $node[actualNodeName] ? $node[actualNodeName].json : `Nessun output specifico trovato per ${agentName}`;\n }\n\n // Tenta di analizzare il contenuto come JSON se l'agente è un agente di revisione\n if (agentName === 'Peer Reviewer' || agentName === 'Sensemaking Agent' || agentName === 'Prompt Engineer') {\n try {\n agentOutput = JSON.parse(rawContent);\n } catch (e) {\n console.warn(`Impossibile analizzare l'output di ${agentName} come JSON. Trattato come stringa.`);\n agentOutput = rawContent;\n }\n } else {\n agentOutput = rawContent;\n }\n}\n\n// Registra il contributo\nconst contribution = {\n agent: agentName,\n output: agentOutput,\n timestamp: new Date().toISOString()\n};\n\n// Assicurati che l'array dei contributi esista e aggiungi il nuovo contributo\nconst existingContributions = Array.isArray($json.contributions) ? $json.contributions : [];\n\n// Incrementa l'indice dell'agente per il loop (solo se non siamo in rielaborazione e questo non è un agente di revisione che porta a rielaborazione)\n// Questo è gestito dalla logica di 'Handle Redraft' che forza l'indice per il riavvio.\nif (!($json.redraftNeeded && $workflow.redraftLoopCount < 2 && agentName !== 'Synthesizer')) { // Evita doppio incremento se riavvia il Synthesizer\n $workflow.currentAgentIndex += 1;\n}\n\n// Restituisce l'elemento aggiornato, preservando l'input originale, aggiungendo l'output corrente e tutti i contributi\nreturn [{ json: { ...$items[0].json, output: agentOutput, contributions: [...existingContributions, contribution] } }];"
},
"typeVersion": 1,
"id": "Agenten-Ausgabe-verarbeiten-31"
},
{
"name": "Slack aktiviert?",
"type": "n8n-nodes-base.if",
"position": [
1250,
500
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $env.SLACK_WEBHOOK_URL }}",
"value2": true
}
]
}
},
"typeVersion": 1,
"id": "Slack-aktiviert--32"
},
{
"name": "Slack benachrichtigen",
"type": "n8n-nodes-base.slack",
"position": [
1450,
500
],
"parameters": {
"text": "Pyragogy AI Village Workflow Completato!\nInput: {{ $json.body.input }}\nOutput Finale: {{ JSON.stringify($json.output) }}\nAgenti Eseguiti: {{ $workflow.agentSequence.join(', ') }}",
"options": {},
"webhookUrl": "={{ $env.SLACK_WEBHOOK_URL }}"
},
"typeVersion": 1,
"id": "Slack-benachrichtigen-33"
},
{
"name": "Finale Antwort",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1250,
400
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { finalOutput: $json.output, contributions: $json.contributions, agentSequence: $workflow.agentSequence } }}"
},
"typeVersion": 1,
"id": "Finale-Antwort-34"
}
],
"settings": {
"executionOrder": "v1"
},
"connections": {
"Slack-benachrichtigen-33": {
"main": [
[
{
"node": "Finale-Antwort-34",
"type": "main",
"index": 0
}
]
],
"error": [
[
{
"node": "Finale-Antwort-34",
"type": "main",
"index": 0
}
]
]
},
"-berarbeitung-bearbeiten-30": {
"main": [
[
{
"node": "Weitere-Agents-auszuf-hren--5",
"type": "main",
"index": 0
}
]
]
},
"Slack-aktiviert--32": {
"main": [
[
{
"node": "Slack-benachrichtigen-33",
"type": "main",
"index": 0
}
],
[
{
"node": "Finale-Antwort-34",
"type": "main",
"index": 0
}
]
]
},
"GitHub-aktiviert--24": {
"main": [
[
{
"node": "In-GitHub-committen-freigegeben--25",
"type": "main",
"index": 0
}
],
[
{
"node": "Archivisten-Pfade-zusammenf-hren-27",
"type": "main",
"index": 0
}
]
]
},
"Webhook-Trigger-1": {
"main": [
[
{
"node": "Datenbankverbindung-pr-fen-2",
"type": "main",
"index": 0
}
]
]
},
"Zusammenfassungs-Agent-8": {
"main": [
[
{
"node": "Agenten-Ausgabe-verarbeiten-31",
"type": "main",
"index": 0
}
]
]
},
"Meta-Orchestrator-3": {
"main": [
[
{
"node": "Orchestrierungsplan-parsen-4",
"type": "main",
"index": 0
}
]
]
},
"Sensemaking-Agent-11": {
"main": [
[
{
"node": "Prompt-Engineer-Agent-12",
"type": "main",
"index": 0
}
]
]
},
"Synthese-Agent-9": {
"main": [
[
{
"node": "Agenten-Ausgabe-verarbeiten-31",
"type": "main",
"index": 0
}
]
]
},
"Review-ID-generieren-16": {
"main": [
[
{
"node": "-berpr-fungsanfrage-per-E-Mail-senden-17",
"type": "main",
"index": 0
}
]
]
},
"Datenbankverbindung-pr-fen-2": {
"main": [
[
{
"node": "Meta-Orchestrator-3",
"type": "main",
"index": 0
}
]
]
},
"Menschliche-Ablehnung-protokollieren-26": {
"main": [
[
{
"node": "Archivisten-Pfade-zusammenf-hren-27",
"type": "main",
"index": 0
}
]
]
},
"Weitere-Agents-auszuf-hren--5": {
"main": [
[
{
"node": "Agent-Eingabe-vorbereiten-6",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack-aktiviert--32",
"type": "main",
"index": 0
}
]
]
},
"Peer-Review-Agent-10": {
"main": [
[
{
"node": "Sensemaking-Agent-11",
"type": "main",
"index": 0
}
]
]
},
"Agent-Eingabe-vorbereiten-6": {
"main": [
[
{
"node": "Agents-mit-Switch-routen-7",
"type": "main",
"index": 0
}
]
]
},
"-berarbeitungsbedarf-pr-fen-29": {
"main": [
[
{
"node": "-berarbeitung-bearbeiten-30",
"type": "main",
"index": 0
}
],
[
{
"node": "Agenten-Ausgabe-verarbeiten-31",
"type": "main",
"index": 0
}
]
]
},
"Menschliche-Entscheidungsverzweigung-19": {
"main": [
[
{
"node": "In-handbook_entries-speichern-20",
"type": "main",
"index": 0
}
],
[
{
"node": "Menschliche-Ablehnung-protokollieren-26",
"type": "main",
"index": 0
}
]
]
},
"Agenten-Ausgabe-verarbeiten-31": {
"main": [
[
{
"node": "Weitere-Agents-auszuf-hren--5",
"type": "main",
"index": 0
}
]
]
},
"Handbuch-Metadaten-hinzuf-gen-14": {
"main": [
[
{
"node": "Inhalt-zur-berpr-fung-generieren-15",
"type": "main",
"index": 0
}
]
]
},
"Archivisten-Pfade-zusammenf-hren-27": {
"main": [
[
{
"node": "Agenten-Ausgabe-verarbeiten-31",
"type": "main",
"index": 0
}
]
]
},
"Prompt-Engineer-Agent-12": {
"main": [
[
{
"node": "Board-Konsens-auswerten-28",
"type": "main",
"index": 0
}
]
]
},
"Auf-manuelle-Freigabe-warten-18": {
"main": [
[
{
"node": "Menschliche-Entscheidungsverzweigung-19",
"type": "main",
"index": 0
}
]
]
},
"Board-Konsens-auswerten-28": {
"main": [
[
{
"node": "-berarbeitungsbedarf-pr-fen-29",
"type": "main",
"index": 0
}
]
]
},
"Orchestrierungsplan-parsen-4": {
"main": [
[
{
"node": "Weitere-Agents-auszuf-hren--5",
"type": "main",
"index": 0
}
]
]
},
"Agents-mit-Switch-routen-7": {
"main": [
[
{
"node": "Zusammenfassungs-Agent-8",
"type": "main",
"index": 0
}
],
[
{
"node": "Synthese-Agent-9",
"type": "main",
"index": 1
}
],
[
{
"node": "Peer-Review-Agent-10",
"type": "main",
"index": 2
}
],
[
{
"node": "Sensemaking-Agent-11",
"type": "main",
"index": 3
}
],
[
{
"node": "Prompt-Engineer-Agent-12",
"type": "main",
"index": 4
}
],
[
{
"node": "Onboarding-Erkl-rungs-Agent-13",
"type": "main",
"index": 5
}
],
[
{
"node": "Handbuch-Metadaten-hinzuf-gen-14",
"type": "main",
"index": 6
}
]
]
},
"In-handbook_entries-speichern-20": {
"main": [
[
{
"node": "Freigegebene-Beitragsdaten-vorbereiten-21",
"type": "main",
"index": 0
}
]
]
},
"GitHub-Dateipfad-generieren-23": {
"main": [
[
{
"node": "GitHub-aktiviert--24",
"type": "main",
"index": 0
}
]
]
},
"-berpr-fungsanfrage-per-E-Mail-senden-17": {
"main": [
[
{
"node": "Auf-manuelle-Freigabe-warten-18",
"type": "main",
"index": 0
}
]
]
},
"Onboarding-Erkl-rungs-Agent-13": {
"main": [
[
{
"node": "Agenten-Ausgabe-verarbeiten-31",
"type": "main",
"index": 0
}
]
]
},
"In-GitHub-committen-freigegeben--25": {
"main": [
[
{
"node": "Archivisten-Pfade-zusammenf-hren-27",
"type": "main",
"index": 0
}
]
]
},
"Inhalt-zur-berpr-fung-generieren-15": {
"main": [
[
{
"node": "Review-ID-generieren-16",
"type": "main",
"index": 0
}
]
]
},
"Freigegebene-Beitragsdaten-vorbereiten-21": {
"main": [
[
{
"node": "Agentenbeitrag-speichern-freigegeben--22",
"type": "main",
"index": 0
}
]
]
},
"Agentenbeitrag-speichern-freigegeben--22": {
"main": [
[
{
"node": "GitHub-Dateipfad-generieren-23",
"type": "main",
"index": 0
}
]
]
}
}
}Wie verwende ich diesen Workflow?
Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.
Für welche Szenarien ist dieser Workflow geeignet?
Experte - Engineering, Künstliche Intelligenz
Ist es kostenpflichtig?
Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.
Verwandte Workflows
Fabrizio Terzi
@orgFounder of Pyragogy.org — an open initiative exploring AI–human co-creation, ethical automation, and peer learning ecosystems. I build modular workflows for AI-driven content creation, with a focus on transparency, human-in-the-loop design, and collaborative publishing. Always learning, always building — let’s co-create the future.
Diesen Workflow teilen