Nova Agent
Last analyzed: 2026-07-05
qanova-agent는 사용자의 로컬 환경에서 실행되는 Testvera 브라우저 자동화 Agent CLI다. 사용자는 Agent를 등록해 토큰을 저장하고, nova-agent start로 Gateway에 연결한다. Runner는 Gateway를 통해 Agent에 DOM 추출, script 실행, browser primitive command를 보내고 Agent는 로컬 Playwright 브라우저에서 이를 수행한다.
기술 스택
| 영역 | 사용 기술 |
|---|---|
| Runtime | Python 3.11+ |
| CLI | Typer, Rich |
| Browser | Playwright |
| WebSocket | websockets |
| Models/settings | Pydantic, pydantic-settings, python-dotenv |
| Serialization | orjson |
| Logging | structlog |
| HTTP/pairing/update check | urllib, pip/pipx |
| Test | pytest, pytest-asyncio |
실행 책임
Agent는 로컬 브라우저 실행과 Gateway 메시지 응답만 담당한다. AI 호출과 DB 업데이트는 Runner가 담당한다.
- 사용자 브라우저에서 Agent 등록 페이지 열기
- 웹 pairing 승인 후 1회 발급된 token을
~/.nova-agent/token에 저장 - Gateway
/ws/agent에Authorization: Bearer ...헤더로 연결 - Gateway registration 이후 system info 전송
- heartbeat 주기 전송
- job assignment 수락 또는 pool full 거절
- job별 browser session 생성/정리
- entry URL navigation
- DOM 추출과 screenshot 전송
- Runner가 보낸 Playwright script 실행
- Runner 공통 엔진이 보내는 browser primitive command 실행
- step/job 완료, 실패, 취소 message 전송
- reconnect 시 active job reset 알림
CLI 명령
| 명령 | 설명 |
|---|---|
nova-agent --version |
현재 Agent 버전 출력 |
nova-agent login |
pairing code로 FE Agent 등록 화면을 열고 승인된 token을 자동 저장 |
nova-agent start |
Gateway에 연결하고 job 대기 |
nova-agent doctor |
token, Gateway URL, 선택적 Playwright browser 준비 상태 진단 |
nova-agent test-connection |
Gateway 인증과 Agent 등록 handshake를 1회 테스트 |
nova-agent logs |
최근 Agent 로그 출력 |
nova-agent status |
token 저장 여부와 경로 표시 |
nova-agent version-check |
설치된 Agent와 PyPI 최신 버전 비교 |
nova-agent logout |
저장된 token 삭제 |
nova-agent update |
pip 또는 pipx로 최신 qanova-agent 패키지 설치 |
nova-agent install-deps |
Linux에서 Playwright system dependency 설치 |
start 옵션:
| 옵션 | 설명 |
|---|---|
--headless/--no-headless |
브라우저 headless 여부 |
--gateway-url, -g |
Gateway WebSocket URL override |
--pool-size, -p |
동시 browser 수, 1-10 |
--verbose, -v |
DEBUG logging |
login 옵션:
| 옵션 | 설명 |
|---|---|
--url, -u |
Frontend URL override |
--api-url |
pairing session을 만들 API base URL override |
--pairing-timeout |
브라우저 승인 대기 시간, 기본 600초 |
--manual |
구버전 서버용 수동 token 복사/붙여넣기 fallback |
doctor 옵션:
| 옵션 | 설명 |
|---|---|
--gateway-url, -g |
검증할 Gateway WebSocket URL override |
--check-browser |
Playwright Chromium 설치/실행 준비 상태 확인 |
test-connection 옵션:
| 옵션 | 설명 |
|---|---|
--gateway-url, -g |
테스트할 Gateway WebSocket URL override |
logs 옵션:
| 옵션 | 설명 |
|---|---|
--lines, -n |
출력할 최근 로그 라인 수, 기본 80 |
--path |
로그 파일 경로만 출력 |
설정과 token 저장
기본 설정은 src/nova_agent/settings.py에 있다. 환경 변수 prefix는 NOVA_다. NOVA_ENV=dev이면 프로젝트 .env, 기본 prod이면 .env.prod를 읽는다.
| 설정 | 기본값/설명 |
|---|---|
NOVA_GATEWAY_URL |
기본 wss://agent-gw.qanova.kr/ws/agent |
NOVA_API_URL |
기본 https://api.qanova.kr/api/v1 |
NOVA_FRONTEND_URL |
기본 https://qanova.kr |
NOVA_AGENT_REGISTER_PATH |
기본 /agent/register |
NOVA_HEADLESS |
기본 true |
NOVA_VIEWPORT_WIDTH, NOVA_VIEWPORT_HEIGHT |
기본 1920x1080 |
NOVA_POOL_SIZE |
기본 1 |
NOVA_HEARTBEAT_INTERVAL |
기본 30초 |
NOVA_CONNECTION_TIMEOUT |
기본 10초 |
NOVA_RECONNECT_DELAY |
기본 5초 |
NOVA_MAX_RECONNECT_ATTEMPTS |
기본 0, 무제한 |
NOVA_JOB_TIMEOUT |
job idle timeout, 기본 300초 |
NOVA_SCRIPT_TIMEOUT |
script timeout, 기본 30초 |
NOVA_ACTION_TIMEOUT |
단일 action timeout, 기본 10초 |
NOVA_MAX_SCREENSHOT_BYTES |
WebSocket으로 전송할 screenshot 원본 byte 상한, 기본 8MB, 0이면 제한 없음 |
NOVA_MAX_DOM_ELEMENTS |
WebSocket으로 전송할 interactive DOM element 상한, 기본 1000 |
NOVA_MAX_DOM_TEXT_CHARS |
DOM element별 text/value 최대 문자 수, 기본 200 |
NOVA_MAX_DOM_HTML_CHARS |
fallback raw HTML 최대 문자 수, 기본 30000, 0이면 raw HTML 생략 |
NOVA_LOCAL_AGENT_ALLOW_EXECUTE_SCRIPT |
Agent 기본 execute_script 허용 여부, 기본 true |
NOVA_LOCAL_AGENT_ALLOW_BROWSER_EVALUATE, NOVA_LOCAL_AGENT_ALLOW_BROWSER_CONTENT |
Agent 기본 browser evaluate/content 허용 여부, 기본 true |
NOVA_LOCAL_AGENT_ALLOW_STORAGE_STATE, NOVA_LOCAL_AGENT_ALLOW_ADD_COOKIES |
Agent 기본 storage/cookie primitive 허용 여부, 기본 true |
NOVA_LOCAL_AGENT_ALLOW_CDP |
Agent 기본 CDP primitive 허용 여부, 기본 false |
NOVA_LOCAL_AGENT_RESTRICT_NAVIGATION |
Agent 기본 navigation origin 제한 여부, 기본 false |
token은 ~/.nova-agent/token에 저장되고 권한은 0600으로 설정된다. ~/.nova-agent 디렉터리는 0700으로 수선되며, config directory 또는 token 파일이 symlink이면 읽기/쓰기를 거부한다. token path가 일반 파일이 아니어도 거부한다. token은 Gateway의 Agent JWT 검증에 사용된다.
Agent 로그는 ~/.nova-agent/agent.log에 rotating file로 저장된다. 기본 보관 정책은 파일당 5MB, backup 3개다. nova-agent logs로 최근 로그를 확인할 수 있다.
Local Agent가 execute_script 또는 위험 browser primitive(evaluate, content, storage_state, add_cookies, cdp_send, cdp_detach)를 허용/차단할 때 job/step/command id와 policy key를 structured log로 남긴다. script 본문, cookie 값, storage state 같은 민감 payload는 로그에 남기지 않는다. Runner가 job_assign.config.security_policy를 보내면 그 값이 우선하며, 누락된 policy key는 위 NOVA_LOCAL_AGENT_* 기본값을 따른다.
Local Agent가 dom_extracted, script_result, primitive browser screenshot 결과에 screenshot을 첨부할 때 screenshot 원본 byte가 NOVA_MAX_SCREENSHOT_BYTES를 넘으면 base64 본문을 생략하고 omitted=true, reason=too_large, original_bytes, max_bytes metadata만 전송한다. Runner는 screenshot이 없는 결과도 처리할 수 있어 대형 payload로 인한 WebSocket 불안정을 줄인다.
DOM payload는 interactive element 중심이며 NOVA_MAX_DOM_ELEMENTS, NOVA_MAX_DOM_TEXT_CHARS, NOVA_MAX_DOM_HTML_CHARS로 크기를 제한한다. Agent는 dom.payload_limits에 적용된 제한과 element_limit_reached, html_truncated, html_chars metadata를 함께 전송한다.
시작 흐름
- 사용자가
nova-agent login을 실행한다. - CLI가 API
POST /agent-pairings로 10분짜리 pairing session을 만들고 pairing code를 표시한다. - CLI가
FRONTEND_URL + /agent/register?pairingId=...&code=...를 브라우저로 연다. - 사용자가 웹앱에서 프로젝트와 Agent 이름을 선택하고 pairing code를 승인한다.
- CLI가 API
GET /agent-pairings/{pairingId}?code=...를 poll하다가 완료 응답의 token을 1회 수신한다. - CLI가 token을
~/.nova-agent/token에 저장한다. token은 브라우저에 표시되지 않는다. - pairing API가 없거나 브라우저 handoff 전에 생성 응답이 유효하지 않으면
nova-agent login은 수동 token 입력 방식으로 fallback한다. 명시적으로 수동 방식을 쓰려면nova-agent login --manual을 사용한다. API가429 Too Many Requests를 반환하면Retry-After안내를 표시하고 종료한다. 이 경우 수동 token 입력으로 자동 fallback하지 않는다. 승인 완료 응답에 token이 없으면 token을 저장하지 않고 명확한 오류로 종료한다. - 사용자가
nova-agent start를 실행한다. - CLI가 업데이트를 확인하고 Playwright Chromium 설치를 보장한다.
BrowserPool과JobManager를 생성한다.AgentWebSocketClient가 Agent token을 Authorization 헤더로 보내 Gateway에 연결한다.- Gateway의
registered메시지를 받으면 OS/arch/version/python/browser 정보를register메시지로 보낸다. - heartbeat와 message loop가 시작되고 job을 기다린다.
WebSocket protocol
Agent가 Gateway로 보내는 주요 메시지:
registerheartbeatjob_acceptedjob_assign_failedstep_starteddom_extractedscript_resultbrowser_command_resultstep_completedgoal_achievedjob_completederror
Gateway/Runner에서 Agent로 들어오는 주요 메시지:
registeredregister_ackheartbeat_ackjob_assignextract_domexecute_scriptbrowser_commandnext_stepjob_cancelgoal_achieved
goal_achieved는 Agent 내부에서 check_goal 결과처럼 처리되어 step 완료로 이어진다.
내부 구조
| 경로 | 설명 |
|---|---|
src/nova_agent/cli.py |
Typer CLI, login/start/status/logout/update/install-deps |
src/nova_agent/settings.py |
env 기반 runtime settings |
src/nova_agent/config.py |
token/config directory 관리 |
src/nova_agent/constants.py |
protocol constant, timeout constant |
src/nova_agent/websocket/client.py |
Gateway 연결, reconnect, heartbeat/message loop |
src/nova_agent/websocket/handlers.py |
message type별 handler |
src/nova_agent/websocket/heartbeat.py |
heartbeat loop |
src/nova_agent/executor/job_manager.py |
job session lifecycle, message execution, response 전송 |
src/nova_agent/executor/job_session.py |
job별 browser/session state |
src/nova_agent/executor/script_runner.py |
Runner가 보낸 script 실행 |
src/nova_agent/browser/pool.py |
동시 browser pool |
src/nova_agent/browser/manager.py |
Playwright browser/context/page, cookie/localStorage/header/test access key 설정 |
src/nova_agent/browser/dom_extractor.py |
Cloud Runner DomParserService와 맞춘 DOM extraction |
src/nova_agent/models |
job/message/dom model |
src/nova_agent/utils |
system info, domain matcher, logging |
Job lifecycle
job_assign수신- Browser pool slot 확인
- slot 없으면
job_assign_failedwithPOOL_FULL - slot 있으면 browser manager acquire
- scenario, steps, config, environment variables로
JobSession생성 job_accepted전송- entry URL로 navigation
- shared engine managed job이면 Runner가
extract_dom/browser_command로 주도 - legacy flow면 Agent가 첫 step 시작
- script/command 실행 중 새 tab/popup과 page close를 감지해 active page 복구
- terminal 또는 cancel 시 session cleanup과 browser release
BrowserManager 기능
BrowserManager는 Playwright Chromium/Firefox/WebKit 중 config browser type을 사용하고, 지원하지 않는 값은 Chromium으로 fallback한다.
지원 기능:
- viewport 설정
- headless, slow_mo, JS heap size, dev shm option
- storage_state, cookie, localStorage 적용
- extra HTTP headers
- test access key header를 route interception으로 주입
- permission grant
- network throttling
- popup/new page active page 전환
- dialog/download/network/console event capture
- DOM extraction용 page access
- browser primitive command 실행
Runner와 Cloud 모드의 동작 차이를 줄이기 위해 DOM extractor는 Cloud Runner의 selector/attribute/metadata extraction 정책을 따라간다.
로컬 개발
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
python -m playwright install chromium
nova-agent --version
dev Gateway를 사용할 때:
NOVA_ENV=dev nova-agent start --gateway-url ws://localhost:9100/ws/agent --no-headless --verbose
prod 기본 URL은 secure WebSocket이므로 local Gateway에는 반드시 override가 필요하다.
테스트
pytest
현재 테스트는 browser, CLI, WebSocket 동작을 중심으로 구성되어 있다. message protocol이나 job manager를 바꾸면 Gateway/Runner 쪽 테스트와 함께 검증한다.
변경 시 같이 봐야 하는 프로젝트
| Agent 변경 | 같이 확인 |
|---|---|
| message payload/type 변경 | qanova-agent-gateway/gateway/models/message.py, qanova-runner/gateway_client |
| token/JWT 처리 변경 | qanova-api AgentController/token 발급, Gateway jwt validator |
| browser config 변경 | Runner AgentJobCoordinator._build_agent_browser_config |
| DOM extraction 변경 | Runner services/dom 및 learning prompt/parser |
| pool/full/cancel 정책 변경 | Gateway runner handler, Runner AgentJobCoordinator |
운영/사용자 지원 메모
사용자가 인증 오류를 겪으면 token 만료/삭제/agent DB 비활성화/project mismatch를 먼저 확인한다. CLI는 401/403을 받으면 재연결하지 않고 종료하도록 되어 있다.
브라우저 설치 실패는 Playwright browser 또는 Linux system dependency 문제일 가능성이 높다. nova-agent install-deps와 python -m playwright install chromium을 확인한다.
Local Agent는 사용자의 로컬 네트워크와 브라우저 상태에 영향을 받는다. Cloud Runner에서 성공하는 시나리오가 Local Agent에서 실패하면 viewport, cookie/storage_state, test access key header, popup/tab 전환, 브라우저 권한을 우선 비교한다.
Metadata
Release files for qanova-agent 0.3.10
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| qanova_agent-0.3.10.tar.gz | 81.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qanova_agent-0.3.10-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 157.6 kB
Release files / qanova_agent-0.3.10.tar.gz
| Download URL | qanova_agent-0.3.10.tar.gz |
|---|---|
| Size | 81.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
74205af55b6b38409485d3b39a58b0ec06fa195d3106edf3ed1f206ed2da6b51
|
|
BLAKE2b-256 checksum How to use checksums |
6e3961b4003802043755affbcbe38c339c55f3fb3329e493bd8d5e8a98dffc74
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / qanova_agent-0.3.10-py3-none-any.whl
| Download URL | qanova_agent-0.3.10-py3-none-any.whl |
|---|---|
| Size | 75.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e07eeaeff7d47eaaf210c4c2c5ab5fe1de731d4abef0b9c35067111fd8323c50
|
|
BLAKE2b-256 checksum How to use checksums |
5bb96d7cabb781dd6537341d48e62e74b8d139a8ab7a9e06553a669f716327cc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|