Spaces:
Sleeping
Sleeping
File size: 5,282 Bytes
f762929 c630ac6 f762929 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | import { test, expect } from '@playwright/test'
import { API_KEY_HEADER } from './helpers'
test.describe('Direct CLI Integration', () => {
const createdConnectionIds: string[] = []
const createdAgentIds: number[] = []
test.afterEach(async ({ request }) => {
// Clean up connections
for (const connId of createdConnectionIds) {
await request.delete('/api/connect', {
headers: API_KEY_HEADER,
data: { connection_id: connId },
})
}
createdConnectionIds.length = 0
// Clean up auto-created agents
for (const agentId of createdAgentIds) {
await request.delete(`/api/agents/${agentId}`, { headers: API_KEY_HEADER })
}
createdAgentIds.length = 0
})
test('POST /api/connect creates connection and auto-creates agent', async ({ request }) => {
const agentName = `e2e-cli-${Date.now()}`
const res = await request.post('/api/connect', {
headers: API_KEY_HEADER,
data: {
tool_name: 'claude-code',
tool_version: '1.0.0',
agent_name: agentName,
agent_role: 'developer',
},
})
expect(res.status()).toBe(200)
const body = await res.json()
expect(body.connection_id).toBeDefined()
expect(body.agent_id).toBeDefined()
expect(body.agent_name).toBe(agentName)
expect(body.status).toBe('connected')
expect(body.sse_url).toBe('/api/events')
expect(body.heartbeat_url).toContain('/api/agents/')
expect(body.token_report_url).toBe('/api/tokens')
createdConnectionIds.push(body.connection_id)
createdAgentIds.push(body.agent_id)
// Verify agent was created
const agentRes = await request.get(`/api/agents/${body.agent_id}`, {
headers: API_KEY_HEADER,
})
expect(agentRes.status()).toBe(200)
const agentBody = await agentRes.json()
expect(agentBody.agent.name).toBe(agentName)
expect(agentBody.agent.status).toBe('online')
})
test('GET /api/connect lists connections', async ({ request }) => {
const agentName = `e2e-cli-list-${Date.now()}`
const postRes = await request.post('/api/connect', {
headers: API_KEY_HEADER,
data: {
tool_name: 'codex',
agent_name: agentName,
},
})
const postBody = await postRes.json()
createdConnectionIds.push(postBody.connection_id)
createdAgentIds.push(postBody.agent_id)
const res = await request.get('/api/connect', { headers: API_KEY_HEADER })
expect(res.status()).toBe(200)
const body = await res.json()
expect(Array.isArray(body.connections)).toBe(true)
const found = body.connections.find((c: any) => c.connection_id === postBody.connection_id)
expect(found).toBeDefined()
expect(found.agent_name).toBe(agentName)
expect(found.tool_name).toBe('codex')
})
test('POST heartbeat with inline token_usage', async ({ request }) => {
const agentName = `e2e-cli-hb-${Date.now()}`
const postRes = await request.post('/api/connect', {
headers: API_KEY_HEADER,
data: {
tool_name: 'claude-code',
agent_name: agentName,
},
})
const postBody = await postRes.json()
createdConnectionIds.push(postBody.connection_id)
createdAgentIds.push(postBody.agent_id)
const hbRes = await request.post(`/api/agents/${postBody.agent_id}/heartbeat`, {
headers: API_KEY_HEADER,
data: {
connection_id: postBody.connection_id,
token_usage: {
model: 'claude-sonnet-4',
inputTokens: 1000,
outputTokens: 500,
},
},
})
expect(hbRes.status()).toBe(200)
const hbBody = await hbRes.json()
expect(hbBody.token_recorded).toBe(true)
expect(hbBody.agent).toBe(agentName)
const costsRes = await request.get('/api/tokens?action=agent-costs&timeframe=hour', {
headers: API_KEY_HEADER,
})
expect(costsRes.status()).toBe(200)
const costsBody = await costsRes.json()
expect(costsBody.agents).toHaveProperty(agentName)
expect(costsBody.agents[agentName].stats.totalTokens).toBeGreaterThanOrEqual(1500)
})
test('DELETE /api/connect disconnects and sets agent offline', async ({ request }) => {
const agentName = `e2e-cli-del-${Date.now()}`
const postRes = await request.post('/api/connect', {
headers: API_KEY_HEADER,
data: {
tool_name: 'claude-code',
agent_name: agentName,
},
})
const postBody = await postRes.json()
createdAgentIds.push(postBody.agent_id)
const delRes = await request.delete('/api/connect', {
headers: API_KEY_HEADER,
data: { connection_id: postBody.connection_id },
})
expect(delRes.status()).toBe(200)
const delBody = await delRes.json()
expect(delBody.status).toBe('disconnected')
// Agent should be offline
const agentRes = await request.get(`/api/agents/${postBody.agent_id}`, {
headers: API_KEY_HEADER,
})
const agentBody = await agentRes.json()
expect(agentBody.agent.status).toBe('offline')
})
test('POST /api/connect requires auth', async ({ request }) => {
const res = await request.post('/api/connect', {
data: {
tool_name: 'claude-code',
agent_name: 'unauthorized-agent',
},
})
expect(res.status()).toBe(401)
})
})
|