컨텍스트 허브 커밋 웹훅 구성하기

컨텍스트 허브 커밋 웹훅 구성하기

컨텍스트 허브 커밋 이벤트를 외부 HTTPS 엔드포인트로 보내고, LangSmith가 각 요청에 서명했는지 검증해요.

컨텍스트 허브 커밋 웹훅은 워크스페이스에서 에이전트 또는 스킬 커밋이 생성될 때마다 외부 서비스에 알려줘요. LangSmith Fleet을 통해 생성된 커밋을 포함해 컨텍스트 허브 변경으로부터 자동화를 트리거하는 데 사용하세요.

컨텍스트 허브 웹훅을 관리하려면 prompts:update 권한이 필요하며, 워크스페이스 관리자워크스페이스 편집자는 기본적으로 이 권한을 가져요.

출처: 문서

본문

웹훅 추가하기

각 웹훅은 워크스페이스 전체에 적용돼요. 구성된 모든 엔드포인트는 Fleet으로 생성된 커밋을 포함해 모든 에이전트 및 스킬 커밋을 수신해요. context_hub.commit.created.v1 이벤트는 저장소 또는 이벤트 유형별 필터링을 지원하지 않아요.

웹훅을 추가하려면:

  1. LangSmith UI에서 Settings > Integrations > Context Hub webhooks로 이동하세요.
  2. Add webhook을 클릭하세요.
  3. 공개적으로 접근 가능한 HTTPS URL을 입력하세요.
  4. (선택) Authorization 헤더 같은 커스텀 요청 헤더를 추가하세요.
  5. Add webhook을 클릭하세요.
  6. 생성된 서명 시크릿을 복사해서 안전하게 보관하세요.

추가할 수 있는 구독 수는 워크스페이스 구성에 따라 달라져요.

웹훅 관리하기

웹훅 목록은 엔드포인트 URL과 커스텀 헤더 이름을 표시해요. 헤더 값과 서명 시크릿은 Reveal secrets를 클릭할 때까지 숨겨져 있어요. 컨텍스트 허브 웹훅을 관리할 권한이 있다면 나중에 공개할 수 있어요.

웹훅의 컨트롤을 사용해서 관리하세요:

  • Edit webhook: HTTPS URL을 변경하거나 커스텀 헤더를 교체해요. 편집해도 서명 시크릿은 바뀌지 않아요.
  • Roll signing secret: 새 서명 시크릿을 생성하고 공개해요. LangSmith는 이후 전달부터 새 시크릿을 즉시 사용하며, 이전 시크릿은 작동을 멈춰요. 웹훅을 검증하는 모든 소비자를 업데이트하세요.
  • Delete webhook: 엔드포인트가 워크스페이스로부터 향후 컨텍스트 허브 커밋 이벤트를 받지 못하게 해요.

전달

LangSmith는 각 이벤트에 대해 JSON POST 요청을 보내요. 커스텀 헤더는 LangSmith가 커스텀 헤더를 적용한 후 설정하는 Content-Type 또는 X-LangSmith-Signature를 재정의할 수 없어요.

속성
메서드 POST
URL 공개적으로 접근 가능한 HTTPS 엔드포인트
콘텐츠 유형 application/json
서명 웹훅의 서명 시크릿으로 서명된 X-LangSmith-Signature 헤더
타임아웃 시도당 20초
시도 최대 4회: 최초 1회 + 재시도 최대 3회
재시도 조건 전송 실패, HTTP 408, 425, 429, 5xx 응답
영구 응답 기타 4xx 응답은 재시도되지 않음
응답 처리 400 미만의 상태는 성공. 응답 본문은 성공에 영향을 주지 않음.

재시도에는 바이트 동일 요청 본문이 포함되며 이벤트 id를 유지해요. 다운스트림 효과를 만들기 전에 id로 이벤트를 중복 제거하세요.

서명 검증하기

각 요청에는 다음 형식의 X-LangSmith-Signature 헤더가 포함돼요:

sha256=<lowercase hex HMAC-SHA256 digest>

웹훅의 서명 시크릿으로 정확한 원시 요청 본문 바이트에 대해 HMAC-SHA256 다이제스트를 계산하세요. JSON을 파싱하기 전에 서명을 검증하고, 전체 헤더 값을 상수 시간으로 비교하세요. 검증 전에 본문을 파싱하고 재직렬화하면 바이트가 변경되어 서명이 무효화될 수 있어요.

