본문으로 건너뛰기

에이전트 루프 내부

핵심 오케스트레이션 엔진은 run_agent.pyAIAgent 클래스입니다. 이 클래스는 프롬프트 어셈블리부터 도구 디스패치, 제공자 장애 조치까지 모든 것을 처리하는 대용량 파일(15k+ 라인)입니다.

핵심 책임

AIAgent은 다음을 담당합니다.

  • prompt_builder.py을 통해 효과적인 시스템 프롬프트 및 도구 스키마 조립
  • 올바른 제공자/API 모드 선택(chat_completions, codex_responses, anthropic_messages)
  • 취소 지원을 통해 중단 가능한 모델 호출하기
  • 도구 호출 실행(스레드 풀을 통해 순차적으로 또는 동시에)
  • OpenAI 메시지 형식으로 대화 기록 유지
  • 압축, 재시도 및 대체 모델 전환 처리
  • 상위 및 하위 에이전트 전체에서 반복 예산 추적
  • 컨텍스트가 손실되기 전에 영구 메모리 플러시

두 개의 진입점

# Simple interface — returns final response string
response = agent.chat("Fix the bug in main.py")

# Full interface — returns dict with messages, metadata, usage stats
result = agent.run_conversation(
user_message="Fix the bug in main.py",
system_message=None, # auto-built if omitted
conversation_history=None, # auto-loaded from session if omitted
task_id="task_abc123"
)
``chat()`은 결과 dict에서 `final_response` 필드를 추출하는 `run_conversation()` 주변의 얇은 래퍼입니다.

## API 모드 \{#api-modes}

Hermes는 공급자 선택, 명시적 인수 및 기본 URL 경험적 방법을 통해 해결되는 세 가지 API 실행 모드를 지원합니다.

| API 모드 | 용도 | 클라이언트 유형 |
|----------|----------|-------------|
| `chat_completions` | OpenAI 호환 엔드포인트(OpenRouter, 맞춤형, 대부분의 공급자) | `openai.OpenAI` |
| `codex_responses` | OpenAI 코덱스/응답 API | `openai.OpenAI`(응답 형식 포함) |
| `anthropic_messages` | 기본 Anthropic 메시지 API | `anthropic.Anthropic` 어댑터를 통해 |

모드는 메시지 형식, 도구 호출 구조, 응답 구문 분석 방식, 캐싱/스트리밍 작동 방식을 결정합니다. 세 가지 모두 API 호출 전후에 동일한 내부 메시지 형식(OpenAI 스타일 `role`/`content`/`tool_calls` dicts)으로 수렴됩니다.

**모드 해결 순서:**
1. 명시적 `api_mode` 생성자 인수(가장 높은 우선순위)
2. 제공자별 감지(: `anthropic` 제공자 → `anthropic_messages`)
3. 기본 URL 추론(: `api.anthropic.com` → `anthropic_messages`)
4. 기본값: `chat_completions`

## 수명주기 전환 \{#turn-lifecycle}

에이전트 루프의 각 반복은 다음 순서를 따릅니다.

```text
run_conversation()
1. Generate task_id if not provided
2. Append user message to conversation history
3. Build or reuse cached system prompt (prompt_builder.py)
4. Check if preflight compression is needed (>50% 컨텍스트)
5. Build API messages from conversation history
- chat_completions: OpenAI format as-is
- codex_responses: convert to Responses API input items
- anthropic_messages: convert via anthropic_adapter.py
6. Inject ephemeral prompt layers (budget warnings, 컨텍스트 pressure)
7. Apply prompt caching markers if on Anthropic
8. Make interruptible API call (_interruptible_api_call)
9. Parse response:
- If tool_calls: execute them, append results, loop back to step 5
- If text response: persist session, flush memory if needed, return

메시지 형식

모든 메시지는 내부적으로 OpenAI 호환 형식을 사용합니다.

{"role": "system", "content": "..."}
{"role": "user", "content": "..."}
{"role": "assistant", "content": "...", "tool_calls": [...]}
{"role": "tool", "tool_call_id": "...", "content": "..."}

확장된 사고를 지원하는 모델의 추론 콘텐츠는 assistant_msg["reasoning"]에 저장되며 선택적으로 reasoning_callback을 통해 표시됩니다.

메시지 대체 규칙

에이전트 루프는 엄격한 메시지 역할 교체를 시행합니다.

  • 시스템 메시지 뒤: User → Assistant → User → Assistant →...
  • 도구 호출 중: Assistant (with tool_calls) → Tool → Tool →... → Assistant
  • 절대로 보조 메시지 2개를 연속으로 사용하지 마세요.
  • 절대로 두 개의 사용자 메시지가 연속으로 표시되지 않음
  • tool 역할은 연속 항목을 가질 수 있습니다(병렬 도구 결과).

공급자는 이러한 시퀀스의 유효성을 검사하고 잘못된 기록을 거부합니다.

중단 가능한 API 호출

API 요청은 인터럽트 이벤트를 모니터링하는 동안 백그라운드 스레드에서 실제 HTTP 호출을 실행하는 _interruptible_api_call()에 래핑됩니다.

┌────────────────────────────────────────────────────┐
│ Main thread API thread │
│ │
│ wait on: HTTP POST │
│ - response ready ───▶ to provider │
│ - interrupt event │
│ - timeout │
└────────────────────────────────────────────────────┘

중단된 경우(사용자가 새 메시지, /stop 명령 또는 신호를 보냄):

  • API 스레드가 중단되었습니다(응답이 삭제되었습니다).
  • 에이전트는 새로운 입력을 처리하거나 완전히 종료할 수 있습니다.
  • 대화 기록에 부분 응답이 삽입되지 않습니다.

