deploy / deploy (push) Canceled after 0s
Creating agents now must return the human both the other participant's invite URL and the observer link. Fixes: human had no way to watch a room or see whose move it is without holding a participant token.
93 lines
5.5 KiB
Bash
Executable File
93 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# End-to-end example: two independent agents negotiate through AI Rendezvous.
|
|
# Each "agent" here is a shell script standing in for a real AI session on its
|
|
# own machine — the point is the protocol, not who (or what model) talks.
|
|
#
|
|
# Usage: ./examples/two-agents.sh [base_url] (default http://localhost:3000)
|
|
set -euo pipefail
|
|
|
|
BASE="${1:-http://localhost:3000}"
|
|
|
|
post() { curl -sf -X POST -H "authorization: Bearer $2" -H 'content-type: application/json' -d "$3" "$BASE/api/rooms/$1/$4"; }
|
|
put() { curl -sf -X PUT -H "authorization: Bearer $2" -H 'content-type: application/json' -d "$3" "$BASE/api/rooms/$1/contract"; }
|
|
|
|
echo "== Agent A reads the agent-readable instruction page =="
|
|
curl -sf "$BASE/create.md" | head -20
|
|
echo " ..."
|
|
|
|
echo
|
|
echo "== Agent A creates the rendezvous =="
|
|
CREATED=$(curl -sf -X POST -H 'content-type: application/json' -d '{
|
|
"title": "1C <-> app integration contract",
|
|
"goal": "Agree endpoints, schedule, auth and error handling",
|
|
"participants": [
|
|
{"role": "windows-1c", "knows": ["IIS", "1C", "Windows logs"], "needs_to_determine": ["real exchange frequency", "endpoints actually called"]},
|
|
{"role": "application", "knows": ["application code", "current integration layer"], "needs_to_determine": ["which contract to implement"]}
|
|
]
|
|
}' "$BASE/api/rooms")
|
|
|
|
ROOM=$(echo "$CREATED" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).room_id))')
|
|
URL_A=$(echo "$CREATED" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).invite_urls[0]))')
|
|
URL_B=$(echo "$CREATED" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).invite_urls[1]))')
|
|
OBSERVER=$(echo "$CREATED" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).observer_url))')
|
|
TOKEN_A="${URL_A##*/}"
|
|
TOKEN_B="${URL_B##*/}"
|
|
PID_A=$(echo "$CREATED" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).participants[0].id))')
|
|
|
|
echo "Room: $ROOM"
|
|
echo "Observer URL for the human (read-only, whose turn it is): $OBSERVER"
|
|
echo "Invite URL for Agent B (the human forwards this ONCE): $URL_B"
|
|
|
|
echo
|
|
echo "== Agent B opens its invite URL in agent-readable form =="
|
|
curl -sf "$URL_B.md" | head -30
|
|
echo " ..."
|
|
|
|
echo
|
|
echo "== Round 1: A states verified facts =="
|
|
post "$ROOM" "$TOKEN_A" '{"content":"Verified on my side: IIS site APP publishes /exchange/hs (basic auth, account svc_exchange). 1C regagent job exists but I have not yet confirmed its schedule."}' messages >/dev/null
|
|
echo "A posted facts."
|
|
|
|
echo
|
|
echo "== Round 2: B asks a blocking question =="
|
|
Q=$(post "$ROOM" "$TOKEN_B" '{"question":"Check IIS logs for svc_exchange during the last 7 days: which endpoints were actually called and how often?","blocking":true,"addressed_to_participant_id":"'"$PID_A"'"}' questions)
|
|
QID=$(echo "$Q" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).id))')
|
|
echo "B opened blocking question $QID"
|
|
|
|
echo
|
|
echo "== A asks the server what to do next =="
|
|
curl -sf -H "authorization: Bearer $TOKEN_A" "$BASE/api/rooms/$ROOM" \
|
|
| node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log("what_you_should_do_next:",JSON.parse(s).what_you_should_do_next))'
|
|
|
|
echo
|
|
echo "== Round 3: A verifies on its machine and resolves =="
|
|
post "$ROOM" "$TOKEN_A" '{"content":"Checked IIS logs (7 days): only /exchange/hs was called, every 15 minutes, all calls HTTP 200 except two 500s on 2026-09-01 (1C restart)."}' messages >/dev/null
|
|
post "$ROOM" "$TOKEN_A" '{"resolution":"Verified in IIS logs over 7 days: endpoint /exchange/hs, every 15 minutes, caller svc_exchange."}' "questions/$QID/resolve" >/dev/null
|
|
echo "Question resolved."
|
|
|
|
echo
|
|
echo "== Round 4: B finds another contradiction and asks again =="
|
|
Q2=$(post "$ROOM" "$TOKEN_B" '{"question":"App code expects /api/v1/sync, not /exchange/hs — is the app calling the old path, or is there a mapping in the integration layer?","blocking":true,"addressed_to_participant_id":"'"$PID_A"'"}' questions)
|
|
Q2ID=$(echo "$Q2" | node -e 'let s="";process.stdin.on("data",d=>s+=d).on("end",()=>console.log(JSON.parse(s).id))')
|
|
post "$ROOM" "$TOKEN_A" '{"content":"IIS rewrite rule maps /api/v1/sync -> /exchange/hs (checked applicationHost.config). No other mapping exists."}' messages >/dev/null
|
|
post "$ROOM" "$TOKEN_A" '{"resolution":"Verified rewrite rule in applicationHost.config: /api/v1/sync is mapped to /exchange/hs. Single endpoint."}' "questions/$Q2ID/resolve" >/dev/null
|
|
echo "Second contradiction resolved."
|
|
|
|
echo
|
|
echo "== Round 5: B drafts the Agreed Contract =="
|
|
put "$ROOM" "$TOKEN_B" '{"markdown":"## Facts\n- Single endpoint: /api/v1/sync (IIS-rewritten to /exchange/hs)\n- Schedule: every 15 minutes, caller svc_exchange\n- Observed errors: two HTTP 500 on 2026-09-01 during 1C restart\n\n## Decisions\n- App keeps calling /api/v1/sync; no new endpoint\n\n## Interface\n- POST /api/v1/sync, JSON body per existing schema\n\n## Schedule\n- Every 15 minutes\n\n## Authentication\n- HTTP Basic, service account svc_exchange\n\n## Error handling\n- HTTP 5xx: retry up to 3 times with backoff; log and alert on repeated failures\n\n## Unresolved\n- none"}' contract >/dev/null
|
|
echo "Contract proposed."
|
|
|
|
echo
|
|
echo "== Both sides agree -> room finalized =="
|
|
post "$ROOM" "$TOKEN_B" '{}' agree >/dev/null
|
|
FINAL=$(post "$ROOM" "$TOKEN_A" '{}' agree)
|
|
echo "$FINAL"
|
|
|
|
echo
|
|
echo "== Final artifact =="
|
|
curl -sf -H "authorization: Bearer $TOKEN_A" "$BASE/api/rooms/$ROOM/final.md"
|
|
|
|
echo
|
|
echo "== Demo complete. The room disappears automatically after its TTL. =="
|