import hashlib
import hmac
from typing import Optional


def verify_langsmith_signature(
    *,
    body: bytes,
    signing_secret: str,
    signature_header: Optional[str],
) -> bool:
    if not signature_header or not signature_header.startswith("sha256="):
        return False

    expected = "sha256=" + hmac.new(
        signing_secret.encode("utf-8"),
        body,
        hashlib.sha256,
    ).hexdigest()

    return hmac.compare_digest(expected, signature_header)
import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyLangSmithSignature({
  body,
  signingSecret,
  signatureHeader,
}: {
  body: Buffer;
  signingSecret: string;
  signatureHeader: string | undefined;
}) {
  if (!signatureHeader?.startsWith("sha256=")) {
    return false;
  }

  const expected = `sha256=${createHmac("sha256", signingSecret)
    .update(body)
    .digest("hex")}`;

  const expectedBytes = Buffer.from(expected);
  const actualBytes = Buffer.from(signatureHeader);

  return (
    expectedBytes.length === actualBytes.length &&
    timingSafeEqual(expectedBytes, actualBytes)
  );
}

이벤트 봉투(envelope)

외부 id, type, created, data 봉투는 고정되어 있어요. 이벤트 유형의 .v1 접미사는 data.commit 스키마를 버전 관리해요.

{
  "id": "0198...",
  "type": "context_hub.commit.created.v1",
  "created": 1720000000,
  "data": {
    "commit": {
      "repo_id": "...",
      "repo_handle": "my-agent",
      "repo_type": "agent",
      "commit_hash": "newcommithash0002",
      "parent_commit_hash": "parentcommithash0001",
      "created_at": "2023-11-14T22:13:20Z",
      "created_by": "[email protected]",
      "url": "https://smith.example.com/context/my-agent/newcommithash0002",
      "files_changed": [
        { "path": "skills/kept", "action": "modified" },
        { "path": "skills/added", "action": "added" },
        { "path": "skills/gone", "action": "removed" }
      ]
    }
  }
}
필드 유형 설명
id UUID 재시도에도 안정적으로 유지되는 고유 이벤트 식별자. 이벤트 중복 제거에 사용.
type string 정확한 이벤트 유형. 현재 context_hub.commit.created.v1.
created integer 이벤트가 대기열에 들어간 UTC Unix 초.
data object 버전 관리된 이벤트 데이터. data.commit을 포함.

data.commit

data.commit 객체는 이벤트를 트리거한 컨텍스트 허브 커밋을 설명해요.

필드 유형 설명
repo_id UUID 컨텍스트 허브 저장소 ID.
repo_handle string 저장소 핸들.
repo_type string 저장소 유형: agent 또는 skill.
commit_hash string 새 커밋의 해시.
parent_commit_hash string 부모 커밋의 해시. 최초 커밋이거나 사용 불가 시 생략.
created_at string 커밋이 생성된 RFC 3339 타임스탬프.
created_by string 커밋을 만든 LangSmith 사용자 ID. 사용 불가 시 생략.
url string LangSmith UI의 커밋 딥 링크.
files_changed array 커밋에 포함된 파일 변경. 각 항목은 pathaction을 포함.

data.commit.files_changed

각 항목은 변경된 경로를 요약해요. 파일 콘텐츠는 포함하지 않아요.

필드 유형 설명
path string 커밋으로 변경된 경로.
action string 변경 유형: added, modified 또는 removed.

이벤트 버전 처리하기

data.commit을 파싱하기 전에 전체 이벤트 유형으로 분기하세요:

if (event.type === "context_hub.commit.created.v1") {
  await handleCommitCreatedV1(event.data.commit);
} else {
  // Ignore unknown event types and versions safely.
}

data.commit의 호환되지 않는 변경은 .v2 같은 새 이벤트 유형 접미사를 사용해요. 알 수 없는 유형을 v1으로 파싱하려고 시도하는 대신 무시하고, 호환 가능한 추가가 핸들러를 깨지 않도록 알 수 없는 필드를 허용하세요.

다음 단계

더 알아보기 (Learn more)