import assert from 'node:assert/strict' import { mkdir, mkdtemp, writeFile } from 'node:fs/promises' import { createServer } from 'node:http' import { tmpdir } from 'node:os' import { join } from 'node:path' import { test } from 'node:test' import { startService } from '../service/main.ts' import type { TgUpdateRaw } from '../shared/telegram.ts' import { loadAgentConfig } from './config.ts' import { startAgent } from './main.ts' /** * Walking skeleton (vertical slice): telegram mention -> durable wake -> * fake resident session turn -> readiness flips healthy. Uses the real * service, real telegram runtime against a fake Telegram, real queue and * spool; only the model session is faked (WILL_SESSION_MODE=fake). */ test('end to end: mention reaches the resident session and readiness is healthy', async () => { const updates: TgUpdateRaw[] = [] const sent: { method: string }[] = [] const tgServer = createServer((req, res) => { const url = new URL(req.url ?? '/', 'http://x') let data = '' req.on('data', (c: Buffer) => { data += c.toString() }) req.on('end', () => { let body: Record = {} try { body = data === '' ? {} : (JSON.parse(data) as Record) } catch { body = {} } const json = (p: unknown) => { res.writeHead(200, { 'content-type': 'application/json' }) res.end(JSON.stringify(p)) } const method = url.pathname.split('/').pop() ?? '' switch (method) { case 'getMe': return json({ ok: true, result: { id: 42, username: 'will_bot' } }) case 'getUpdates': return json({ ok: true, result: updates.filter((u) => u.update_id >= ((body.offset as number) ?? 0)), }) case 'getFile': return json({ ok: true, result: { file_id: 'f', file_path: 'x' } }) default: sent.push({ method }) return json({ ok: true, result: { message_id: 1 } }) } }) }) await new Promise((r) => tgServer.listen(0, '127.0.0.1', () => r())) const tgUrl = `http://127.0.0.1:${(tgServer.address() as { port: number }).port}` const dir = await mkdtemp(join(tmpdir(), 'e2e-')) const webDist = join(dir, 'web-dist') const resourceDir = join(dir, 'resources') await mkdir(webDist, { recursive: true }) await mkdir(join(resourceDir, 'persona'), { recursive: true }) await writeFile(join(resourceDir, 'persona', '10-identity.md'), '# identity\nI am will.', 'utf8') const service = await startService({ dataDir: join(dir, 'data'), publicAddr: '127.0.0.1:0', internalAddr: '127.0.0.1:0', webDist, docsDist: webDist, mediaMaxBytes: 100 << 20, storageWarnPct: 20, storageStopPct: 10, workerUrl: join(import.meta.dirname, '../service/worker.ts'), }) const intPort = (service.internalServer.address() as { port: number }).port const prev = { ...process.env } process.env.WILL_SESSION_MODE = 'fake' process.env.WILL_AGENT_DIR = join(dir, 'agent') process.env.WILL_RESOURCE_DIR = resourceDir process.env.WILL_SERVICE_INTERNAL_URL = `http://127.0.0.1:${intPort}` process.env.WILL_AGENT_READY_ADDR = '127.0.0.1:0' process.env.WILL_TELEGRAM_TOKEN = 'TOKEN' process.env.WILL_TELEGRAM_CHAT_ID = '-100' process.env.WILL_TELEGRAM_OLIVER_ID = '1' process.env.WILL_TELEGRAM_API_BASE = tgUrl process.env.ZAI_BASE_URL = tgUrl // unused without a key; keeps config total delete process.env.WILL_VCS_GIT_URL try { updates.push({ update_id: 1, message: { message_id: 7, date: Math.floor(Date.now() / 1000), chat: { id: -100 }, from: { id: 5, username: 'friend' }, text: 'hey @will_bot are you alive', entities: [{ type: 'mention', offset: 4, length: 9 }], }, }) const agent = await startAgent(loadAgentConfig()) // wait for the wake to be consumed by the fake session const fake = agent.session as unknown as { prompts: string[] } const deadline = Date.now() + 15_000 while ((fake.prompts.length === 0 || !fake.prompts[0]) && Date.now() < deadline) { await new Promise((r) => setTimeout(r, 100)) } assert.ok(fake.prompts[0], 'resident session received a wake prompt') assert.match(fake.prompts[0], /