Fix: 로그인 완료 자동 감지, completion_check LLM 판단, 프롬프트 규칙 보완#88
Conversation
| return {"done": True} | ||
| if is_auth: | ||
| page_before = state.get("last_page_state") | ||
| page_after = await actor._browser.get_page_state() |
There was a problem hiding this comment.
graph 노드에서 actor._browser로 private 멤버에 직접 접근하고 있습니다. 헥사고날 아키텍처 규칙상 graph는 port 인터페이스만 사용해야 합니다. compile_graph에 browser: BrowserPort 파라미터를 추가하고 await browser.get_page_state()로 변경하는 것이 맞을 것 같습니다.
There was a problem hiding this comment.
"헥사고날 아키텍처 규칙상 graph는 port 인터페이스만 사용" 이 부분은 제가 헥사고날 아키텍처에 대한 이해도가 떨어져서 잘못 구현한 것 같습니다.
There was a problem hiding this comment.
claude가 실수할까봐 AGENTS.md에 넣어뒀는데, claude.md를 먼저읽어서 못읽었을 수도 있겠네요.
Lines 65 to 91 in 7e6597d
| if llm is not None and last_page_state is not None: | ||
| eval_result = await llm.evaluate( | ||
| SuccessCriteria(description=anchor), | ||
| last_page_state, |
There was a problem hiding this comment.
anchor 텍스트를 SuccessCriteria(description=...)에만 넣으면 구조적 체크(url_contains, text_visible)는 전부 skip되고 매번 LLM 호출이 발생합니다. completion마다 Gemini 호출 1회(4-6초)가 추가되는 점은 의도된 것인지 확인 부탁드립니다.
There was a problem hiding this comment.
초반에는 정확한 완료 확인을 위해 LLM 체크가 필요하다고 생각했는데..생각보다 호출이 빈번하고 planner가 같은 역할을 하고 있어 중복이었습니다. LLM 호출을 제거하고 유저 interrupt로만 처리하도록 수정하겠습니다.
| if not login_completed: | ||
| result2 = interrupt( | ||
| { | ||
| "type": "auth_verify_failed", |
There was a problem hiding this comment.
auth_verify_failed라는 새 interrupt 타입을 사용하고 있는데, Extension InterruptBlock.tsx에서 이 타입을 처리하는 UI가 없습니다. auto-approve에서의 동작도 정의되지 않았고요. Extension 쪽 대응 없이 머지되면 런타임에 fallback으로 빠질 수 있습니다.
| @echo "Starting surfy server..." | ||
| @curl -sf http://localhost:3000/api/public/health >/dev/null 2>&1 || echo "⚠️ Langfuse not running. Run 'make langfuse' first for tracing." | ||
| @doppler run -- uv run python main.py --serve --port 8765 & | ||
| @$(if $(shell command -v doppler 2>/dev/null),doppler run -- uv run python main.py --serve --port 8765,uv run --env-file .env python main.py --serve --port 8765) & |
There was a problem hiding this comment.
serve에서는 _RUN 변수를 사용하는데, restart에서는 인라인 분기로 직접 처리하고 있어 동일 로직이 두 가지 방식으로 존재합니다. restart도 _RUN 변수로 통일하면 유지보수가 편할 것 같습니다.
There was a problem hiding this comment.
restart에서 $(_RUN) 대신 $(if ...) 조건을 직접 인라인으로 썼고 fallback 명령도 serve와 다른 걸 발견해서 수정하겠습니다.
1. graph: actor._browser private 접근 제거 → compile_graph에 browser: BrowserPort 파라미터 추가 후 await browser.get_page_state() 사용 2. messages: InterruptMessageData에 auth_verify_failed 타입 추가, Extension InterruptBlock.tsx에서 해당 타입 처리 UI 추가 3. graph: completion_check에서 anchor 기반 LLM 평가 제거 (매 completion마다 불필요한 Gemini 호출 방지) 4. Makefile: restart에서 _RUN 변수 사용으로 통일
rover0811
left a comment
There was a problem hiding this comment.
리뷰 피드백 4건 반영 확인. 아래 2건 수정 후 merge.
| @@ -349,11 +351,30 @@ def human_gateway_node(state: AgentState) -> dict[str, object]: | |||
| ) | |||
There was a problem hiding this comment.
browser가 None이면 로그인 감지가 경고 없이 스킵됨. warning 로그 추가하거나 required로 변경.
if is_auth and browser is None:
logger.warning("browser port not provided — skipping login detection")| page_before = state.get("last_page_state") | ||
| page_after = await browser.get_page_state() | ||
|
|
||
| login_completed = ( |
There was a problem hiding this comment.
SPA 로그인(URL 안 바뀌고 DOM만 변경)에서 300자 header가 동일하면 false negative. 당장은 OK, 이슈 생기면 비교 범위 확장 필요.
| login_completed = ( | |
| or page_before.dom_text[:500] != page_after.dom_text[:500] |
Summary
human_gateway_node를 async로 변경하여 인증(Human-in-the-Loop) 이후 페이지 상태(URL, DOM)를 실제로 비교. 변화가 없으면 재확인 interrupt를 발생시켜 "완료했나요?" 수동 질문 제거completion_check_node를 async로 변경하여 anchor 달성 여부를 LLM으로 먼저 평가. 달성 안 됐으면 planner로 재라우팅하여 조기 완료 오탐 방지.env파일로 실행 가능하도록_RUN변수로 분기Test plan
make serve정상 동작 확인