도구 실행

순차 대 동시

모델이 도구 호출을 반환하는 경우:

  • 단일 도구 호출 → 메인 스레드에서 직접 실행
  • 다중 도구 호출ThreadPoolExecutor을 통해 동시에 실행됨
    • 예외: 대화형으로 표시된 도구(예: clarify)는 순차적 실행을 강제합니다.
    • 완료 순서에 관계없이 원래 도구 호출 순서에 결과가 다시 삽입됩니다.

실행 흐름

for each tool_call in response.tool_calls:
1. Resolve handler from tools/registry.py
2. Fire pre_tool_call plugin hook
3. Check if dangerous command (tools/approval.py)
- If dangerous: invoke approval_callback, wait for user
4. Execute handler with args + task_id
5. Fire post_tool_call plugin hook
6. Append {"role": "tool", "content": result} to history

상담원 수준 도구

일부 도구는 handle_function_call()에 도달하기 전에 run_agent.py에 의해 차단됩니다.

도구가로채는 이유
todo에이전트-로컬 작업 상태 읽기/쓰기
memory문자 제한이 있는 영구 메모리 파일에 씁니다.
session_search상담원의 세션 DB를 통해 세션 내역을 조회합니다.
delegate_task격리된 컨텍스트로 하위 에이전트를 생성합니다.

이러한 도구는 에이전트 상태를 직접 수정하고 레지스트리를 거치지 않고 합성 도구 결과를 반환합니다.

콜백 표면

AIAgent은 CLI, 게이트웨이 및 ACP 통합에서 실시간 진행을 가능하게 하는 플랫폼별 콜백을 지원합니다.

콜백해고되었을 때사용처
tool_progress_callback각 도구 실행 전/후CLI 스피너, 게이트웨이 진행 메시지
thinking_callback모델이 생각을 시작하거나 멈출 때CLI "생각 중..." 표시기
reasoning_callback모델이 추론 콘텐츠를 반환하는 경우CLI 추론 디스플레이, 게이트웨이 추론 블록
clarify_callbackclarify 도구가 호출될 때CLI 입력 프롬프트, 게이트웨이 대화형 메시지
step_callback에이전트 차례가 완료될 때마다게이트웨이 단계 추적, ACP 진행
stream_delta_callback각 스트리밍 토큰(활성화된 경우)CLI 스트리밍 디스플레이
tool_gen_callback도구 호출이 스트림에서 구문 분석되는 경우스피너의 CLI 도구 미리보기
status_callback상태 변화(생각, 실행 등)ACP 상태 업데이트

예산 및 대체 동작

Iteration Budget

에이전트는 IterationBudget을 통해 반복을 추적합니다.

  • 기본값: 90회 반복(agent.max_turns을 통해 구성 가능)
  • 각 에이전트는 자체 예산을 갖습니다. 하위 에이전트는 delegation.max_iterations(기본값 50)으로 제한된 독립 예산을 얻습니다. — 상위 + 하위 에이전트 전체의 총 반복은 상위의 한도를 초과할 수 있습니다.
  • 100%에서는 에이전트가 중지되고 완료된 작업 요약을 반환합니다.

폴백 모델

기본 모델이 실패하는 경우(429 비율 제한, 5xx 서버 오류, 401/403 인증 오류):

  1. 구성에서 fallback_providers 목록을 확인하세요.
  2. 각 대체를 순서대로 시도해 보세요.
  3. 성공하면 새 공급자와 대화를 계속합니다.
  4. 401/403에서는 장애 조치 전에 자격 증명 새로 고침을 시도합니다.

폴백 시스템은 보조 작업도 독립적으로 처리합니다. 비전, 압축, 웹 추출 및 세션 검색에는 각각 auxiliary.* 구성 섹션을 통해 구성할 수 있는 자체 폴백 체인이 있습니다.

압축 및 지속성

압축이 트리거되는 경우

  • 프리플라이트(API 호출 전): 대화가 모델 컨텍스트 창의 50%를 초과하는 경우
  • 게이트웨이 자동 압축: 대화가 85%를 초과하는 경우(더 공격적, 턴 간 실행)

압축 중에 어떤 일이 발생합니까?

  1. 메모리가 먼저 디스크로 플러시됩니다(데이터 손실 방지).
  2. 중간 대화 차례는 간결한 요약으로 요약됩니다.
  3. 마지막 N개의 메시지는 그대로 유지됩니다(compression.protect_last_n, 기본값: 20).
  4. 도구 호출/결과 메시지 쌍은 함께 유지됩니다(분할되지 않음).
  5. 새 세션 계보 ID가 생성됩니다(압축하면 "하위" 세션이 생성됨)

세션 지속성

매 턴 이후:

  • 메시지는 세션 저장소에 저장됩니다(hermes_state.py을 통한 SQLite).
  • 메모리 변경 사항은 MEMORY.md / USER.md로 플러시됩니다.
  • 세션은 나중에 /resume 또는 hermes chat --resume을 통해 재개될 수 있습니다.

주요 소스 파일

파일목적
run_agent.pyAIAgent 클래스 — 완전한 에이전트 루프
agent/prompt_builder.py메모리, 기술, 컨텍스트 파일, 성격을 바탕으로 시스템 프롬프트 조립
agent/context_engine.pyContextEngine ABC — 플러그형 컨텍스트 관리
agent/context_compressor.py기본 엔진 — 손실 요약 알고리즘
agent/prompt_caching.py인류 프롬프트 캐싱 마커 및 캐시 측정항목
agent/auxiliary_client.py부가 작업(비전, 요약)을 위한 보조 LLM 클라이언트
model_tools.py도구 스키마 수집, handle_function_call() 디스패치