Files
AriWeb-Suite/docs/HAL-AI.md

7.5 KiB

HAL AI 채팅룸 — 연결·방·도구·MCP (Ariweb Suite 0.3.0)

운영자 콘솔(/ops/*) 오른쪽의 AI 채팅룸과 그 백엔드(hal/ai/*) 설명. 개발 지시 Ariweb-Suitle_Dev-Order_v0.3.0.md(Oz) · v0.1.4 §41·§42. 비밀값은 이 문서에 없다.

1. 구성

파일 역할
hal/ai/connections.mjs 모델 연결(API 키·OAuth PKCE·로컬 CLI 로그인 세션), 비밀값은 Vault(ai:conn:<id>:api_key / :oauth / :client_secret), 모델 목록 확인, 상태
hal/ai/providers.mjs 공급자 어댑터: Anthropic Messages, OpenAI 호환 Chat Completions(도구 호출 포함), 로컬 CLI(claude -p --output-format json, 도구 없음)
hal/ai/rooms.mjs 방(통합 room_group 고정 + 연결별 개별)·메시지(블록 JSON, seq)·통합 방 호출 규칙(parseAddressing, mentionedParticipants)
hal/ai/engine.mjs 턴 실행: system prompt(고유 정보·참여자·스킬 문서) → 모델 호출 → 읽기 도구 즉시 실행 / 쓰기·고위험은 제안 → 통합 방 @전달 1회 → 승인 실행·거부
hal/ai/tools.mjs 도구 레지스트리(이름·설명·위험 등급·인자 선언·실행), 공급자별 선언 변환(toolDefs), 인자 검증
hal/ai/skill.md 스킬 문서: HAL 상태·작업·릴리스·사건·감사·긴급 복구·DR·오류 코드의 뜻과 AI 규칙(system prompt 와 hal_skill·GET /ops/api/ai/skill)
hal/ai/mcp.mjs MCP(stdio JSON-RPC) 서버 — node hal/index.mjs mcp, 같은 도구 정의, 읽기 도구만 실행
hal/ai/routes.mjs 운영자 API /ops/api/ai/*, OAuth 콜백 /ops/ai/oauth/callback
hal/ui.mjs · hal/ui/public/ai.js · ai-render.mjs · ops.css 패널(#ai-panel)·AI 연동 화면(/ops/ai)·순수 렌더러·스타일
표 ai_connections · ai_rooms · ai_messages · ai_actions · ai_oauth_states(마이그레이션 hal_0006_ai_chat)

2. 연결(AI 연동 화면 /ops/ai)

  • 공급자: anthropic(API 키 또는 OAuth Bearer) · openai(OpenAI 호환, baseUrl 로 다른 호환 공급자) · local-cli(서버에 설치·로그인된 Claude Code 세션, 대화·분석 전용).
  • 고유 정보 identity: role(역할·업무) · traits(특성) · instructions(추가 지시). 통합 방에서 다른 참여자에게도 이름·역할이 안내된다.
  • 상태: active · disabled(탭은 보이되 응답하지 않음) · reauth_required(OAuth 토큰 없음·만료·401) · error(마지막 확인 실패 — lastError).
  • "확인"(POST /ops/api/ai/connections/:id/test): 실제 공급자 GET /models(CLI 는 --version)로 사용 가능 모델을 받아 둔다. 목록에 없는 모델로 바꾸면 model_unavailable.
  • 인증 키 변경은 고위험: 키 등록(POST /connections with apiKey)·교체(POST /:id/secret)·OAuth client secret·연결 삭제는 최근 10분 재인증(reauth_required)이 필요하다.
  • OAuth: POST /:id/oauth/start → authorizeUrl(state·PKCE S256) → 공급자 로그인 → GET /ops/ai/oauth/callback?code&state → 토큰 교환(code_verifier, client secret 은 서버→토큰 끝점에만) → Vault 저장 → /ops/ai?oauth=ok. state 는 해시 저장·10분·1회용, 시작한 운영자와 같은 세션만 허용. 만료 토큰은 refresh_token 으로 서버가 갱신하고 실패하면 reauth_required.
  • 공개 객체의 secret 은 { hasKey, hint } / { hasToken, expiresAt, hasRefresh } / { cli: true } 뿐이다.

3. 방과 규칙

  • GET /ops/api/ai/rooms: [통합(fixed), 개별…] — 통합이 항상 먼저. 개별 방 title 은 비우면 연결 이름(PATCH /rooms/:id {title} 로 수정, 통합은 room_fixed).
  • POST /rooms/:id/messages {text, context?}:
    • 개별 방 → 그 모델만(연결이 active 가 아니면 409 connection_inactive).
    • 통합 방 → 활성 모델 모두. @이름(어디든) 또는 글머리 이름:/이름, → 그 모델만. 모르는 @이름 → 400 unknown_addressee(참여자 목록 포함).
    • 응답은 비동기 턴. GET /rooms/:id/messages?after=<seq> 가 새 메시지·pending(응답 중 턴 수)·actions(제안)를 준다.
  • 모델→모델 전달: 모델 답에 @다른이름 이 있으면 그 모델이 자동 1회 답한다(relayDepth 1, 화면에 "전달 응답"). depth 1 의 답이 또 부르면 HAL 안내만 남기고 멈춘다 — 다음 반응은 운영자 지시로. 자기 자신·비활성 모델은 전달 대상이 아니다.
  • 메시지 역할: user(운영자) · assistant(모델, connectionId·usage) · tool(도구 결과 블록) · system(HAL 안내). 공급자 오류는 status: failed + error(코드·메시지) 로 남는다.

4. 도구와 위험 등급

등급 실행 도구
읽기(read) 모델이 부르면 즉시 hal_skill hal_health hal_overview hal_servers_list hal_server_get hal_server_metrics hal_releases_list hal_jobs_list hal_job_get hal_incidents_list hal_audit_list hal_mail_services_list hal_emergency_list hal_dr_status hal_changelog
쓰기(write) 제안 → 운영자 승인(재인증) hal_server_create hal_server_approve hal_server_maintenance hal_incident_open hal_incident_resolve hal_job_control hal_module_health hal_dr_snapshot
고위험(high) 제안 → 승인(재인증 + 3단계 확인, 식별정보 = 도구가 정한 identifiers) hal_server_isolate hal_server_delete hal_module_deploy hal_module_rollback hal_module_reconcile hal_release_approve hal_job_revert hal_config_set
  • 인자는 validateArgs(모르는 키·필수·형식·enum·길이)로 다시 검사한다. 모르는 도구·인자 오류는 실행하지 않고 모델에게 오류 결과로 돌려준다. 임의 셸 명령·경로·네트워크 도구는 없다.
  • 제안(ai_actions): proposed → executing → executed | failed, 또는 rejected / cancelled. POST /ops/api/ai/actions/:id/approve(write: requireRecent, high: requireRecent + threeStep(confirmImpact, confirmIdentifiers, confirmExecute)), POST …/reject {reason}. 승인은 한 번만 실행된다(상태를 먼저 executing 으로 바꿔 동시 클릭을 막음). 실행 결과는 도구 결과로 대화에 들어가고 모델이 이어서 답한다. 거부는 모델을 자동으로 부르지 않는다.
  • 감사: ai.connection.*, ai.action.propose/execute/reject, ai.turn.failed. detail 은 redact 를 거친다(비밀값 없음).

5. MCP 서버

ARIWEB_HAL_DATA=/srv/ariweb/hal/data node hal/index.mjs mcp     # stdio JSON-RPC: initialize · tools/list · tools/call · ping

HAL 서비스와 같은 SQLite 를 WAL 로 함께 읽는다. 읽기 도구만 실행하고, 쓰기·고위험 도구는 isError 결과로 "운영자 콘솔 AI 채팅룸에서 승인을 받으라"고 안내한다(MCP 경로에는 운영자 세션·재인증·3단계 확인이 없기 때문). 로그는 stderr.

6. 운영 메모

  • 턴은 HAL 프로세스 안에서 돈다. HAL 재시작 뒤 진행 중이던 턴은 사라지며 "응답 중" 표시도 사라진다(거짓 진행 표시 없음). 운영자가 다시 지시하면 된다.
  • 비용·토큰: 공급자가 준 입력·출력 토큰만 메시지 usage 에 기록한다. 주지 않으면 "제공되지 않음".
  • 로컬 CLI 연결은 bear(hal21.ariweb.net) 유닛의 ProtectSystem=strict·CLI 미설치 때문에 현재 운영 서버에서는 "사용 불가(cli_unavailable)" 로 표시된다 — 설치·로그인 뒤 "확인"을 누르면 활성화된다.