forked from molecule-ai/molecule-core
Forked clean from public hackathon repo (Starfire-AgentTeam, BSL 1.1) with full rebrand to Molecule AI under github.com/Molecule-AI/molecule-monorepo. Brand: Starfire → Molecule AI. Slug: starfire / agent-molecule → molecule. Env vars: STARFIRE_* → MOLECULE_*. Go module: github.com/agent-molecule/platform → github.com/Molecule-AI/molecule-monorepo/platform. Python packages: starfire_plugin → molecule_plugin, starfire_agent → molecule_agent. DB: agentmolecule → molecule. History truncated; see public repo for prior commits and contributor attribution. Verified green: go test -race ./... (platform), pytest (workspace-template 1129 + sdk 132), vitest (canvas 352), build (mcp). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
163 lines
6.5 KiB
Bash
Executable File
163 lines
6.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# E2E test: Agents talk TO EACH OTHER via A2A delegation
|
|
# Tests cross-runtime peer-to-peer communication, not just user→agent
|
|
set -euo pipefail
|
|
|
|
PLATFORM="${1:-http://localhost:8080}"
|
|
OPENAI_KEY="${OPENAI_API_KEY:?Set OPENAI_API_KEY env var}"
|
|
PASS=0
|
|
FAIL=0
|
|
|
|
check() {
|
|
local label="$1" expected="$2" actual="$3"
|
|
if echo "$actual" | grep -qi "$expected"; then
|
|
echo "PASS: $label"
|
|
PASS=$((PASS + 1))
|
|
else
|
|
echo "FAIL: $label"
|
|
echo " expected: $expected"
|
|
echo " got: $(echo "$actual" | head -3)"
|
|
FAIL=$((FAIL + 1))
|
|
fi
|
|
}
|
|
|
|
wait_online() {
|
|
local id="$1" name="$2" max="${3:-60}"
|
|
for i in $(seq 1 "$max"); do
|
|
local s
|
|
s=$(curl -s "$PLATFORM/workspaces/$id" | python3 -c "import sys,json; print(json.load(sys.stdin).get('status',''))" 2>/dev/null)
|
|
[ "$s" = "online" ] && return 0
|
|
[ "$s" = "failed" ] && return 1
|
|
[ $((i % 10)) -eq 0 ] && echo " [$name] $((i*5))s..."
|
|
sleep 5
|
|
done
|
|
return 1
|
|
}
|
|
|
|
a2a_send() {
|
|
local id="$1" message="$2"
|
|
curl -s -X POST "$PLATFORM/workspaces/$id/a2a" \
|
|
-H 'Content-Type: application/json' \
|
|
-d "{\"method\":\"message/send\",\"params\":{\"message\":{\"role\":\"user\",\"parts\":[{\"kind\":\"text\",\"text\":\"$message\"}]}}}" | \
|
|
python3 -c "import sys,json; r=json.load(sys.stdin); print(r.get('result',{}).get('parts',[{}])[0].get('text','ERROR'))" 2>/dev/null
|
|
}
|
|
|
|
echo "============================================"
|
|
echo " Cross-Agent Chat: Agents Talk to Each Other"
|
|
echo "============================================"
|
|
echo ""
|
|
|
|
# --- Create 3 agents: PM (LangGraph), Developer (CrewAI), Researcher (AutoGen) ---
|
|
echo "--- Creating 3 agents ---"
|
|
|
|
R=$(curl -s -X POST "$PLATFORM/workspaces" -H 'Content-Type: application/json' \
|
|
-d '{"name":"PM","role":"Project Manager","tier":2,"template":"langgraph"}')
|
|
PM=$(echo "$R" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
|
echo "PM (LangGraph): $PM"
|
|
|
|
R=$(curl -s -X POST "$PLATFORM/workspaces" -H 'Content-Type: application/json' \
|
|
-d '{"name":"Developer","role":"Code implementation","tier":2,"template":"crewai"}')
|
|
DEV=$(echo "$R" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
|
echo "Developer (CrewAI): $DEV"
|
|
|
|
R=$(curl -s -X POST "$PLATFORM/workspaces" -H 'Content-Type: application/json' \
|
|
-d '{"name":"Researcher","role":"Research and analysis","tier":2,"template":"autogen"}')
|
|
RES=$(echo "$R" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
|
|
echo "Researcher (AutoGen): $RES"
|
|
|
|
# --- Set hierarchy: PM -> Developer, Researcher ---
|
|
echo ""
|
|
echo "--- Setting hierarchy ---"
|
|
curl -s -X PATCH "$PLATFORM/workspaces/$DEV" -H 'Content-Type: application/json' \
|
|
-d "{\"parent_id\":\"$PM\"}" > /dev/null
|
|
curl -s -X PATCH "$PLATFORM/workspaces/$RES" -H 'Content-Type: application/json' \
|
|
-d "{\"parent_id\":\"$PM\"}" > /dev/null
|
|
echo "PM → Developer, Researcher"
|
|
|
|
# --- Set API keys ---
|
|
echo ""
|
|
echo "--- Setting API keys ---"
|
|
for ID in $PM $DEV $RES; do
|
|
curl -s -X POST "$PLATFORM/workspaces/$ID/secrets" \
|
|
-H 'Content-Type: application/json' \
|
|
-d "{\"key\":\"OPENAI_API_KEY\",\"value\":\"$OPENAI_KEY\"}" > /dev/null
|
|
done
|
|
|
|
# Restart to pick up keys
|
|
for ID in $PM $DEV $RES; do
|
|
curl -s -X POST "$PLATFORM/workspaces/$ID/restart" > /dev/null
|
|
done
|
|
echo "Set keys and restarting..."
|
|
|
|
# --- Wait for all online ---
|
|
echo ""
|
|
echo "--- Waiting for agents ---"
|
|
wait_online "$PM" "PM" 60 && check "PM online" "ok" "ok" || check "PM online" "online" "timeout"
|
|
wait_online "$DEV" "Developer" 120 && check "Developer online" "ok" "ok" || check "Developer online" "online" "timeout"
|
|
wait_online "$RES" "Researcher" 120 && check "Researcher online" "ok" "ok" || check "Researcher online" "online" "timeout"
|
|
|
|
# --- Set prompts with delegation instructions ---
|
|
echo ""
|
|
echo "--- Setting prompts with peer info ---"
|
|
|
|
curl -s -X PUT "$PLATFORM/workspaces/$PM/files/system-prompt.md" \
|
|
-H 'Content-Type: application/json' \
|
|
-d "{\"content\":\"You are the PM. You coordinate Developer and Researcher. When asked to research something, delegate to the Researcher (workspace ID: $RES) using the delegate_to_workspace tool. When asked to build something, delegate to the Developer (workspace ID: $DEV). Always include the peer's response in your answer.\"}" > /dev/null
|
|
|
|
curl -s -X PUT "$PLATFORM/workspaces/$DEV/files/system-prompt.md" \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"content":"You are the Developer. When asked to code or build something, describe the approach briefly. Keep responses under 30 words."}' > /dev/null
|
|
|
|
curl -s -X PUT "$PLATFORM/workspaces/$RES/files/system-prompt.md" \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"content":"You are the Researcher. When asked to research something, provide a brief 1-sentence finding. Keep responses under 30 words."}' > /dev/null
|
|
|
|
# Restart PM to pick up new prompt with peer IDs
|
|
curl -s -X POST "$PLATFORM/workspaces/$PM/restart" > /dev/null
|
|
sleep 5
|
|
wait_online "$PM" "PM" 60 || true
|
|
check "Prompts set" "ok" "ok"
|
|
|
|
# --- Test 1: Direct agent responses ---
|
|
echo ""
|
|
echo "--- Test 1: Direct responses (no delegation) ---"
|
|
|
|
echo " Asking Developer directly..."
|
|
RESP=$(a2a_send "$DEV" "how would you implement a REST API?")
|
|
echo " Developer: $RESP"
|
|
check "Developer responds directly" "API" "$RESP"
|
|
|
|
echo " Asking Researcher directly..."
|
|
RESP=$(a2a_send "$RES" "what is the latest trend in AI agents?")
|
|
echo " Researcher: $RESP"
|
|
check "Researcher responds directly" "agent" "$RESP"
|
|
|
|
# --- Test 2: PM delegates to Researcher ---
|
|
echo ""
|
|
echo "--- Test 2: PM delegates to Researcher (cross-runtime A2A) ---"
|
|
echo " Asking PM to research something (should delegate to Researcher)..."
|
|
RESP=$(a2a_send "$PM" "Please ask the Researcher to briefly explain what LangGraph is.")
|
|
echo " PM says: $RESP"
|
|
# The response should contain info from the Researcher
|
|
check "PM got Researcher's response" "graph\|agent\|lang\|workflow" "$RESP"
|
|
|
|
# --- Test 3: PM delegates to Developer ---
|
|
echo ""
|
|
echo "--- Test 3: PM delegates to Developer (cross-runtime A2A) ---"
|
|
echo " Asking PM to get dev advice (should delegate to Developer)..."
|
|
RESP=$(a2a_send "$PM" "Ask the Developer how to build a WebSocket server.")
|
|
echo " PM says: $RESP"
|
|
check "PM got Developer's response" "WebSocket\|socket\|server\|connect" "$RESP"
|
|
|
|
# --- Cleanup ---
|
|
echo ""
|
|
echo "--- Cleanup ---"
|
|
curl -s -X DELETE "$PLATFORM/workspaces/$PM" > /dev/null 2>&1
|
|
check "Cleanup" "ok" "ok"
|
|
|
|
echo ""
|
|
echo "============================================"
|
|
echo " Results: $PASS passed, $FAIL failed"
|
|
echo "============================================"
|
|
exit $FAIL
|