1 line
37 KiB
JSON
1 line
37 KiB
JSON
{"repo": "aganfebro/areyouai", "files": {"scripts/deepseek_agents.js": {"9d205aebe70154b6ca57e0d989cbd7698c7c5121": {"t": 1785746690.241629, "n": 11384, "h": "967024c926b8fa34", "c": "#!/usr/bin/env node\n\n/**\n * Simulate 2 agents using DeepSeek API against areyouai backend\n * with an SSE-driven turn loop.\n *\n * Required:\n * DEEPSEEK_API_KEY=...\n *\n * Optional:\n * AREYOUAI_API_BASE_URL=http://localhost:8080\n * API_BASE_URL=http://localhost:8080 (legacy fallback)\n * DEEPSEEK_MODEL=deepseek-chat\n * TOPIC=\"AI safety debate\"\n * MAX_TURNS=6\n * SSE_WAIT_TIMEOUT_MS=60000\n */\n\nconst fs = require(\"node:fs\");\nconst path = require(\"node:path\");\n\nloadDotEnv();\n\nconst API_BASE_URL =\n process.env.AREYOUAI_API_BASE_URL || process.env.API_BASE_URL || \"http://localhost:8080\";\nconst DEEPSEEK_API_KEY = process.env.DEEPSEEK_API_KEY || \"\";\nconst DEEPSEEK_MODEL = process.env.DEEPSEEK_MODEL || \"deepseek-chat\";\nconst DEEPSEEK_TEMPERATURE = Number(process.env.DEEPSEEK_TEMPERATURE || \"0.9\");\nconst TOPIC = process.env.TOPIC || \"Should agents disclose uncertainty?\";\nconst MAX_TURNS = Number(process.env.MAX_TURNS || \"6\");\nconst SSE_WAIT_TIMEOUT_MS = Number(process.env.SSE_WAIT_TIMEOUT_MS || \"60000\");\nconst RUN_NONCE = Math.random().toString(36).slice(2, 8);\n\nif (!DEEPSEEK_API_KEY) {\n console.error(\"DEEPSEEK_API_KEY is required\");\n process.exit(1);\n}\n\nasync function main() {\n console.log(\"API:\", API_BASE_URL);\n console.log(\"Topic:\", TOPIC);\n console.log(\"Turns:\", MAX_TURNS);\n\n const a = await registerAndLogin(\"deepseek-agent-a\");\n const b = await registerAndLogin(\"deepseek-agent-b\");\n\n const listing = await api(\"/v1/listings\", {\n method: \"POST\",\n token: a.token,\n body: {\n topic: TOPIC,\n tags: [\"deepseek\", \"auto\"],\n max_turns: MAX_TURNS,\n ttl_seconds: 900,\n },\n });\n\n const connected = await api(`/v1/listings/${listing.id}/connect`, {\n method: \"POST\",\n token: b.token,\n });\n\n const roomID = connected.room_id;\n const humanCode = connected.human_code;\n console.log(\"room_id:\", roomID);\n console.log(\"human_code:\", humanCode);\n\n await api(`/v1/rooms/${roomID}/join`, { method: \"POST\", token: a.token });\n await api(`/v1/rooms/${roomID}/join`, { method: \"POST\", token: b.token });\n\n const transcript = [];\n let lastEventID = await getBaselineEventID(roomID, a.token);\n let turn = 0;\n while (turn < MAX_TURNS) {\n const speaker = turn % 2 === 0 ? a : b;\n const partner = turn % 2 === 0 ? b : a;\n const context = await api(`/v1/rooms/${roomID}/context`, {\n method: \"GET\",\n token: speaker.token,\n });\n const state = String(context.state || \"\").toUpperCase();\n const contextTurn = Number(context.turn_index ?? turn);\n if (state === \"CLOSED\" || state === \"PURGED\") {\n break;\n }\n if (!Number.isFinite(contextTurn)) {\n throw new Error(`invalid context turn_index: ${context.turn_index}`);\n }\n if (contextTurn !== turn) {\n const ev = await waitForNextRoomEvent({\n roomID,\n token: a.token,\n sinceEventID: lastEventID,\n timeoutMs: SSE_WAIT_TIMEOUT_MS,\n });\n lastEventID = Math.max(lastEventID, Number(ev.event_id || 0));\n continue;\n }\n\n const text = await askDeepSeek({\n speakerName: speaker.name,\n partnerName: partner.name,\n topic: TOPIC,\n transcript,\n backendBundleText: context.prompt_bundle_text || \"\",\n });\n\n let sent;\n try {\n sent = await api(`/v1/rooms/${roomID}/messages`, {\n method: \"POST\",\n token: speaker.token,\n body: {\n expected_turn: turn,\n ciphertext: text,\n bundle_hash: context.bundle_hash,\n },\n });\n } catch (err) {\n if (err instanceof APIError && err.status === 409) {\n const ev = await waitForNextRoomEvent({\n roomID,\n token: a.token,\n sinceEventID: lastEventID,\n timeoutMs: SSE_WAIT_TIMEOUT_MS,\n });\n lastEventID = Math.max(lastEventID, Number(ev.event_id || 0));\n continue;\n }\n throw err;\n }\n\n transcript.push({\n turn,\n sender: speaker.name,\n ciphertext: text,\n message_id: sent.message_id,\n });\n console.log(`[turn ${turn}] ${speaker.name}: ${text.slice(0, 90)}`);\n turn += 1;\n\n if (turn < MAX_TURNS) {\n const ev = await waitForNextRoomEvent({\n roomID,\n token: a.token,\n sinceEventID: lastEventID,\n timeoutMs: SSE_WAIT_TIMEOUT_MS,\n });\n lastEventID = Math.max(lastEventID, Number(ev.event_id || 0));\n const eventType = String(ev.type || \"\");\n if (eventType === \"room.closed\" || eventType === \"room.purged\") {\n break;\n }\n }\n }\n\n const finalTranscript = await api(\n `/v1/rooms/${roomID}/transcript?human_code=${encodeURIComponent(humanCode)}`,\n { method: \"GET\" },\n );\n\n console.log(\"\\nTranscript messages:\", finalTranscript.messages?.length ?? 0);\n for (const m of finalTranscript.messages || []) {\n const turn = m.turn ?? m.Turn;\n const sender = m.sender_id ?? m.SenderID;\n const text = m.ciphertext ?? m.Ciphertext;\n console.log(`- turn ${turn} | ${sender}: ${String(text).slice(0, 120)}`);\n }\n}\n\nasync function registerAndLogin(name) {\n const reg = await api(\"/v1/agent/register\", {\n method: \"POST\",\n body: { name },\n });\n const login = await api(\"/v1/agent/login\", {\n method: \"POST\",\n body: { api_key: reg.api_key },\n });\n return {\n id: reg.agent_id,\n name,\n token: login.session_token,\n };\n}\n\nasync function askDeepSeek({ speakerName, partnerName, topic, transcript, backendBundleText }) {\n const convo = transcript\n .map((m) => `turn ${m.turn} | ${m.sender}: ${m.ciphertext}`)\n .join(\"\\n\");\n\n const prompt = [\n `Topic: ${topic}`,\n `You are ${speakerName}.`,\n `You are talking to ${partnerName} in a concise 1:1 agent chat.`,\n \"Rules:\",\n \"- 1 to 2 short sentences.\",\n \"- Stay on topic.\",\n \"- No markdown, no labels, plain text only.\",\n \"\",\n \"Recent transcript:\",\n `Run nonce: ${RUN_NONCE}`,\n convo || \"(empty)\",\n \"\",\n \"Your next message:\",\n ].join(\"\\n\");\n\n const res = await fetch(\"https://api.deepseek.com/chat/completions\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${DEEPSEEK_API_KEY}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: DEEPSEEK_MODEL,\n temperature: DEEPSEEK_TEMPERATURE,\n messages: [\n {\n role: \"system\",\n content:\n \"You are an autonomous agent in a private agent-to-agent room.\\n\" +\n \"Use the authoritative backend context bundle below.\\n\\n\" +\n \"=== BACKEND_CONTEXT_BUNDLE ===\\n\" +\n (backendBundleText || \"(missing)\"),\n },\n { role: \"user\", content: prompt },\n ],\n }),\n });\n\n const data = await res.json();\n if (!res.ok) {\n throw new Error(`DeepSeek error ${res.status}: ${JSON.stringify(data)}`);\n }\n const content = data?.choices?.[0]?.message?.content;\n if (!content || typeof content !== \"string\") {\n throw new Error(`DeepSeek response missing content: ${JSON.stringify(data)}`);\n }\n return content.trim();\n}\n\nasync function api(path, { method, body, token } = {}) {\n const res = await fetch(`${API_BASE_URL}${path}`, {\n method: method || \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) {\n throw new APIError(\n `API ${method || \"GET\"} ${path} failed ${res.status}: ${JSON.stringify(data)}`,\n res.status,\n data,\n );\n }\n return data;\n}\n\nasync function getBaselineEventID(roomID, token) {\n const out = await api(`/v1/rooms/${roomID}/events/history?limit=1`, {\n method: \"GET\",\n token,\n });\n return Number(out.next_since || 0);\n}\n\nasync function waitForNextRoomEvent({ roomID, token, sinceEventID, timeoutMs }) {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await fetch(\n `${API_BASE_URL}/v1/rooms/${roomID}/events?since=${encodeURIComponent(String(sinceEventID || 0))}`,\n {\n method: \"GET\",\n headers: {\n Accept: \"text/event-stream\",\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n signal: controller.signal,\n },\n );\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new APIError(`SSE /events failed ${res.status}: ${body}`, res.status, body);\n }\n if (!res.body) {\n throw new Error(\"SSE response missing body stream\");\n }\n return await readFirstSSEDataFrame(res.body);\n } catch (err) {\n if (err && err.name === \"AbortError\") {\n throw new Error(`timed out waiting room event after ${timeoutMs}ms`);\n }\n throw err;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nasync function readFirstSSEDataFrame(stream) {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let eventType = \"\";\n let data = \"\";\n try {\n for (;;) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n for (;;) {\n const idx = buffer.indexOf(\"\\n\");\n if (idx < 0) break;\n let line = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 1);\n if (line.endsWith(\"\\r\")) line = line.slice(0, -1);\n if (line === \"\") {\n if (eventType && data) {\n const payload = JSON.parse(data);\n payload.type = payload.type || eventType;\n return payload;\n }\n eventType = \"\";\n data = \"\";\n continue;\n }\n if (line.startsWith(\":\") || line.startsWith(\"retry:\")) continue;\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(\"event:\".length).trim();\n continue;\n }\n if (line.startsWith(\"data:\")) {\n const chunk = line.slice(\"data:\".length).trim();\n data = data ? `${data}\\n${chunk}` : chunk;\n }\n }\n }\n } finally {\n reader.releaseLock();\n if (typeof stream.cancel === \"function\") {\n try {\n await stream.cancel();\n } catch {\n // Ignore stream cancel races.\n }\n }\n }\n throw new Error(\"SSE stream ended before receiving event data\");\n}\n\nclass APIError extends Error {\n constructor(message, status, body) {\n super(message);\n this.name = \"APIError\";\n this.status = status;\n this.body = body;\n }\n}\n\nmain().catch((err) => {\n console.error(err.message || err);\n process.exit(1);\n});\n\nfunction loadDotEnv() {\n const file = path.resolve(process.cwd(), \".env\");\n if (!fs.existsSync(file)) return;\n\n const content = fs.readFileSync(file, \"utf8\");\n const lines = content.split(/\\r?\\n/);\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (!line || line.startsWith(\"#\")) continue;\n const idx = line.indexOf(\"=\");\n if (idx <= 0) continue;\n\n const key = line.slice(0, idx).trim();\n if (!key) continue;\n let value = line.slice(idx + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n // Environment passed at runtime wins over .env values.\n if (process.env[key] === undefined) {\n process.env[key] = value;\n }\n }\n}\n"}, "96f43a468dc5afb35010a2c26e26e4a82f18ecb2": {"t": 1785766917.6275964, "n": 11384, "h": "967024c926b8fa34", "c": "#!/usr/bin/env node\n\n/**\n * Simulate 2 agents using DeepSeek API against areyouai backend\n * with an SSE-driven turn loop.\n *\n * Required:\n * DEEPSEEK_API_KEY=...\n *\n * Optional:\n * AREYOUAI_API_BASE_URL=http://localhost:8080\n * API_BASE_URL=http://localhost:8080 (legacy fallback)\n * DEEPSEEK_MODEL=deepseek-chat\n * TOPIC=\"AI safety debate\"\n * MAX_TURNS=6\n * SSE_WAIT_TIMEOUT_MS=60000\n */\n\nconst fs = require(\"node:fs\");\nconst path = require(\"node:path\");\n\nloadDotEnv();\n\nconst API_BASE_URL =\n process.env.AREYOUAI_API_BASE_URL || process.env.API_BASE_URL || \"http://localhost:8080\";\nconst DEEPSEEK_API_KEY = process.env.DEEPSEEK_API_KEY || \"\";\nconst DEEPSEEK_MODEL = process.env.DEEPSEEK_MODEL || \"deepseek-chat\";\nconst DEEPSEEK_TEMPERATURE = Number(process.env.DEEPSEEK_TEMPERATURE || \"0.9\");\nconst TOPIC = process.env.TOPIC || \"Should agents disclose uncertainty?\";\nconst MAX_TURNS = Number(process.env.MAX_TURNS || \"6\");\nconst SSE_WAIT_TIMEOUT_MS = Number(process.env.SSE_WAIT_TIMEOUT_MS || \"60000\");\nconst RUN_NONCE = Math.random().toString(36).slice(2, 8);\n\nif (!DEEPSEEK_API_KEY) {\n console.error(\"DEEPSEEK_API_KEY is required\");\n process.exit(1);\n}\n\nasync function main() {\n console.log(\"API:\", API_BASE_URL);\n console.log(\"Topic:\", TOPIC);\n console.log(\"Turns:\", MAX_TURNS);\n\n const a = await registerAndLogin(\"deepseek-agent-a\");\n const b = await registerAndLogin(\"deepseek-agent-b\");\n\n const listing = await api(\"/v1/listings\", {\n method: \"POST\",\n token: a.token,\n body: {\n topic: TOPIC,\n tags: [\"deepseek\", \"auto\"],\n max_turns: MAX_TURNS,\n ttl_seconds: 900,\n },\n });\n\n const connected = await api(`/v1/listings/${listing.id}/connect`, {\n method: \"POST\",\n token: b.token,\n });\n\n const roomID = connected.room_id;\n const humanCode = connected.human_code;\n console.log(\"room_id:\", roomID);\n console.log(\"human_code:\", humanCode);\n\n await api(`/v1/rooms/${roomID}/join`, { method: \"POST\", token: a.token });\n await api(`/v1/rooms/${roomID}/join`, { method: \"POST\", token: b.token });\n\n const transcript = [];\n let lastEventID = await getBaselineEventID(roomID, a.token);\n let turn = 0;\n while (turn < MAX_TURNS) {\n const speaker = turn % 2 === 0 ? a : b;\n const partner = turn % 2 === 0 ? b : a;\n const context = await api(`/v1/rooms/${roomID}/context`, {\n method: \"GET\",\n token: speaker.token,\n });\n const state = String(context.state || \"\").toUpperCase();\n const contextTurn = Number(context.turn_index ?? turn);\n if (state === \"CLOSED\" || state === \"PURGED\") {\n break;\n }\n if (!Number.isFinite(contextTurn)) {\n throw new Error(`invalid context turn_index: ${context.turn_index}`);\n }\n if (contextTurn !== turn) {\n const ev = await waitForNextRoomEvent({\n roomID,\n token: a.token,\n sinceEventID: lastEventID,\n timeoutMs: SSE_WAIT_TIMEOUT_MS,\n });\n lastEventID = Math.max(lastEventID, Number(ev.event_id || 0));\n continue;\n }\n\n const text = await askDeepSeek({\n speakerName: speaker.name,\n partnerName: partner.name,\n topic: TOPIC,\n transcript,\n backendBundleText: context.prompt_bundle_text || \"\",\n });\n\n let sent;\n try {\n sent = await api(`/v1/rooms/${roomID}/messages`, {\n method: \"POST\",\n token: speaker.token,\n body: {\n expected_turn: turn,\n ciphertext: text,\n bundle_hash: context.bundle_hash,\n },\n });\n } catch (err) {\n if (err instanceof APIError && err.status === 409) {\n const ev = await waitForNextRoomEvent({\n roomID,\n token: a.token,\n sinceEventID: lastEventID,\n timeoutMs: SSE_WAIT_TIMEOUT_MS,\n });\n lastEventID = Math.max(lastEventID, Number(ev.event_id || 0));\n continue;\n }\n throw err;\n }\n\n transcript.push({\n turn,\n sender: speaker.name,\n ciphertext: text,\n message_id: sent.message_id,\n });\n console.log(`[turn ${turn}] ${speaker.name}: ${text.slice(0, 90)}`);\n turn += 1;\n\n if (turn < MAX_TURNS) {\n const ev = await waitForNextRoomEvent({\n roomID,\n token: a.token,\n sinceEventID: lastEventID,\n timeoutMs: SSE_WAIT_TIMEOUT_MS,\n });\n lastEventID = Math.max(lastEventID, Number(ev.event_id || 0));\n const eventType = String(ev.type || \"\");\n if (eventType === \"room.closed\" || eventType === \"room.purged\") {\n break;\n }\n }\n }\n\n const finalTranscript = await api(\n `/v1/rooms/${roomID}/transcript?human_code=${encodeURIComponent(humanCode)}`,\n { method: \"GET\" },\n );\n\n console.log(\"\\nTranscript messages:\", finalTranscript.messages?.length ?? 0);\n for (const m of finalTranscript.messages || []) {\n const turn = m.turn ?? m.Turn;\n const sender = m.sender_id ?? m.SenderID;\n const text = m.ciphertext ?? m.Ciphertext;\n console.log(`- turn ${turn} | ${sender}: ${String(text).slice(0, 120)}`);\n }\n}\n\nasync function registerAndLogin(name) {\n const reg = await api(\"/v1/agent/register\", {\n method: \"POST\",\n body: { name },\n });\n const login = await api(\"/v1/agent/login\", {\n method: \"POST\",\n body: { api_key: reg.api_key },\n });\n return {\n id: reg.agent_id,\n name,\n token: login.session_token,\n };\n}\n\nasync function askDeepSeek({ speakerName, partnerName, topic, transcript, backendBundleText }) {\n const convo = transcript\n .map((m) => `turn ${m.turn} | ${m.sender}: ${m.ciphertext}`)\n .join(\"\\n\");\n\n const prompt = [\n `Topic: ${topic}`,\n `You are ${speakerName}.`,\n `You are talking to ${partnerName} in a concise 1:1 agent chat.`,\n \"Rules:\",\n \"- 1 to 2 short sentences.\",\n \"- Stay on topic.\",\n \"- No markdown, no labels, plain text only.\",\n \"\",\n \"Recent transcript:\",\n `Run nonce: ${RUN_NONCE}`,\n convo || \"(empty)\",\n \"\",\n \"Your next message:\",\n ].join(\"\\n\");\n\n const res = await fetch(\"https://api.deepseek.com/chat/completions\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${DEEPSEEK_API_KEY}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: DEEPSEEK_MODEL,\n temperature: DEEPSEEK_TEMPERATURE,\n messages: [\n {\n role: \"system\",\n content:\n \"You are an autonomous agent in a private agent-to-agent room.\\n\" +\n \"Use the authoritative backend context bundle below.\\n\\n\" +\n \"=== BACKEND_CONTEXT_BUNDLE ===\\n\" +\n (backendBundleText || \"(missing)\"),\n },\n { role: \"user\", content: prompt },\n ],\n }),\n });\n\n const data = await res.json();\n if (!res.ok) {\n throw new Error(`DeepSeek error ${res.status}: ${JSON.stringify(data)}`);\n }\n const content = data?.choices?.[0]?.message?.content;\n if (!content || typeof content !== \"string\") {\n throw new Error(`DeepSeek response missing content: ${JSON.stringify(data)}`);\n }\n return content.trim();\n}\n\nasync function api(path, { method, body, token } = {}) {\n const res = await fetch(`${API_BASE_URL}${path}`, {\n method: method || \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) {\n throw new APIError(\n `API ${method || \"GET\"} ${path} failed ${res.status}: ${JSON.stringify(data)}`,\n res.status,\n data,\n );\n }\n return data;\n}\n\nasync function getBaselineEventID(roomID, token) {\n const out = await api(`/v1/rooms/${roomID}/events/history?limit=1`, {\n method: \"GET\",\n token,\n });\n return Number(out.next_since || 0);\n}\n\nasync function waitForNextRoomEvent({ roomID, token, sinceEventID, timeoutMs }) {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n try {\n const res = await fetch(\n `${API_BASE_URL}/v1/rooms/${roomID}/events?since=${encodeURIComponent(String(sinceEventID || 0))}`,\n {\n method: \"GET\",\n headers: {\n Accept: \"text/event-stream\",\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n signal: controller.signal,\n },\n );\n if (!res.ok) {\n const body = await res.text().catch(() => \"\");\n throw new APIError(`SSE /events failed ${res.status}: ${body}`, res.status, body);\n }\n if (!res.body) {\n throw new Error(\"SSE response missing body stream\");\n }\n return await readFirstSSEDataFrame(res.body);\n } catch (err) {\n if (err && err.name === \"AbortError\") {\n throw new Error(`timed out waiting room event after ${timeoutMs}ms`);\n }\n throw err;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nasync function readFirstSSEDataFrame(stream) {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let eventType = \"\";\n let data = \"\";\n try {\n for (;;) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n for (;;) {\n const idx = buffer.indexOf(\"\\n\");\n if (idx < 0) break;\n let line = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 1);\n if (line.endsWith(\"\\r\")) line = line.slice(0, -1);\n if (line === \"\") {\n if (eventType && data) {\n const payload = JSON.parse(data);\n payload.type = payload.type || eventType;\n return payload;\n }\n eventType = \"\";\n data = \"\";\n continue;\n }\n if (line.startsWith(\":\") || line.startsWith(\"retry:\")) continue;\n if (line.startsWith(\"event:\")) {\n eventType = line.slice(\"event:\".length).trim();\n continue;\n }\n if (line.startsWith(\"data:\")) {\n const chunk = line.slice(\"data:\".length).trim();\n data = data ? `${data}\\n${chunk}` : chunk;\n }\n }\n }\n } finally {\n reader.releaseLock();\n if (typeof stream.cancel === \"function\") {\n try {\n await stream.cancel();\n } catch {\n // Ignore stream cancel races.\n }\n }\n }\n throw new Error(\"SSE stream ended before receiving event data\");\n}\n\nclass APIError extends Error {\n constructor(message, status, body) {\n super(message);\n this.name = \"APIError\";\n this.status = status;\n this.body = body;\n }\n}\n\nmain().catch((err) => {\n console.error(err.message || err);\n process.exit(1);\n});\n\nfunction loadDotEnv() {\n const file = path.resolve(process.cwd(), \".env\");\n if (!fs.existsSync(file)) return;\n\n const content = fs.readFileSync(file, \"utf8\");\n const lines = content.split(/\\r?\\n/);\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (!line || line.startsWith(\"#\")) continue;\n const idx = line.indexOf(\"=\");\n if (idx <= 0) continue;\n\n const key = line.slice(0, idx).trim();\n if (!key) continue;\n let value = line.slice(idx + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n // Environment passed at runtime wins over .env values.\n if (process.env[key] === undefined) {\n process.env[key] = value;\n }\n }\n}\n"}, "1fe09056605023d5599f5c58cc4e799419e76e86": {"t": 1785766918.9279592, "n": 6755, "h": "376b569427fd883b", "c": "#!/usr/bin/env node\n\n/**\n * Simulate 2 agents using DeepSeek API against areyouai backend.\n *\n * Required:\n * DEEPSEEK_API_KEY=...\n *\n * Optional:\n * AREYOUAI_API_BASE_URL=http://localhost:8080\n * API_BASE_URL=http://localhost:8080 (legacy fallback)\n * DEEPSEEK_MODEL=deepseek-chat\n * TOPIC=\"AI safety debate\"\n * MAX_TURNS=6\n */\n\nconst fs = require(\"node:fs\");\nconst path = require(\"node:path\");\n\nloadDotEnv();\n\nconst API_BASE_URL =\n process.env.AREYOUAI_API_BASE_URL || process.env.API_BASE_URL || \"http://localhost:8080\";\nconst DEEPSEEK_API_KEY = process.env.DEEPSEEK_API_KEY || \"\";\nconst DEEPSEEK_MODEL = process.env.DEEPSEEK_MODEL || \"deepseek-chat\";\nconst DEEPSEEK_TEMPERATURE = Number(process.env.DEEPSEEK_TEMPERATURE || \"0.9\");\nconst TOPIC = process.env.TOPIC || \"Should agents disclose uncertainty?\";\nconst MAX_TURNS = Number(process.env.MAX_TURNS || \"6\");\nconst RUN_NONCE = Math.random().toString(36).slice(2, 8);\n\nif (!DEEPSEEK_API_KEY) {\n console.error(\"DEEPSEEK_API_KEY is required\");\n process.exit(1);\n}\n\nasync function main() {\n console.log(\"API:\", API_BASE_URL);\n console.log(\"Topic:\", TOPIC);\n console.log(\"Turns:\", MAX_TURNS);\n\n const a = await registerAndLogin(\"deepseek-agent-a\");\n const b = await registerAndLogin(\"deepseek-agent-b\");\n\n const listing = await api(\"/v1/listings\", {\n method: \"POST\",\n token: a.token,\n body: {\n topic: TOPIC,\n tags: [\"deepseek\", \"auto\"],\n max_turns: MAX_TURNS,\n ttl_seconds: 900,\n },\n });\n\n const connected = await api(`/v1/listings/${listing.id}/connect`, {\n method: \"POST\",\n token: b.token,\n });\n\n const roomID = connected.room_id;\n const humanCode = connected.human_code;\n console.log(\"room_id:\", roomID);\n console.log(\"human_code:\", humanCode);\n\n await api(`/v1/rooms/${roomID}/join`, { method: \"POST\", token: a.token });\n await api(`/v1/rooms/${roomID}/join`, { method: \"POST\", token: b.token });\n\n const transcript = [];\n\n for (let turn = 0; turn < MAX_TURNS; turn += 1) {\n const speaker = turn % 2 === 0 ? a : b;\n const partner = turn % 2 === 0 ? b : a;\n const context = await api(`/v1/rooms/${roomID}/context`, {\n method: \"GET\",\n token: speaker.token,\n });\n\n const text = await askDeepSeek({\n speakerName: speaker.name,\n partnerName: partner.name,\n topic: TOPIC,\n transcript,\n backendBundleText: context.prompt_bundle_text || \"\",\n });\n\n const sent = await api(`/v1/rooms/${roomID}/messages`, {\n method: \"POST\",\n token: speaker.token,\n body: {\n expected_turn: turn,\n ciphertext: text,\n bundle_hash: context.bundle_hash,\n },\n });\n\n transcript.push({\n turn,\n sender: speaker.name,\n ciphertext: text,\n message_id: sent.message_id,\n });\n console.log(`[turn ${turn}] ${speaker.name}: ${text.slice(0, 90)}`);\n }\n\n const finalTranscript = await api(\n `/v1/rooms/${roomID}/transcript?human_code=${encodeURIComponent(humanCode)}`,\n { method: \"GET\" },\n );\n\n console.log(\"\\nTranscript messages:\", finalTranscript.messages?.length ?? 0);\n for (const m of finalTranscript.messages || []) {\n const turn = m.turn ?? m.Turn;\n const sender = m.sender_id ?? m.SenderID;\n const text = m.ciphertext ?? m.Ciphertext;\n console.log(`- turn ${turn} | ${sender}: ${String(text).slice(0, 120)}`);\n }\n}\n\nasync function registerAndLogin(name) {\n const reg = await api(\"/v1/agent/register\", {\n method: \"POST\",\n body: { name },\n });\n const login = await api(\"/v1/agent/login\", {\n method: \"POST\",\n body: { api_key: reg.api_key },\n });\n return {\n id: reg.agent_id,\n name,\n token: login.session_token,\n };\n}\n\nasync function askDeepSeek({ speakerName, partnerName, topic, transcript, backendBundleText }) {\n const convo = transcript\n .map((m) => `turn ${m.turn} | ${m.sender}: ${m.ciphertext}`)\n .join(\"\\n\");\n\n const prompt = [\n `Topic: ${topic}`,\n `You are ${speakerName}.`,\n `You are talking to ${partnerName} in a concise 1:1 agent chat.`,\n \"Rules:\",\n \"- 1 to 2 short sentences.\",\n \"- Stay on topic.\",\n \"- No markdown, no labels, plain text only.\",\n \"\",\n \"Recent transcript:\",\n `Run nonce: ${RUN_NONCE}`,\n convo || \"(empty)\",\n \"\",\n \"Your next message:\",\n ].join(\"\\n\");\n\n const res = await fetch(\"https://api.deepseek.com/chat/completions\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${DEEPSEEK_API_KEY}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: DEEPSEEK_MODEL,\n temperature: DEEPSEEK_TEMPERATURE,\n messages: [\n {\n role: \"system\",\n content:\n \"You are an autonomous agent in a private agent-to-agent room.\\n\" +\n \"Use the authoritative backend context bundle below.\\n\\n\" +\n \"=== BACKEND_CONTEXT_BUNDLE ===\\n\" +\n (backendBundleText || \"(missing)\"),\n },\n { role: \"user\", content: prompt },\n ],\n }),\n });\n\n const data = await res.json();\n if (!res.ok) {\n throw new Error(`DeepSeek error ${res.status}: ${JSON.stringify(data)}`);\n }\n const content = data?.choices?.[0]?.message?.content;\n if (!content || typeof content !== \"string\") {\n throw new Error(`DeepSeek response missing content: ${JSON.stringify(data)}`);\n }\n return content.trim();\n}\n\nasync function api(path, { method, body, token } = {}) {\n const res = await fetch(`${API_BASE_URL}${path}`, {\n method: method || \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) {\n throw new Error(`API ${method || \"GET\"} ${path} failed ${res.status}: ${JSON.stringify(data)}`);\n }\n return data;\n}\n\nmain().catch((err) => {\n console.error(err.message || err);\n process.exit(1);\n});\n\nfunction loadDotEnv() {\n const file = path.resolve(process.cwd(), \".env\");\n if (!fs.existsSync(file)) return;\n\n const content = fs.readFileSync(file, \"utf8\");\n const lines = content.split(/\\r?\\n/);\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (!line || line.startsWith(\"#\")) continue;\n const idx = line.indexOf(\"=\");\n if (idx <= 0) continue;\n\n const key = line.slice(0, idx).trim();\n if (!key) continue;\n let value = line.slice(idx + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n // Environment passed at runtime wins over .env values.\n if (process.env[key] === undefined) {\n process.env[key] = value;\n }\n }\n}\n"}, "bcd9c1e7ec684f387389709a31418f33715fc530": {"t": 1785766920.6628866, "n": 6302, "h": "066dacb1954ef55b", "c": "#!/usr/bin/env node\n\n/**\n * Simulate 2 agents using DeepSeek API against areyouai backend.\n *\n * Required:\n * DEEPSEEK_API_KEY=...\n *\n * Optional:\n * AREYOUAI_API_BASE_URL=http://localhost:8080\n * API_BASE_URL=http://localhost:8080 (legacy fallback)\n * DEEPSEEK_MODEL=deepseek-chat\n * TOPIC=\"AI safety debate\"\n * MAX_TURNS=6\n */\n\nconst fs = require(\"node:fs\");\nconst path = require(\"node:path\");\n\nloadDotEnv();\n\nconst API_BASE_URL =\n process.env.AREYOUAI_API_BASE_URL || process.env.API_BASE_URL || \"http://localhost:8080\";\nconst DEEPSEEK_API_KEY = process.env.DEEPSEEK_API_KEY || \"\";\nconst DEEPSEEK_MODEL = process.env.DEEPSEEK_MODEL || \"deepseek-chat\";\nconst DEEPSEEK_TEMPERATURE = Number(process.env.DEEPSEEK_TEMPERATURE || \"0.9\");\nconst TOPIC = process.env.TOPIC || \"Should agents disclose uncertainty?\";\nconst MAX_TURNS = Number(process.env.MAX_TURNS || \"6\");\nconst RUN_NONCE = Math.random().toString(36).slice(2, 8);\n\nif (!DEEPSEEK_API_KEY) {\n console.error(\"DEEPSEEK_API_KEY is required\");\n process.exit(1);\n}\n\nasync function main() {\n console.log(\"API:\", API_BASE_URL);\n console.log(\"Topic:\", TOPIC);\n console.log(\"Turns:\", MAX_TURNS);\n\n const a = await registerAndLogin(\"deepseek-agent-a\");\n const b = await registerAndLogin(\"deepseek-agent-b\");\n\n const listing = await api(\"/v1/listings\", {\n method: \"POST\",\n token: a.token,\n body: {\n topic: TOPIC,\n tags: [\"deepseek\", \"auto\"],\n max_turns: MAX_TURNS,\n ttl_seconds: 900,\n },\n });\n\n const connected = await api(`/v1/listings/${listing.id}/connect`, {\n method: \"POST\",\n token: b.token,\n });\n\n const roomID = connected.room_id;\n const humanCode = connected.human_code;\n console.log(\"room_id:\", roomID);\n console.log(\"human_code:\", humanCode);\n\n await api(`/v1/rooms/${roomID}/join`, { method: \"POST\", token: a.token });\n await api(`/v1/rooms/${roomID}/join`, { method: \"POST\", token: b.token });\n\n const transcript = [];\n\n for (let turn = 0; turn < MAX_TURNS; turn += 1) {\n const speaker = turn % 2 === 0 ? a : b;\n const partner = turn % 2 === 0 ? b : a;\n\n const text = await askDeepSeek({\n speakerName: speaker.name,\n partnerName: partner.name,\n topic: TOPIC,\n transcript,\n });\n\n const sent = await api(`/v1/rooms/${roomID}/messages`, {\n method: \"POST\",\n token: speaker.token,\n body: {\n expected_turn: turn,\n ciphertext: text,\n },\n });\n\n transcript.push({\n turn,\n sender: speaker.name,\n ciphertext: text,\n message_id: sent.message_id,\n });\n console.log(`[turn ${turn}] ${speaker.name}: ${text.slice(0, 90)}`);\n }\n\n const finalTranscript = await api(\n `/v1/rooms/${roomID}/transcript?human_code=${encodeURIComponent(humanCode)}`,\n { method: \"GET\" },\n );\n\n console.log(\"\\nTranscript messages:\", finalTranscript.messages?.length ?? 0);\n for (const m of finalTranscript.messages || []) {\n const turn = m.turn ?? m.Turn;\n const sender = m.sender_id ?? m.SenderID;\n const text = m.ciphertext ?? m.Ciphertext;\n console.log(`- turn ${turn} | ${sender}: ${String(text).slice(0, 120)}`);\n }\n}\n\nasync function registerAndLogin(name) {\n const reg = await api(\"/v1/agent/register\", {\n method: \"POST\",\n body: { name },\n });\n const login = await api(\"/v1/agent/login\", {\n method: \"POST\",\n body: { api_key: reg.api_key },\n });\n return {\n id: reg.agent_id,\n name,\n token: login.session_token,\n };\n}\n\nasync function askDeepSeek({ speakerName, partnerName, topic, transcript }) {\n const convo = transcript\n .map((m) => `turn ${m.turn} | ${m.sender}: ${m.ciphertext}`)\n .join(\"\\n\");\n\n const prompt = [\n `Topic: ${topic}`,\n `You are ${speakerName}.`,\n `You are talking to ${partnerName} in a concise 1:1 agent chat.`,\n \"Rules:\",\n \"- 1 to 2 short sentences.\",\n \"- Stay on topic.\",\n \"- No markdown, no labels, plain text only.\",\n \"\",\n \"Recent transcript:\",\n `Run nonce: ${RUN_NONCE}`,\n convo || \"(empty)\",\n \"\",\n \"Your next message:\",\n ].join(\"\\n\");\n\n const res = await fetch(\"https://api.deepseek.com/chat/completions\", {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${DEEPSEEK_API_KEY}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n model: DEEPSEEK_MODEL,\n temperature: DEEPSEEK_TEMPERATURE,\n messages: [\n { role: \"system\", content: \"You are an autonomous agent in a private agent-to-agent room.\" },\n { role: \"user\", content: prompt },\n ],\n }),\n });\n\n const data = await res.json();\n if (!res.ok) {\n throw new Error(`DeepSeek error ${res.status}: ${JSON.stringify(data)}`);\n }\n const content = data?.choices?.[0]?.message?.content;\n if (!content || typeof content !== \"string\") {\n throw new Error(`DeepSeek response missing content: ${JSON.stringify(data)}`);\n }\n return content.trim();\n}\n\nasync function api(path, { method, body, token } = {}) {\n const res = await fetch(`${API_BASE_URL}${path}`, {\n method: method || \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n const data = await res.json().catch(() => ({}));\n if (!res.ok) {\n throw new Error(`API ${method || \"GET\"} ${path} failed ${res.status}: ${JSON.stringify(data)}`);\n }\n return data;\n}\n\nmain().catch((err) => {\n console.error(err.message || err);\n process.exit(1);\n});\n\nfunction loadDotEnv() {\n const file = path.resolve(process.cwd(), \".env\");\n if (!fs.existsSync(file)) return;\n\n const content = fs.readFileSync(file, \"utf8\");\n const lines = content.split(/\\r?\\n/);\n for (const rawLine of lines) {\n const line = rawLine.trim();\n if (!line || line.startsWith(\"#\")) continue;\n const idx = line.indexOf(\"=\");\n if (idx <= 0) continue;\n\n const key = line.slice(0, idx).trim();\n if (!key) continue;\n let value = line.slice(idx + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n\n // Environment passed at runtime wins over .env values.\n if (process.env[key] === undefined) {\n process.env[key] = value;\n }\n }\n}\n"}}}} |